Back to index

tetex-bin  3.0
Public Member Functions | Static Public Member Functions | Protected Attributes | Private Member Functions | Private Attributes
PostScriptFunction Class Reference

#include <Function.h>

Inheritance diagram for PostScriptFunction:
Inheritance graph
[legend]
Collaboration diagram for PostScriptFunction:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 PostScriptFunction (Object *funcObj, Dict *dict)
virtual ~PostScriptFunction ()
virtual Functioncopy ()
virtual void transform (double *in, double *out)
virtual GBool isOk ()
GBool init (Dict *dict)
int getInputSize ()
int getOutputSize ()

Static Public Member Functions

static Functionparse (Object *funcObj)

Protected Attributes

int m
int n
double domain [funcMaxInputs][2]
double range [funcMaxOutputs][2]
GBool hasRange

Private Member Functions

 PostScriptFunction (PostScriptFunction *func)
GBool parseCode (Stream *str, int *codePtr)
GStringgetToken (Stream *str)
void resizeCode (int newSize)
void exec (PSStack *stack, int codePtr)

Private Attributes

PSObjectcode
int codeSize
GBool ok

Detailed Description

Definition at line 161 of file Function.h.


Constructor & Destructor Documentation

PostScriptFunction::PostScriptFunction ( Object funcObj,
Dict dict 
)

Definition at line 967 of file Function.cc.

                                                                  {
  Stream *str;
  int codePtr;
  GString *tok;

  code = NULL;
  codeSize = 0;
  ok = gFalse;

  //----- initialize the generic stuff
  if (!init(dict)) {
    goto err1;
  }
  if (!hasRange) {
    error(-1, "Type 4 function is missing range");
    goto err1;
  }

  //----- get the stream
  if (!funcObj->isStream()) {
    error(-1, "Type 4 function isn't a stream");
    goto err1;
  }
  str = funcObj->getStream();

  //----- parse the function
  str->reset();
  if (!(tok = getToken(str)) || tok->cmp("{")) {
    error(-1, "Expected '{' at start of PostScript function");
    if (tok) {
      delete tok;
    }
    goto err1;
  }
  delete tok;
  codePtr = 0;
  if (!parseCode(str, &codePtr)) {
    goto err2;
  }
  str->close();

  ok = gTrue;

 err2:
  str->close();
 err1:
  return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1022 of file Function.cc.

                                        {
  gfree(code);
}

Here is the call graph for this function:

Definition at line 1016 of file Function.cc.

                                                               {
  memcpy(this, func, sizeof(PostScriptFunction));
  code = (PSObject *)gmalloc(codeSize * sizeof(PSObject));
  memcpy(code, func->code, codeSize * sizeof(PSObject));
}

Here is the call graph for this function:


Member Function Documentation

virtual Function* PostScriptFunction::copy ( ) [inline, virtual]

Implements Function.

Definition at line 166 of file Function.h.

{ return new PostScriptFunction(this); }

Here is the call graph for this function:

void PostScriptFunction::exec ( PSStack stack,
int  codePtr 
) [private]

Definition at line 1209 of file Function.cc.

                                                         {
  int i1, i2;
  double r1, r2;
  GBool b1, b2;

  while (1) {
    switch (code[codePtr].type) {
    case psInt:
      stack->pushInt(code[codePtr++].intg);
      break;
    case psReal:
      stack->pushReal(code[codePtr++].real);
      break;
    case psOperator:
      switch (code[codePtr++].op) {
      case psOpAbs:
       if (stack->topIsInt()) {
         stack->pushInt(abs(stack->popInt()));
       } else {
         stack->pushReal(fabs(stack->popNum()));
       }
       break;
      case psOpAdd:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushInt(i1 + i2);
       } else {
         r2 = stack->popNum();
         r1 = stack->popNum();
         stack->pushReal(r1 + r2);
       }
       break;
      case psOpAnd:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushInt(i1 & i2);
       } else {
         b2 = stack->popBool();
         b1 = stack->popBool();
         stack->pushBool(b1 && b2);
       }
       break;
      case psOpAtan:
       r2 = stack->popNum();
       r1 = stack->popNum();
       stack->pushReal(atan2(r1, r2));
       break;
      case psOpBitshift:
       i2 = stack->popInt();
       i1 = stack->popInt();
       if (i2 > 0) {
         stack->pushInt(i1 << i2);
       } else if (i2 < 0) {
         stack->pushInt((int)((Guint)i1 >> i2));
       } else {
         stack->pushInt(i1);
       }
       break;
      case psOpCeiling:
       if (!stack->topIsInt()) {
         stack->pushReal(ceil(stack->popNum()));
       }
       break;
      case psOpCopy:
       stack->copy(stack->popInt());
       break;
      case psOpCos:
       stack->pushReal(cos(stack->popNum()));
       break;
      case psOpCvi:
       if (!stack->topIsInt()) {
         stack->pushInt((int)stack->popNum());
       }
       break;
      case psOpCvr:
       if (!stack->topIsReal()) {
         stack->pushReal(stack->popNum());
       }
       break;
      case psOpDiv:
       r2 = stack->popNum();
       r1 = stack->popNum();
       stack->pushReal(r1 / r2);
       break;
      case psOpDup:
       stack->copy(1);
       break;
      case psOpEq:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushBool(i1 == i2);
       } else if (stack->topTwoAreNums()) {
         r2 = stack->popNum();
         r1 = stack->popNum();
         stack->pushBool(r1 == r2);
       } else {
         b2 = stack->popBool();
         b1 = stack->popBool();
         stack->pushBool(b1 == b2);
       }
       break;
      case psOpExch:
       stack->roll(2, 1);
       break;
      case psOpExp:
       r2 = stack->popNum();
       r1 = stack->popNum();
       stack->pushReal(pow(r1, r2));
       break;
      case psOpFalse:
       stack->pushBool(gFalse);
       break;
      case psOpFloor:
       if (!stack->topIsInt()) {
         stack->pushReal(floor(stack->popNum()));
       }
       break;
      case psOpGe:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushBool(i1 >= i2);
       } else {
         r2 = stack->popNum();
         r1 = stack->popNum();
         stack->pushBool(r1 >= r2);
       }
       break;
      case psOpGt:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushBool(i1 > i2);
       } else {
         r2 = stack->popNum();
         r1 = stack->popNum();
         stack->pushBool(r1 > r2);
       }
       break;
      case psOpIdiv:
       i2 = stack->popInt();
       i1 = stack->popInt();
       stack->pushInt(i1 / i2);
       break;
      case psOpIndex:
       stack->index(stack->popInt());
       break;
      case psOpLe:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushBool(i1 <= i2);
       } else {
         r2 = stack->popNum();
         r1 = stack->popNum();
         stack->pushBool(r1 <= r2);
       }
       break;
      case psOpLn:
       stack->pushReal(log(stack->popNum()));
       break;
      case psOpLog:
       stack->pushReal(log10(stack->popNum()));
       break;
      case psOpLt:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushBool(i1 < i2);
       } else {
         r2 = stack->popNum();
         r1 = stack->popNum();
         stack->pushBool(r1 < r2);
       }
       break;
      case psOpMod:
       i2 = stack->popInt();
       i1 = stack->popInt();
       stack->pushInt(i1 % i2);
       break;
      case psOpMul:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         //~ should check for out-of-range, and push a real instead
         stack->pushInt(i1 * i2);
       } else {
         r2 = stack->popNum();
         r1 = stack->popNum();
         stack->pushReal(r1 * r2);
       }
       break;
      case psOpNe:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushBool(i1 != i2);
       } else if (stack->topTwoAreNums()) {
         r2 = stack->popNum();
         r1 = stack->popNum();
         stack->pushBool(r1 != r2);
       } else {
         b2 = stack->popBool();
         b1 = stack->popBool();
         stack->pushBool(b1 != b2);
       }
       break;
      case psOpNeg:
       if (stack->topIsInt()) {
         stack->pushInt(-stack->popInt());
       } else {
         stack->pushReal(-stack->popNum());
       }
       break;
      case psOpNot:
       if (stack->topIsInt()) {
         stack->pushInt(~stack->popInt());
       } else {
         stack->pushBool(!stack->popBool());
       }
       break;
      case psOpOr:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushInt(i1 | i2);
       } else {
         b2 = stack->popBool();
         b1 = stack->popBool();
         stack->pushBool(b1 || b2);
       }
       break;
      case psOpPop:
       stack->pop();
       break;
      case psOpRoll:
       i2 = stack->popInt();
       i1 = stack->popInt();
       stack->roll(i1, i2);
       break;
      case psOpRound:
       if (!stack->topIsInt()) {
         r1 = stack->popNum();
         stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
       }
       break;
      case psOpSin:
       stack->pushReal(sin(stack->popNum()));
       break;
      case psOpSqrt:
       stack->pushReal(sqrt(stack->popNum()));
       break;
      case psOpSub:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushInt(i1 - i2);
       } else {
         r2 = stack->popNum();
         r1 = stack->popNum();
         stack->pushReal(r1 - r2);
       }
       break;
      case psOpTrue:
       stack->pushBool(gTrue);
       break;
      case psOpTruncate:
       if (!stack->topIsInt()) {
         r1 = stack->popNum();
         stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
       }
       break;
      case psOpXor:
       if (stack->topTwoAreInts()) {
         i2 = stack->popInt();
         i1 = stack->popInt();
         stack->pushInt(i1 ^ i2);
       } else {
         b2 = stack->popBool();
         b1 = stack->popBool();
         stack->pushBool(b1 ^ b2);
       }
       break;
      case psOpIf:
       b1 = stack->popBool();
       if (b1) {
         exec(stack, codePtr + 2);
       }
       codePtr = code[codePtr + 1].blk;
       break;
      case psOpIfelse:
       b1 = stack->popBool();
       if (b1) {
         exec(stack, codePtr + 2);
       } else {
         exec(stack, code[codePtr].blk);
       }
       codePtr = code[codePtr + 1].blk;
       break;
      case psOpReturn:
       return;
      }
      break;
    default:
      error(-1, "Internal: bad object in PostScript function code");
      break;
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int Function::getInputSize ( ) [inline, inherited]

Definition at line 49 of file Function.h.

{ return m; }

Here is the caller graph for this function:

int Function::getOutputSize ( ) [inline, inherited]

Definition at line 50 of file Function.h.

{ return n; }

Here is the caller graph for this function:

Definition at line 1170 of file Function.cc.

                                                 {
  GString *s;
  int c;

  s = new GString();
  do {
    c = str->getChar();
  } while (c != EOF && isspace(c));
  if (c == '{' || c == '}') {
    s->append((char)c);
  } else if (isdigit(c) || c == '.' || c == '-') {
    while (1) {
      s->append((char)c);
      c = str->lookChar();
      if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
       break;
      }
      str->getChar();
    }
  } else {
    while (1) {
      s->append((char)c);
      c = str->lookChar();
      if (c == EOF || !isalnum(c)) {
       break;
      }
      str->getChar();
    }
  }
  return s;
}

Here is the call graph for this function:

Here is the caller graph for this function:

GBool Function::init ( Dict dict) [inherited]

Definition at line 81 of file Function.cc.

                               {
  Object obj1, obj2;
  int i;

  //----- Domain
  if (!dict->lookup("Domain", &obj1)->isArray()) {
    error(-1, "Function is missing domain");
    goto err2;
  }
  m = obj1.arrayGetLength() / 2;
  if (m > funcMaxInputs) {
    error(-1, "Functions with more than %d inputs are unsupported",
         funcMaxInputs);
    goto err2;
  }
  for (i = 0; i < m; ++i) {
    obj1.arrayGet(2*i, &obj2);
    if (!obj2.isNum()) {
      error(-1, "Illegal value in function domain array");
      goto err1;
    }
    domain[i][0] = obj2.getNum();
    obj2.free();
    obj1.arrayGet(2*i+1, &obj2);
    if (!obj2.isNum()) {
      error(-1, "Illegal value in function domain array");
      goto err1;
    }
    domain[i][1] = obj2.getNum();
    obj2.free();
  }
  obj1.free();

  //----- Range
  hasRange = gFalse;
  n = 0;
  if (dict->lookup("Range", &obj1)->isArray()) {
    hasRange = gTrue;
    n = obj1.arrayGetLength() / 2;
    if (n > funcMaxOutputs) {
      error(-1, "Functions with more than %d outputs are unsupported",
           funcMaxOutputs);
      goto err2;
    }
    for (i = 0; i < n; ++i) {
      obj1.arrayGet(2*i, &obj2);
      if (!obj2.isNum()) {
       error(-1, "Illegal value in function range array");
       goto err1;
      }
      range[i][0] = obj2.getNum();
      obj2.free();
      obj1.arrayGet(2*i+1, &obj2);
      if (!obj2.isNum()) {
       error(-1, "Illegal value in function range array");
       goto err1;
      }
      range[i][1] = obj2.getNum();
      obj2.free();
    }
  }
  obj1.free();

  return gTrue;

 err1:
  obj2.free();
 err2:
  obj1.free();
  return gFalse;
}

Here is the call graph for this function:

Here is the caller graph for this function:

virtual GBool PostScriptFunction::isOk ( ) [inline, virtual]

Implements Function.

Definition at line 168 of file Function.h.

{ return ok; }
Function * Function::parse ( Object funcObj) [static, inherited]

Definition at line 36 of file Function.cc.

                                         {
  Function *func;
  Dict *dict;
  int funcType;
  Object obj1;

  if (funcObj->isStream()) {
    dict = funcObj->streamGetDict();
  } else if (funcObj->isDict()) {
    dict = funcObj->getDict();
  } else if (funcObj->isName("Identity")) {
    return new IdentityFunction();
  } else {
    error(-1, "Expected function dictionary or stream");
    return NULL;
  }

  if (!dict->lookup("FunctionType", &obj1)->isInt()) {
    error(-1, "Function type is missing or wrong type");
    obj1.free();
    return NULL;
  }
  funcType = obj1.getInt();
  obj1.free();

  if (funcType == 0) {
    func = new SampledFunction(funcObj, dict);
  } else if (funcType == 2) {
    func = new ExponentialFunction(funcObj, dict);
  } else if (funcType == 3) {
    func = new StitchingFunction(funcObj, dict);
  } else if (funcType == 4) {
    func = new PostScriptFunction(funcObj, dict);
  } else {
    error(-1, "Unimplemented function type (%d)", funcType);
    return NULL;
  }
  if (!func->isOk()) {
    delete func;
    return NULL;
  }

  return func;
}

Here is the call graph for this function:

Here is the caller graph for this function:

GBool PostScriptFunction::parseCode ( Stream str,
int codePtr 
) [private]

Definition at line 1050 of file Function.cc.

                                                             {
  GString *tok;
  char *p;
  GBool isReal;
  int opPtr, elsePtr;
  int a, b, mid, cmp;

  while (1) {
    if (!(tok = getToken(str))) {
      error(-1, "Unexpected end of PostScript function stream");
      return gFalse;
    }
    p = tok->getCString();
    if (isdigit(*p) || *p == '.' || *p == '-') {
      isReal = gFalse;
      for (++p; *p; ++p) {
       if (*p == '.') {
         isReal = gTrue;
         break;
       }
      }
      resizeCode(*codePtr);
      if (isReal) {
       code[*codePtr].type = psReal;
       code[*codePtr].real = atof(tok->getCString());
      } else {
       code[*codePtr].type = psInt;
       code[*codePtr].intg = atoi(tok->getCString());
      }
      ++*codePtr;
      delete tok;
    } else if (!tok->cmp("{")) {
      delete tok;
      opPtr = *codePtr;
      *codePtr += 3;
      resizeCode(opPtr + 2);
      if (!parseCode(str, codePtr)) {
       return gFalse;
      }
      if (!(tok = getToken(str))) {
       error(-1, "Unexpected end of PostScript function stream");
       return gFalse;
      }
      if (!tok->cmp("{")) {
       elsePtr = *codePtr;
       if (!parseCode(str, codePtr)) {
         return gFalse;
       }
       delete tok;
       if (!(tok = getToken(str))) {
         error(-1, "Unexpected end of PostScript function stream");
         return gFalse;
       }
      } else {
       elsePtr = -1;
      }
      if (!tok->cmp("if")) {
       if (elsePtr >= 0) {
         error(-1, "Got 'if' operator with two blocks in PostScript function");
         return gFalse;
       }
       code[opPtr].type = psOperator;
       code[opPtr].op = psOpIf;
       code[opPtr+2].type = psBlock;
       code[opPtr+2].blk = *codePtr;
      } else if (!tok->cmp("ifelse")) {
       if (elsePtr < 0) {
         error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
         return gFalse;
       }
       code[opPtr].type = psOperator;
       code[opPtr].op = psOpIfelse;
       code[opPtr+1].type = psBlock;
       code[opPtr+1].blk = elsePtr;
       code[opPtr+2].type = psBlock;
       code[opPtr+2].blk = *codePtr;
      } else {
       error(-1, "Expected if/ifelse operator in PostScript function");
       delete tok;
       return gFalse;
      }
      delete tok;
    } else if (!tok->cmp("}")) {
      delete tok;
      resizeCode(*codePtr);
      code[*codePtr].type = psOperator;
      code[*codePtr].op = psOpReturn;
      ++*codePtr;
      break;
    } else {
      a = -1;
      b = nPSOps;
      // invariant: psOpNames[a] < tok < psOpNames[b]
      while (b - a > 1) {
       mid = (a + b) / 2;
       cmp = tok->cmp(psOpNames[mid]);
       if (cmp > 0) {
         a = mid;
       } else if (cmp < 0) {
         b = mid;
       } else {
         a = b = mid;
       }
      }
      if (cmp != 0) {
       error(-1, "Unknown operator '%s' in PostScript function",
             tok->getCString());
       delete tok;
       return gFalse;
      }
      delete tok;
      resizeCode(*codePtr);
      code[*codePtr].type = psOperator;
      code[*codePtr].op = (PSOp)a;
      ++*codePtr;
    }
  }
  return gTrue;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void PostScriptFunction::resizeCode ( int  newSize) [private]

Definition at line 1202 of file Function.cc.

                                               {
  if (newSize >= codeSize) {
    codeSize += 64;
    code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject));
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void PostScriptFunction::transform ( double *  in,
double *  out 
) [virtual]

Implements Function.

Definition at line 1026 of file Function.cc.

                                                          {
  PSStack *stack;
  int i;

  stack = new PSStack();
  for (i = 0; i < m; ++i) {
    //~ may need to check for integers here
    stack->pushReal(in[i]);
  }
  exec(stack, 0);
  for (i = n - 1; i >= 0; --i) {
    out[i] = stack->popNum();
    if (out[i] < range[i][0]) {
      out[i] = range[i][0];
    } else if (out[i] > range[i][1]) {
      out[i] = range[i][1];
    }
  }
  // if (!stack->empty()) {
  //   error(-1, "Extra values on stack at end of PostScript function");
  // }
  delete stack;
}

Here is the call graph for this function:


Member Data Documentation

Definition at line 178 of file Function.h.

Definition at line 179 of file Function.h.

double Function::domain[funcMaxInputs][2] [protected, inherited]

Definition at line 61 of file Function.h.

GBool Function::hasRange [protected, inherited]

Definition at line 64 of file Function.h.

int Function::m [protected, inherited]

Definition at line 59 of file Function.h.

int Function::n [protected, inherited]

Definition at line 59 of file Function.h.

Definition at line 180 of file Function.h.

double Function::range[funcMaxOutputs][2] [protected, inherited]

Definition at line 63 of file Function.h.


The documentation for this class was generated from the following files: