Logo Search packages:      
Sourcecode: lcdf-typetools version File versions

t1mm.cc

// -*- related-file-name: "../include/efont/t1mm.hh" -*-

/* t1mm.{cc,hh} -- Type 1 multiple master font information
 *
 * Copyright (c) 1998-2004 Eddie Kohler
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version. This program 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 General
 * Public License for more details.
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <efont/t1mm.hh>
#include <efont/t1interp.hh>
#include <lcdf/error.hh>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
namespace Efont {

MultipleMasterSpace::MultipleMasterSpace(PermString fn, int na, int nm)
    : _ok(false), _font_name(fn), _naxes(na), _nmasters(nm),
      _axis_types(na, PermString()), _axis_labels(na, PermString()),
      _design_vector(0), _norm_design_vector(0), _weight_vector(0)
{
}


void
MultipleMasterSpace::set_master_positions(const Vector<NumVector> &mp)
{
    _master_positions = mp;
}

void
MultipleMasterSpace::set_normalize(const Vector<NumVector> &nin,
                      const Vector<NumVector> &nout)
{
    _normalize_in = nin;
    _normalize_out = nout;
}

void
MultipleMasterSpace::set_axis_type(int ax, PermString t)
{
    _axis_types[ax] = t;
}

void
MultipleMasterSpace::set_axis_label(int ax, PermString t)
{
    _axis_labels[ax] = t;
}

void
MultipleMasterSpace::set_design_vector(const NumVector &v)
{
    _default_design_vector = v;
}

void
MultipleMasterSpace::set_weight_vector(const NumVector &v)
{
    _default_weight_vector = v;
}


PermString
MultipleMasterSpace::axis_abbreviation(PermString atype)
{
    if (atype == "Weight")
      return "wt";
    else if (atype == "Width")
      return "wd";
    else if (atype == "OpticalSize")
      return "op";
    else if (atype == "Style")
      return "st";
    else
      return atype;
}


bool
MultipleMasterSpace::error(ErrorHandler *errh, const char *s, ...) const
{
    if (errh) {
      char buf[1024];
      va_list val;
      va_start(val, s);
      assert(strlen(s) < 800);
      sprintf(buf, (s[0] == ' ' ? "%.200s%s" : "%.200s: %s"),
            _font_name.c_str(), s);
      errh->verror(ErrorHandler::ERR_ERROR, String(), buf, val);
      va_end(val);
    }
    return false;
}


bool
MultipleMasterSpace::check(ErrorHandler *errh)
{
    if (_ok)
      return true;
  
    if (_nmasters <= 0 || _nmasters > 16)
      return error(errh, "number of masters must be between 1 and 16");
    if (_naxes <= 0 || _naxes > 4)
      return error(errh, "number of axes must be between 1 and 4");
  
    if (_master_positions.size() != _nmasters)
      return error(errh, "bad BlendDesignPositions");
    for (int i = 0; i < _nmasters; i++)
      if (_master_positions[i].size() != _naxes)
          return error(errh, "inconsistent BlendDesignPositions");
  
    if (_normalize_in.size() != _naxes || _normalize_out.size() != _naxes)
      return error(errh, "bad BlendDesignMap");
    for (int i = 0; i < _naxes; i++)
      if (_normalize_in[i].size() != _normalize_out[i].size())
          return error(errh, "bad BlendDesignMap");
  
    if (!_axis_types.size())
      _axis_types.assign(_naxes, PermString());
    if (_axis_types.size() != _naxes)
      return error(errh, "bad BlendAxisTypes");
  
    if (!_axis_labels.size())
      _axis_labels.assign(_naxes, PermString());
    if (_axis_labels.size() != _naxes)
      return error(errh, "bad axis labels");
  
    if (!_default_design_vector.size())
      _default_design_vector.assign(_naxes, UNKDOUBLE);
    if (_default_design_vector.size() != _naxes)
      return error(errh, "inconsistent design vector");
  
    if (!_default_weight_vector.size())
      _default_weight_vector.assign(_nmasters, UNKDOUBLE);
    if (_default_weight_vector.size() != _nmasters)
      return error(errh, "inconsistent weight vector");
  
    _ok = true;
    return true;
}

bool
MultipleMasterSpace::check_intermediate(ErrorHandler *errh)
{
    if (!_ok || _cdv)
      return true;
  
    for (int a = 0; a < _naxes; a++)
      for (int m = 0; m < _nmasters; m++)
          if (_master_positions[m][a] != 0 && _master_positions[m][a] != 1) {
            if (errh)
                errh->warning("%s requires intermediate master conversion programs",
                          _font_name.c_str());
            return false;
          }

    return true;
}


int
MultipleMasterSpace::axis(PermString ax) const
{
    for (int a = 0; a < _naxes; a++)
      if (_axis_types[a] == ax || _axis_labels[a] == ax)
          return a;
    return -1;
}

double
MultipleMasterSpace::axis_low(int ax) const
{
    return _normalize_in[ax][0];
}

double
MultipleMasterSpace::axis_high(int ax) const
{
    return _normalize_in[ax].back();
}


Vector<double>
MultipleMasterSpace::empty_design_vector() const
{
    return Vector<double>(_naxes, UNKDOUBLE);
}

bool
MultipleMasterSpace::set_design(NumVector &design_vector, int ax, double value,
                    ErrorHandler *errh) const
{
    if (ax < 0 || ax >= _naxes)
      return error(errh, " has only %d axes", _naxes);
  
    if (value < axis_low(ax)) {
      value = axis_low(ax);
      if (errh)
          errh->warning("raising %s's %s to %g", _font_name.c_str(),
                    _axis_types[ax].c_str(), value);
    }
    if (value > axis_high(ax)) {
      value = axis_high(ax);
      if (errh)
          errh->warning("lowering %s's %s to %g", _font_name.c_str(),
                    _axis_types[ax].c_str(), value);
    }
  
    design_vector[ax] = value;
    return true;
}

bool
MultipleMasterSpace::set_design(NumVector &design_vector, PermString ax_name,
                    double val, ErrorHandler *errh) const
{
    int ax = axis(ax_name);
    if (ax < 0)
      return error(errh, " has no `%s' axis", ax_name.c_str());
    else
      return set_design(design_vector, ax, val, errh);
}


bool
MultipleMasterSpace::normalize_vector(ErrorHandler *errh) const
{
    NumVector &design = *_design_vector;
    NumVector &norm_design = *_norm_design_vector;
  
    for (int a = 0; a < _naxes; a++)
      if (!KNOWN(design[a])) {
          if (errh)
            errh->error("must specify %s's %s coordinate", _font_name.c_str(), _axis_types[a].c_str());
          return false;
      }
  
    // Move to normalized design coordinates.
    norm_design.assign(_naxes, UNKDOUBLE);
  
    if (_ndv) {
      CharstringInterp ai;
      if (!ai.interpret(this, &_ndv))
          return error(errh, "%s in NDV program", ai.error_string().c_str());
    
    } else
      for (int a = 0; a < _naxes; a++) {
          double d = design[a];
          double nd = UNKDOUBLE;
          const Vector<double> &norm_in = _normalize_in[a];
          const Vector<double> &norm_out = _normalize_out[a];
      
          if (d < norm_in[0])
            nd = norm_out[0];
          for (int i = 1; i < norm_in.size(); i++)
            if (d >= norm_in[i-1] && d < norm_in[i]) {
                nd = norm_out[i-1]
                  + ((d - norm_in[i-1])
                     * (norm_out[i] - norm_out[i-1])
                     / (norm_in[i] - norm_in[i-1]));
                goto done;
            }
          if (d >= norm_in.back())
            nd = norm_out.back();
      
        done:
          norm_design[a] = nd;
      }
  
    for (int a = 0; a < _naxes; a++)
      if (!KNOWN(norm_design[a]))
          return error(errh, "bad normalization");
  
    return true;
}


bool
MultipleMasterSpace::convert_vector(ErrorHandler *errh) const
{
    NumVector &norm_design = *_norm_design_vector;
    NumVector &weight = *_weight_vector;
  
    weight.assign(_nmasters, 1);
  
    if (_cdv) {
      CharstringInterp ai;
      if (!ai.interpret(this, &_cdv))
          return error(errh, "%s in CDV program", ai.error_string().c_str());
    
    } else
      for (int a = 0; a < _naxes; a++)
          for (int m = 0; m < _nmasters; m++) {
            if (_master_positions[m][a] == 0)
                weight[m] *= 1 - norm_design[a];
            else if (_master_positions[m][a] == 1)
                weight[m] *= norm_design[a];
            else
                return error(errh, " requires intermediate master conversion programs");
          }
  
    return true;
}


bool
MultipleMasterSpace::design_to_norm_design(const NumVector &design_in,
                                 NumVector &norm_design,
                                 ErrorHandler *errh) const
{
    NumVector design(design_in);
    NumVector weight;
  
    _design_vector = &design;
    _norm_design_vector = &norm_design;
    _weight_vector = &weight;
    if (!normalize_vector(errh))
      return false;
    _design_vector = _norm_design_vector = _weight_vector = 0;
  
    return true;
}


bool
MultipleMasterSpace::design_to_weight(const NumVector &design_in, NumVector &weight, ErrorHandler *errh) const
{
    NumVector design(design_in);
    NumVector norm_design;
  
    bool dirty = false;
    for (int i = 0; i < _naxes; i++)
      if (design[i] != _default_design_vector[i])
          dirty = true;
  
    if (dirty) {
      _design_vector = &design;
      _norm_design_vector = &norm_design;
      _weight_vector = &weight;
      if (!normalize_vector(errh))
          return false;
      if (!convert_vector(errh))
          return false;
      _design_vector = _norm_design_vector = _weight_vector = 0;
    } else
      weight = _default_weight_vector;
  
    double sum = 0;
    for (int m = 0; m < _nmasters; m++)
      sum += weight[m];
    if (sum < 0.9999 || sum > 1.0001)
      return error(errh, "bad conversion: weight vector doesn't sum to 1");

    // adjust weight vector to max 4 decimal digits of precision, and make it
    // sum to exactly 1
    sum = 0;
    for (int m = 0; m < _nmasters - 1; m++) {
      weight[m] = floor(weight[m] * 10000. + 0.5) / 10000.;
      sum += weight[m];
    }
    weight[_nmasters - 1] = 1 - sum;
    
    return true;
}


Vector<double> *
MultipleMasterSpace::mm_vector(VectorType t, bool writable) const
{
    if (t == VEC_WEIGHT)
      return _weight_vector;
    else if (t == VEC_NORM_DESIGN)
      return _norm_design_vector;
    else if (t == VEC_DESIGN && !writable)
      return _design_vector;
    else
      return 0;
}

}

Generated by  Doxygen 1.6.0   Back to index