<?php

/**

 * @package php-font-lib

 * @link    http://php-font-lib.googlecode.com/

 * @author  Fabien Ménager <fabien.menager@gmail.com>

 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License

 * @version $Id: adobe_font_metrics.cls.php 35 2011-11-02 22:30:45Z fabien.menager $

 */



require_once dirname(__FILE__)."/encoding_map.cls.php";



/**

 * Adobe Font Metrics file creation utility class.

 * 

 * @package php-font-lib

 */

class Adobe_Font_Metrics {

  private $f;

  

  /**

   * @var Font_TrueType

   */

  private $font;

  

  function __construct(Font_TrueType $font) {

    $this->font = $font;

  }

  

  function write($file, $encoding = null){

    if ($encoding) {

      $encoding = preg_replace("/[^a-z0-9-_]/", "", $encoding);

      $map_file = dirname(__FILE__)."/../maps/$encoding.map";

      if (!file_exists($map_file)) {

        throw new Exception("Unkown encoding ($encoding)");

      }

      

      $map = new Encoding_Map($map_file);

      $map_data = $map->parse();

    }

    

    $this->f = fopen($file, "w+");

    

    $font = $this->font;

    

    $this->startSection("FontMetrics", 4.1);

    $this->addPair("Notice", "Converted by PHP-font-lib");

    $this->addPair("Comment", "http://php-font-lib.googlecode.com/");

    

    $encoding_scheme = ($encoding ? $encoding : "FontSpecific");

    $this->addPair("EncodingScheme", $encoding_scheme);

    

    $records = $font->getData("name", "records");

    foreach($records as $id => $record) {

      if (!isset(Font_TrueType::$nameIdCodes[$id]) || preg_match("/[\r\n]/", $record->string)) {

        continue;

      }

      

      $this->addPair(Font_TrueType::$nameIdCodes[$id], $record->string);

    }

    

    $os2 = $font->getData("OS/2");

    $this->addPair("Weight", ($os2["usWeightClass"] > 400 ? "Bold" : "Medium"));

    

    $post = $font->getData("post");

    $this->addPair("ItalicAngle",        $post["italicAngle"]);

    $this->addPair("IsFixedPitch",      ($post["isFixedPitch"] ? "true" : "false"));

    $this->addPair("UnderlineThickness", $font->normalizeFUnit($post["underlineThickness"]));

    $this->addPair("UnderlinePosition",  $font->normalizeFUnit($post["underlinePosition"]));

    

    $hhea = $font->getData("hhea");

    

    if (isset($os2["typoAscender"])) {

      $this->addPair("FontHeightOffset",  $font->normalizeFUnit($os2["typoLineGap"]));

      $this->addPair("Ascender",  $font->normalizeFUnit($os2["typoAscender"]));

      $this->addPair("Descender", $font->normalizeFUnit($os2["typoDescender"]));

    }

    else {

      $this->addPair("FontHeightOffset",  $font->normalizeFUnit($hhea["lineGap"]));

      $this->addPair("Ascender",  $font->normalizeFUnit($hhea["ascent"]));

      $this->addPair("Descender", $font->normalizeFUnit($hhea["descent"]));

    }

    

    $head = $font->getData("head");

    $this->addArray("FontBBox", array(

      $font->normalizeFUnit($head["xMin"]),

      $font->normalizeFUnit($head["yMin"]),

      $font->normalizeFUnit($head["xMax"]),

      $font->normalizeFUnit($head["yMax"]),

    ));

    

    $subtable = null;

    foreach($font->getData("cmap", "subtables") as $_subtable) {

      if ($_subtable["platformID"] == 0 || $_subtable["platformID"] == 3 && $_subtable["platformSpecificID"] == 1) {

        $subtable = $_subtable;

        break;

      }

    }

    

    if ($subtable) {

      $hmtx = $font->getData("hmtx");

      $names = $font->getData("post", "names");

      $glyphIndexArray = $subtable["glyphIndexArray"];

      

      $this->startSection("CharMetrics", count($hmtx));

        

      if ($encoding)  {

        foreach($map_data as $code => $value) {

          list($c, $name) = $value;

          

          if (!isset($glyphIndexArray[$c])) continue;

          

          $g = $glyphIndexArray[$c];

          

          if (!isset($hmtx[$g])) {

            $hmtx[$g] = $hmtx[0];

          }

          

          $this->addMetric(array(

            "C"  => ($code > 255 ? -1 : $code),

            "WX" => $font->normalizeFUnit($hmtx[$g][0]),

            "N"  => $name,

          ));

        }

      }

      else {

        foreach($glyphIndexArray as $c => $g) {

          if (!isset($hmtx[$g])) {

            $hmtx[$g] = $hmtx[0];

          }

          

          $this->addMetric(array(

            "U" => $c,

            "WX" => $font->normalizeFUnit($hmtx[$g][0]),

            "N" => (isset($names[$g]) ? $names[$g] : sprintf("uni%04x", $c)),

            "G" => $g,

          ));

        }

      }

        

      $this->endSection("CharMetrics");

    

      $kern = $font->getData("kern", "subtable");

      $tree = $kern["tree"];

      

      if (!$encoding && is_array($tree)) {

        $this->startSection("KernData");

          $this->startSection("KernPairs", count($tree, COUNT_RECURSIVE) - count($tree));

            

          foreach($tree as $left => $values) {

            if (!is_array($values)) continue;

            if (!isset($glyphIndexArray[$left])) continue;

            

            $left_gid = $glyphIndexArray[$left];

            

            if (!isset($names[$left_gid])) continue;

            

            $left_name = $names[$left_gid];

            

            $this->addLine("");

            

            foreach($values as $right => $value) {

              if (!isset($glyphIndexArray[$right])) continue;

              

              $right_gid = $glyphIndexArray[$right];

            

              if (!isset($names[$right_gid])) continue;

              

              $right_name = $names[$right_gid];

              $this->addPair("KPX", "$left_name $right_name $value");

            }

          }

            

          $this->endSection("KernPairs");

        $this->endSection("KernData");

      }

    }

      

    $this->endSection("FontMetrics");

  }

  

  function addLine($line) {

    fwrite($this->f, "$line\n");

  }

  

  function addPair($key, $value) {

    $this->addLine("$key $value");

  }

  

  function addArray($key, $array) {

    $this->addLine("$key ".implode(" ", $array));

  }

  

  function addMetric($data) {

    $array = array();

    foreach($data as $key => $value) {

      $array[] = "$key $value";

    }

    $this->addLine(implode(" ; ", $array));

  }



  function startSection($name, $value = "") {

    $this->addLine("Start$name $value");

  }

  

  function endSection($name) {

    $this->addLine("End$name");

  }

}

