commit 63f258e83e92979388721f57ff1f9500140f6ea6
parent 900ea78da3b57a7c03a76609c671676c2bd13dd1
Author: tomas <tomas@logand.com>
Date:   Sat, 23 Jan 2010 14:23:42 +0100
Second commit
Diffstat:
| M | wps.js |  |  | 794 | +++++++++++++++++++++++++++---------------------------------------------------- | 
| M | wps.wps |  |  | 411 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- | 
2 files changed, 490 insertions(+), 715 deletions(-)
diff --git a/wps.js b/wps.js
@@ -1,252 +1,265 @@
 function PdfT(V) {
-   this.V = V;
-   return this;
+  this.V = V;
+  return this;
 }
+
 function isPdfT(V) {
-   return V.constructor == PdfT; // TODO better test
+  return V.constructor == PdfT; // TODO better test
 }
 
 function ps0(L, F, S) {
-   var N = L.length;
-   var I = 0;
-   if(!S) S = [];
-
-   function member(C, L) {return 0 <= L.indexOf(C);}
-   function peek() {return I < N && L[I];}
-   function xchar() {return I < N && L[I++];}
-   function skip() {while(I < N && member(L[I], " \t\n")) I++;}
-
-   function comment() {
-      while("%" == peek()) {
-         while(peek() && "\n" != peek())
-            xchar();
-         skip();
-      }
-   }
-
-   function text() {
-      xchar();
-      var L = [];
-      var N = 1;
-      while(0 < N && peek()) {
-         var C = xchar();
-         switch(C) {
-            case "(":
-               N++;
-               break;
-            case ")":
-               N--;
-               if(N <= 0) C = false;
-               break;
-            case "\\":
-               C = xchar();
-               switch(C) {
-                  case "(": break;
-                  case ")": break;
-                  case "\\": break;
-                  case "n": C = "\n"; break;
-                  case "r": C = "\r"; break;
-                  case "t": C = "\t"; break;
-                  default:
-                     C = false;
-               }
-               break;
-         }
-         if(C !== false) L.push(C);
-      }
-      return new PdfT(L.join(""));
-   }
-
-   function symbol() {
+  var N = L.length;
+  var I = 0;
+
+  function member(C, L) {return 0 <= L.indexOf(C);}
+  function peek() {return I < N && L[I];}
+  function xchar() {return I < N && L[I++];}
+  function skip() {while(I < N && member(L[I], " \t\n")) I++;}
+
+  function comment() {
+    while("%" == peek()) {
+      while(peek() && "\n" != peek())
+        xchar();
+      skip();
+    }
+  }
+
+  function text() { // TODO hex text in <>
+    xchar();
+    var L = [];
+    var N = 1;
+    while(0 < N && peek()) {
       var C = xchar();
-      var N = member(C, "+-0123456789.");
-      var F = "." == C;
-      var L = [C];
-      while(peek() && !member(peek(), "%/[]{}<>( \t\n")) {
-         C = xchar();
-         L.push(C);
-         if(N && !member(C, "0123456789")) {
-            if(!F && "." == C) F = true;
-            else N = false;
-         }
+      switch(C) {
+        case "(":
+          N++;
+          break;
+        case ")":
+          N--;
+          if(N <= 0) C = false;
+          break;
+        case "\\":
+          C = xchar();
+          switch(C) {
+            case "(": break;
+            case ")": break;
+            case "\\": break;
+            case "n": C = "\n"; break;
+            case "r": C = "\r"; break;
+            case "t": C = "\t"; break;
+            default:
+              C = false;
+          }
+          break;
       }
-      L = L.join("");
-      if(1 == L.length && member(L, "+-.")) N = false;
-      return N ? (F ? parseFloat(L) : parseInt(L, 10)) : L;
-   }
-
-   function code() {
-      xchar();
-      var L = [];
-      while(peek()) {
-         var T = token();
-         if("}" == T) break;
-         if(T || T == 0) L.push(T);
+      if(C !== false) L.push(C);
+    }
+    return new PdfT(L.join(""));
+  }
+
+  function symbol() {
+    var C = xchar();
+    var N = member(C, "+-0123456789.");
+    var F = "." == C;
+    var L = [C];
+    while(peek() && !member(peek(), "%/[]{}<>( \t\n")) {
+      C = xchar();
+      L.push(C);
+      if(N && !member(C, "0123456789")) {
+        if(!F && "." == C) F = true;
+        else N = false;
       }
-      return L;
-   }
-
-   function token() {
-      skip();
-      switch(peek()) {
-         case false: return undefined;
-         case "%": return comment();
-         case "[": return xchar();
-         case "]": return xchar();
-         case "{": return code();
-         case "}": return xchar();
-         case "(": return text();
-         default: return symbol();
-      }
-   }
+    }
+    L = L.join("");
+    if(1 == L.length && member(L, "+-.")) N = false;
+    return N ? (F ? parseFloat(L) : parseInt(L, 10)) : L;
+  }
+
+  function proc() { // TODO supress evaluation???
+    xchar();
+    var L = [];
+    while(peek()) {
+      var T = token();
+      if("}" == T) break;
+      if(T || T == 0) L.push(T);
+    }
+    return L;
+  }
+
+  function token() {
+    skip();
+    switch(peek()) { // TODO read dict in <<>>
+      case false: return undefined;
+      case "%": return comment();
+      case "[": return xchar();
+      case "]": return xchar();
+      case "{": return proc();
+      case "}": return xchar();
+      case "(": return text();
+      default: return symbol();
+    }
+  }
 
 //   function quoted(T) {
 //      return typeof T == "string" && "/" == T.charAt(0);
 //   }
 
-   function parse(E) {
-      var G = true;
-      while(G && peek()) {
-         var T = token();
-         if(T || T == 0) {
-            if(typeof T == "number" || typeof T == "object" || quoted(T))
-               S.push(T);
-            else {
-               if(F[T]) F[T]();
-               else throw "Unknown operator '" + T + "' " + typeof T;
-               if(E == T) G = false;
-            }
-         }
+  function parse(E) {
+    var G = true;
+    while(G && peek()) {
+      var T = token();
+      if(T || T == 0) {
+        if(typeof T == "number" || typeof T == "object" || quoted(T))
+          S.push(T);
+        else {
+          if(F[T]) F[T]();
+          else throw "Unknown operator '" + T + "' " + typeof T;
+          if(E == T) G = false;
+        }
       }
-      return S;
-   }
+    }
+    return S;
+  }
 
-   return parse();
+  return parse();
 }
 
 function quoted(T) {
-   return typeof T == "string" && "/" == T.charAt(0);
+  return typeof T == "string" && "/" == T.charAt(0);
 }
 
-function wps(E, W, H, T) {
-   var S = [];
-   var F = {};
-   var C = E.getContext("2d");
-
-   E.setAttribute("width", W);
-   E.setAttribute("height", H);
-
-   function min(X, Y) {
-      return X < Y ? X : Y;
-   }
-   function max(X, Y) {
-      return X < Y ? Y : X;
-   }
-
-   // basic operators
-
-   F["true"] = function() {S.push(true);};
-   F["false"] = function() {S.push(false);};
-   F["null"] = function() {S.push(null);};
-
-   F["neg"] = function() {S.push(- S.pop());};
-   F["add"] = function() {S.push(S.pop() + S.pop());};
-   F["sub"] = function() {F["neg"](); F["add"]();};
-   F["mul"] = function() {S.push(S.pop() * S.pop());};
-   F["div"] = function() {
-      var X = S.pop();
-      S.push(S.pop() / X);
-   };
-   F["idiv"] = function() {
-      var X = S.pop();
-      S.push(Math.floor(S.pop() / X));
-   };
-   F["mod"] = function() {
-      var X = S.pop();
-      S.push(S.pop() % X);
-   };
-   // TODO sqrt, exp, ceiling, sin
-   F["exch"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      S.push(Y);
-      S.push(X);
-   };
-
-   F["dup"] = function() {var X = S.pop(); S.push(X); S.push(X);};
-   F["clear"] = function() {S = [];};
-   F["pop"] = function() {S.pop();};
-   // TODO roll
-
-   F["eq"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      S.push(X == Y);
-   };
-   F["ne"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      S.push(X != Y);
-   };
-   F["gt"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      S.push(X > Y);
-   };
-   F["lt"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      S.push(X < Y);
-   };
-   F["ge"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      S.push(X >= Y);
-   };
-   F["le"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      S.push(X <= Y);
-   };
-
-   F["if"] = function() {
-      var B = S.pop();
-      var C = S.pop();
-      if(C == true) run(B);
-   };
-   F["ifelse"] = function() {
-      var N = S.pop();
-      var P = S.pop();
-      var C = S.pop();
-      if(C == true) run(P);
-      else run(N);
-   };
-   F["repeat"] = function() {
-      var B = S.pop();
-      var N = S.pop();
-      for(var I = 0; I < N; I++) run(B);
-   };
-   F["for"] = function() {
-      var B = S.pop();
-      var L = S.pop();
-      var K = S.pop();
-      var J = S.pop();
-      if(K < 0) {
-         for(var I = J; L <= I; I += K) {
-            S.push(I);
-            run(B);
-         }
-      } else {
-         for(var I = J; I <= L; I += K) {
-            S.push(I);
-            run(B);
-         }
+function wps(E, T) {
+  var S = [];
+  var F = {};
+  var C = E.getContext("2d");
+
+  F["get"] = function() { // dict key -- any
+    var K = S.pop();
+    var D = S.pop();
+    // TODO other datatypes http://www.capcode.de/help/get
+    S.push(D[K.substring(1)]);
+  };
+  F["put"] = function() { // dict key any --
+    var V = S.pop();
+    var K = S.pop();
+    var D = S.pop();
+    // TODO other datatypes http://www.capcode.de/help/put
+    D[K.substring(1)] = V;
+  };
+
+  F["true"] = function() {S.push(true);};
+  F["false"] = function() {S.push(false);};
+  F["null"] = function() {S.push(null);};
+
+  F["neg"] = function() {S.push(- S.pop());};
+  F["add"] = function() {S.push(S.pop() + S.pop());};
+  F["mul"] = function() {S.push(S.pop() * S.pop());};
+  F["div"] = function() {
+    var X = S.pop();
+    S.push(S.pop() / X);
+  };
+  F["idiv"] = function() {
+    var X = S.pop();
+    S.push(Math.floor(S.pop() / X));
+  };
+  F["mod"] = function() {
+    var X = S.pop();
+    S.push(S.pop() % X);
+  };
+  // TODO sqrt, exp, ceiling, sin
+  F["exch"] = function() {
+    var Y = S.pop();
+    var X = S.pop();
+    S.push(Y);
+    S.push(X);
+  };
+
+  F["dup"] = function() {var X = S.pop(); S.push(X); S.push(X);};
+  F["clear"] = function() {S.length = 0;};
+  F["pop"] = function() {S.pop();};
+  F["roll"] = function() { // n j --
+    var J = S.pop();
+    var N = S.pop();
+    var X = [];
+    var Y = [];
+    //alert("roll 1 " + N + " " + J + " " + S);
+    for(var I = 0; I < N; I++)
+      if(I < J) X.unshift(S.pop());
+      else Y.unshift(S.pop());
+    for(I = 0; I < J; I++) S.push(X.shift());
+    for(I = 0; I < N - J; I++) S.push(Y.shift());
+    //alert("roll 2 " + N + " " + J + " " + S);
+  };
+
+  F["eq"] = function() {
+    var Y = S.pop();
+    var X = S.pop();
+    S.push(X == Y);
+  };
+  F["ne"] = function() {
+    var Y = S.pop();
+    var X = S.pop();
+    S.push(X != Y);
+  };
+  F["gt"] = function() {
+    var Y = S.pop();
+    var X = S.pop();
+    S.push(X > Y);
+  };
+  F["lt"] = function() {
+    var Y = S.pop();
+    var X = S.pop();
+    S.push(X < Y);
+  };
+  F["ge"] = function() {
+    var Y = S.pop();
+    var X = S.pop();
+    S.push(X >= Y);
+  };
+  F["le"] = function() {
+    var Y = S.pop();
+    var X = S.pop();
+    S.push(X <= Y);
+  };
+
+  F["if"] = function() {
+    var B = S.pop();
+    var C = S.pop();
+    if(C == true) run(B);
+  };
+  F["ifelse"] = function() {
+    var N = S.pop();
+    var P = S.pop();
+    var C = S.pop();
+    if(C == true) run(P);
+    else run(N);
+  };
+  F["repeat"] = function() {
+    var B = S.pop();
+    var N = S.pop();
+    for(var I = 0; I < N; I++) run(B);
+  };
+  F["for"] = function() {
+    var B = S.pop();
+    var L = S.pop();
+    var K = S.pop();
+    var J = S.pop();
+    if(K < 0) {
+      for(var I = J; L <= I; I += K) {
+        S.push(I);
+        run(B);
       }
-   };
+    } else {
+      for(var I = J; I <= L; I += K) {
+        S.push(I);
+        run(B);
+      }
+    }
+  };
 
-   F["."] = function() {alert(S.pop());};
-   F["=="] = function() {alert(S[0]);};
-   F["pstack"] = function() {alert(S);};
+  F["."] = function() {alert(S.pop());};
+  F["=="] = function() {alert(S[0]);};
+  F["pstack"] = function() {alert(S);};
 
    function run(C) {
       if(!C.length) S.push(C);
@@ -271,305 +284,40 @@ function wps(E, W, H, T) {
       else throw "Wrong operator name " + N + " for " + C;
    };
 
-   // html5 graphic operators
-
-   //transform
-   //setTransform
-   //createLinearGradient
-   //createRadialGradient
-   //createPatternI
-   //createPatternC
-   //createPatternV
-   F["clearRect"] = function() {
-      var H = S.pop();
-      var W = S.pop();
-      var Y = S.pop();
-      var X = S.pop();
-      C.clearRect(X, Y, W, H);
-   };
-   F["fillRect"] = function() {
-      var H = S.pop();
-      var W = S.pop();
-      var Y = S.pop();
-      var X = S.pop();
-      C.fillRect(X, Y, W, H);
-   };
-   F["strokeRect"] = function() {
-      var H = S.pop();
-      var W = S.pop();
-      var Y = S.pop();
-      var X = S.pop();
-      C.strokeRect(X, Y, W, H);
-   };
-   //quadraticCurveTo
-   F["rect"] = function() {
-      var H = S.pop();
-      var W = S.pop();
-      var Y = S.pop();
-      var X = S.pop();
-      C.strokeRect(X, Y, W, H);
-   };
-   //isPointInPath
-   //fillText
-   //strokeText
-   //measureText
-   //drawImageI1
-   //drawImageI2
-   //drawImageC1
-   //drawImageC2
-   //drawImageV1
-   //drawImageV2
-   //createImageData1
-   //createImageData2
-   //getImageData
-   //putImageData
+  // js ffi operators
 
-   // html5 utility operators
-
-   F["gput"] = function() {
-      var K = S.pop();
+  F["call"] = function() { // fn nargs -- ...
+    var A = S.pop();
+    var N = S.pop();
+    var X = [];
+    for(var I = 0; I < A; I++) {
+      // TODO fix PdfT + quoted
       var V = S.pop();
-      C[K.substring(1)] = isPdfT(V) ? V.V : V;
-   };
-   F["gget"] = function() {
-      var K = S.pop();
-      S.push(C[K.substring(1)]);
-   };
-
-   F["rgb"] = function() {
-      var B = S.pop();
-      var G = S.pop();
-      var R = S.pop();
-      S.push(new PdfT("rgba(" + R + "," + G + "," + B + ")"));
-   };
-   F["rgba"] = function() {
-      var A = S.pop();
-      var B = S.pop();
-      var G = S.pop();
-      var R = S.pop();
-      S.push(new PdfT("rgba(" + R + "," + G + "," + B + "," + A + ")"));
-   };
-
-   // ps graphic operators
-
-   F["gsave"] = function() {C.save();};
-   F["grestore"] = function() {C.restore();};
-   F["scale"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      C.scale(X, Y);
-   };
-   F["rotate"] = function() {
-      var A = S.pop();
-      C.rotate(A);
-   };
-   F["translate"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      C.translate(X, Y);
-   };
-   F["newpath"] = function() {C.beginPath();};
-   F["closepath"] = function() {C.closePath();};
-   F["moveto"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      C.moveTo(X, Y);
-   };
-   F["lineto"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      C.lineTo(X, Y);
-   };
-   F["arcto"] = function() {
-      var R = S.pop();
-      var Y2 = S.pop();
-      var X2 = S.pop();
-      var Y1 = S.pop();
-      var X1 = S.pop();
-      C.arcTo(X1, Y1, X2, Y2, R);
-   };
-   F["arc"] = function() {
-      var A = S.pop();
-      var E = S.pop();
-      var B = S.pop();
-      var R = S.pop();
-      var Y = S.pop();
-      var X = S.pop();
-      C.arc(X, Y, R, B, E, A);
-   };
-   F["fill"] = function() {C.fill();};
-   F["stroke"] = function() {C.stroke();};
-   F["clip"] = function() {C.clip();};
-   F["setgray"] = function() {
-      var G = S.pop();
-      C.fillStyle = "rgb(" + G * 255 + "," + G * 255 + "," + G * 255 + ")";
-   };
-
-   // TODO eps operators
-
-   F["save"] = function() {S.push(true);};
-   F["restore"] = function() {S.push(true);};
-   F["bind"] = function() {};
-   F["dict"] = function() {};
-   F["load"] = function() {};
-   F["begin"] = function() {};
-   F["end"] = function() {};
-   F["where"] = function() {};
-   F["currentflat"] = function() {};
-   F["setflat"] = function() {};
-   F["_"] = function() {};
-   F["clippath"] = function() {};
-
-   // pdf graphic operators
-
-   F["w"] = function() {C.lineWidth = S.pop();};
-   F["J"] = function() {C.lineCap = S.pop();};
-   F["j"] = function() {C.lineJoin = S.pop();};
-   F["M"] = function() {C.mitterLimit = S.pop();};
-   F["d"] = function() {
-      var P = S.pop();
-      var A = S.pop();
-      alert("TODO d");
-   };
-   F["ri"] = function() {alert("TODO ri");};
-   F["i"] = function() {alert("TODO i");};
-   F["gs"] = function() {alert("TODO gs");};
-
-   F["q"] = function() {C.save();};
-   F["Q"] = function() {C.restore();};
-   F["cm"] = function() { // TODO fix cm
-      var Dy = S.pop();
-      var Dx = S.pop();
-      var M22 = S.pop();
-      var M21 = S.pop();
-      var M12 = S.pop();
-      var M11 = S.pop();
-      //alert(M11 +"|"+ M12 +"|"+ M21 +"|"+ M22 +"|"+ Dx +"|"+ Dy);
-      //C.setTransform(M11, M12, M21, M22, Dx, Dy);
-      C.transform(M11, M12, M21, M22, Dx, Dy);
-   };
-
-   F["m"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      C.beginPath(); // TODO only if not m previously
-      C.moveTo(X, Y);
-   };
-   F["l"] = function() {
-      var Y = S.pop();
-      var X = S.pop();
-      C.lineTo(X, Y);
-   };
-   F["c"] = function() {
-      var Y3 = S.pop();
-      var X3 = S.pop();
-      var Y2 = S.pop();
-      var X2 = S.pop();
-      var Y1 = S.pop();
-      var X1 = S.pop();
-      C.bezierCurveTo(X1, Y1, X2, Y2, X3, Y3); // TODO the right c method
-   };
-//   F["c2"] = function() { // not in pdf
-//      var Y3 = S.pop();
-//      var X3 = S.pop();
-//      var Y2 = S.pop();
-//      var X2 = S.pop();
-//      var Y1 = S.pop();
-//      var X1 = S.pop();
-//      C.bezierCurveTo(X1, Y1, X2, Y2, X3, Y3); // TODO the right c method
-//   };
-   F["v"] = function() {alert("TODO v");};
-   F["y"] = function() {alert("TODO y");};
-   F["h"] = function() {C.closePath();};
-   F["re"] = function() {
-      var Y2 = S.pop();
-      var X2 = S.pop();
-      var Y1 = S.pop();
-      var X1 = S.pop();
-      C.rect(X1, Y1, X2, Y2);
-   };
-
-   F["S"] = function() {C.stroke();};
-   F["s"] = function() {F["h"](); F["S"]();};
-   F["f"] = function() {C.fill();};
-   F["F"] = function() {C.fill();};
-   F["f*"] = function() {alert("TODO f*");};
-   F["B"] = function() {F["f"](); F["S"]();};
-   F["B*"] = function() {F["f*"](); F["S"]();};
-   F["b"] = function() {F["h"](); F["B"]();};
-   F["b*"] = function() {F["h"](); F["B*"]();};
-   F["n"] = function() {alert("TODO n");};
-
-   F["W"] = function() {C.clip();};
-   F["W*"] = function() {alert("TODO W*");};
-
-   F["BT"] = function() {alert("TODO BT");};
-   F["ET"] = function() {alert("TODO ET");};
-
-   F["Tc"] = function() {alert("TODO Tc");};
-   F["Tw"] = function() {alert("TODO Tw");};
-   F["Tz"] = function() {alert("TODO Tz");};
-   F["TL"] = function() {alert("TODO Tf");};
-   F["Tf"] = function() {
-      var N = S.pop();
-      var F = S.pop();
-      C.font = N + "pt " + F.V;
-   };
-   F["Tr"] = function() {alert("TODO Tr");};
-   F["Ts"] = function() {alert("TODO Ts");};
-
-   F["Td"] = function() {alert("TODO Td");};
-   F["TD"] = function() {alert("TODO TD");};
-   F["Tm"] = function() {alert("TODO Tm");};
-   F["T*"] = function() {alert("TODO T*");};
-
-   F["Tj"] = function() {
-      var T = S.pop();
-      //alert(T.V);
-      //if(C.strokeText) C.strokeText(T.V, 0, 0);
-      if(C.fillText) C.fillText(T.V, 0, 0);
-   };
-   F["TJ"] = function() {alert("TODO TJ");};
-   F["'"] = function() {alert("TODO '");};
-   F["\""] = function() {alert("TODO \"");};
-
-   F["d0"] = function() {alert("TODO d0");};
-   F["d1"] = function() {alert("TODO d1");};
-
-   F["CS"] = function() {alert("TODO CS");};
-   F["cs"] = function() {alert("TODO cs");};
-   F["SC"] = function() {alert("TODO SC");};
-   F["SCN"] = function() {alert("TODO SCN");};
-   F["sc"] = function() {alert("TODO sc");};
-   F["scn"] = function() {alert("TODO scn");};
-   F["G"] = function() {alert("TODO G");};
-   F["g"] = function() {alert("TODO g");};
-   F["RG"] = function() {alert("TODO RG");};
-   F["rg"] = function() { // TODO color spaces
-      var B = S.pop();
-      var G = S.pop();
-      var R = S.pop();
-      C.fillStyle = "rgb(" + R + "," + G + "," + B + ")";
-   };
-   F["K"] = function() {alert("TODO K");};
-   F["k"] = function() {alert("TODO k");};
-
-   F["sh"] = function() {alert("TODO sh");};
-
-   F["BI"] = function() {alert("TODO BI");};
-   F["ID"] = function() {alert("TODO ID");};
-   F["EI"] = function() {alert("TODO EI");};
-
-   F["Do"] = function() {alert("TODO Do");};
-
-   F["MP"] = function() {alert("TODO MP");};
-   F["DP"] = function() {alert("TODO DP");};
-   F["BMC"] = function() {alert("TODO BMC");};
-   F["BDC"] = function() {alert("TODO BDC");};
-   F["EMC"] = function() {alert("TODO EMC");};
-
-   F["BX"] = function() {alert("TODO BX");};
-   F["EX"] = function() {alert("TODO EX");};
+      X.unshift(isPdfT(V) ? V.V : (quoted(V) ? V.substring(1) : V));
+    }
+    alert("call " + N + " " + A);
+    N.apply(this, X);
+  };
+
+  F["gc"] = function() { // -- gc
+    S.push(C);
+  };
+
+  // html5 utility operators
+
+  F["rgb"] = function() {
+    var B = S.pop();
+    var G = S.pop();
+    var R = S.pop();
+    S.push(new PdfT("rgb(" + R + "," + G + "," + B + ")"));
+  };
+  F["rgba"] = function() {
+    var A = S.pop();
+    var B = S.pop();
+    var G = S.pop();
+    var R = S.pop();
+    S.push(new PdfT("rgba(" + R + "," + G + "," + B + "," + A + ")"));
+  };
 
   if(T.length)
     for(var I = 0; I < T.length; I++)
diff --git a/wps.wps b/wps.wps
@@ -1,207 +1,241 @@
-%%% wps.wps -- postscript and pdf operators for html 5 canvas
 %%% (c) 2009 Tomas Hlavaty
 
-%% basic operators
-
-/sub { % num num -- num
-  neg add
-} def
-
-%% html5 operators
+%% math
+
+/abs      {.math (abs) 1 .call} def
+/.acos    {.math (acos) 1 .call} def
+/.asin    {.math (asin) 1 .call} def
+/atan     {exch .math (atan) 1 .call} def
+/.atan2   {.math (atan2) 2 .call} def
+/ceiling  {.math (ceil) 1 .call} def
+/cos      {.math (cos) 1 .call} def
+/.exp     {.math (exp) 1 .call} def
+/floor    {.math (floor) 1 .call} def
+/log      {.math (log) 1 .call} def
+/.max     {.math (max) 2 .call} def
+/.min     {.math (min) 2 .call} def
+/.pow     {.math (pow) 2 .call} def
+/.random  {.math (random) 0 .call} def
+/rand     {.random} def % TODO follow spec
+/round    {.math (round) 1 .call} def
+/sin      {.math (sin) 1 .call} def
+/sqrt     {.math (sqrt) 1 .call} def
+/.tan     {.math (tan) 1 .call} def
+/truncate {.math (truncate) 1 .call} def % TODO Math.truncate does not exist!
+
+/.e       {.math (E) get} def
+/.ln2     {.math (LN2) get} def
+/.ln10    {.math (LN10) get} def
+/.log2e   {.math (LOG2E) get} def
+/.log10e  {.math (LOG10E) get} def
+/.pi      {.math (PI) get} def
+/.sqrt1_2 {.math (SQRT1_2) get} def
+/.sqrt2   {.math (SQRT2) get} def
+
+/sub     {neg add} def
+/idiv    {div .floor} def
+
+%% html5
 
 /.gget { % key --
-  gc exch
+  .gc exch
   get
 } def
 
 /.gput { % any key --
-  gc 3 1 roll exch
+  .gc 3 1 roll exch
   put
 } def
 
-/.gcall { % key nargs --
-  gc 3 1 roll call
+/.gcall0 { % key nargs --
+  .gc 3 1 roll .call pop
+} def
+
+/.gcall1 { % key nargs -- result
+  .gc 3 1 roll .call
 } def
 
 /.gcanvas { % -- canvas
-  /canvas .gget
+  (canvas) .gget
 } def
 
 /.gdim { % w h --
-  .gcanvas exch /height exch put
-  .gcanvas exch /width exch put
+  .gcanvas exch (height) exch put
+  .gcanvas exch (width) exch put
 } def
 
-/gbox { % x0 y0 x1 y1 --
+/.gbox { % x0 y0 x1 y1 --
   % TODO compute properly
   .gdim
   pop
   pop
 } def
 
-/.save    {/save 0 .gcall} def
-/.restore {/restore 0 .gcall} def
+/.save    {(save) 0 .gcall0} def
+/.restore {(restore) 0 .gcall0} def
 
 /scale { % x y --
-  /scale 2 .gcall
+  (scale) 2 .gcall0
 } def
 
 /rotate { % angle --
-  /rotate 1 .gcall
+  (rotate) 1 .gcall0
 } def
 
 /translate { % x y --
-  /translate 2 .gcall
+  (translate) 2 .gcall0
 } def
 
-/transform { % m11 m12 m21 m22 dx dy --
-  /transform 6 .gcall
+/.transform { % m11 m12 m21 m22 dx dy --
+  (transform) 6 .gcall0
 } def
 
-/setTransform { % m11 m12 m21 m22 dx dy --
-  /setTransform 6 .gcall
+/.setTransform { % m11 m12 m21 m22 dx dy --
+  (setTransform) 6 .gcall0
 } def
 
-/createLinearGradient { % x0 y0 x1 y1 -- CanvasGradient
-  /createLinearGradient 4 .gcall
+/.createLinearGradient { % x0 y0 x1 y1 -- CanvasGradient
+  (createLinearGradient) 4 .gcall1
 } def
 
-/createRadialGradient { % x0 y0 r0 x1 y1 r1 -- CanvasGradient
-  /createRadialGradient 6 .gcall
+/.createRadialGradient { % x0 y0 r0 x1 y1 r1 -- CanvasGradient
+  (createRadialGradient) 6 .gcall1
 } def
 
-/createPattern { % image repetition -- CanvasPattern
-  /createPattern 2 .gcall
+/.createPattern { % image repetition -- CanvasPattern
+  (createPattern) 2 .gcall1
 } def
 
 /.clearRect { % x y w h --
-  /clearRect 4 .gcall
+  (clearRect) 4 .gcall0
 } def
 
 /.fillRect { % x y w h --
-  /fillRect 4 .gcall
+  (fillRect) 4 .gcall0
 } def
 
 /.strokeRect { % x y w h --
-  /strokeRect 4 .gcall
+  (strokeRect) 4 .gcall0
 } def
 
-/.beginPath {/.beginPath 0 .gcall} def
-/.closePath {/.closePath 0 .gcall} def
+/.beginPath {(beginPath) 0 .gcall0} def
+/.closePath {(closePath) 0 .gcall0} def
 
 /.moveTo { % x y --
-  /moveTo 2 .gcall
+  (moveTo) 2 .gcall0
 } def
 
 /.lineTo { % x y --
-  /lineTo 2 .gcall
+  (lineTo) 2 .gcall0
 } def
 
-/quadraticCurveTo { % cpx cpy x y --
-  /quadraticCurveTo 4 .gcall
+/.quadraticCurveTo { % cpx cpy x y --
+  (quadraticCurveTo) 4 .gcall0
 } def
 
-/bezierCurveTo { % cp1x cp1y cp2x cp2y x y --
-  /bezierCurveTo 6 .gcall
+/.bezierCurveTo { % cp1x cp1y cp2x cp2y x y --
+  (bezierCurveTo) 6 .gcall0
 } def
 
 /.arcTo { % x1 y1 x2 y2 radius --
-  /arcTo 5 .gcall
+  (arcTo) 5 .gcall0
 } def
 
-/rect { % x y w h --
-  /rect 4 .gcall
+/.rect { % x y w h --
+  (rect) 4 .gcall0
 } def
 
 /arc { % x y radius startAngle endAngle anticlockwise --
-  /arc 6 .gcall
+  (arc) 6 .gcall0
 } def
 
 /fill { % --
-  /fill 0 .gcall
+  (fill) 0 .gcall0
 } def
 
 /stroke { % --
-  /stroke 0 .gcall
+  (stroke) 0 .gcall0
 } def
 
 /clip { % --
-  /clip 0 .gcall
+  (clip) 0 .gcall0
 } def
 
-/isPointInPath { % x y -- boolean
-  /isPointInPath 2 .gcall
+/.isPointInPath { % x y -- boolean
+  (isPointInPath) 2 .gcall1
 } def
 
-/fillText { % text x y maxWidth --
-  /fillText 4 .gcall
+/.fillText { % text x y maxWidth --
+  (fillText) 4 .gcall0
 } def
 
-/strokeText { % text x y maxWidth --
-  /strokeText 4 .gcall
+/.strokeText { % text x y maxWidth --
+  (strokeText) 4 .gcall0
 } def
 
-/measureText { % text -- TextMetrics
-  /measureText 1 .gcall
+/.measureText { % text -- TextMetrics
+  (measureText) 1 .gcall1
 } def
 
-/drawImage1 { % image dx dy dw dh --
-  /drawImage1 5 .gcall
+/.drawImage1 { % image dx dy dw dh --
+  (drawImage1) 5 .gcall0
 } def
 
-/drawImage2 { % image sx sy sw sh dx dy dw dh --
-  /drawImage2 9 .gcall
+/.drawImage2 { % image sx sy sw sh dx dy dw dh --
+  (drawImage2) 9 .gcall0
 } def
 
-/createImageData1 { % imagedata -- ImageData
-  /createImageData1 1 .gcall
+/.createImageData1 { % imagedata -- ImageData
+  (createImageData1) 1 .gcall1
 } def
 
-/createImageData2 { % sw sh -- ImageData
-  /createImageData2 2 .gcall
+/.createImageData2 { % sw sh -- ImageData
+  (createImageData2) 2 .gcall1
 } def
 
-/getImageData { % sx sy sw sh --
-  /getImageData 4 .gcall
+/.getImageData { % sx sy sw sh --
+  (getImageData) 4 .gcall1
 } def
 
-/putImageData { % imagedata dx dy dirtyX dirtyY dirtyWidth dirtyHeight --
-  /putImageData 7 .gcall
+/.putImageData { % imagedata dx dy dirtyX dirtyY dirtyWidth dirtyHeight --
+  (putImageData) 7 .gcall0
 } def
 
-/getGlobalAlpha              {/globalAlpha .gget} def
-/getGlobalCompositeOperation {/globalCompositeOperation .gget} def % TODO str
-/getStrokeStyle              {/strokeStyle .gget} def % TODO str
-/getFillStyle                {/fillStyle .gget} def % TODO str
-/.getLineWidth               {/lineWidth .gget} def
-/.getLineCap                 {/lineCap .gget} def % TODO str
-/.getLineJoin                {/lineJoin .gget} def % TODO str
-/.getMiterLimit              {/miterLimit .gget} def
-/getShadowOffsetX            {/shadowOffsetX .gget} def
-/getShadowOffsetY            {/shadowOffsetY .gget} def
-/getShadowBlur               {/shadowBlur .gget} def
-/getShadowColor              {/shadowColor .gget} def % TODO str
-/.getFont                    {/font .gget} def % TODO str
-/getTextAlign                {/textAlign .gget} def % TODO str
-/getTextBaseline             {/textBaseline .gget} def % TODO str
+/.getGlobalAlpha              {(globalAlpha) .gget} def
+/.getGlobalCompositeOperation {(globalCompositeOperation) .gget} def
+/.getStrokeStyle              {(strokeStyle) .gget} def
+/.getFillStyle                {(fillStyle) .gget} def
+/.getLineWidth                {(lineWidth) .gget} def
+/.getLineCap                  {(lineCap) .gget} def
+/.getLineJoin                 {(lineJoin) .gget} def
+/.getMiterLimit               {(miterLimit) .gget} def
+/.getShadowOffsetX            {(shadowOffsetX) .gget} def
+/.getShadowOffsetY            {(shadowOffsetY) .gget} def
+/.getShadowBlur               {(shadowBlur) .gget} def
+/.getShadowColor              {(shadowColor) .gget} def
+/.getFont                     {(font) .gget} def
+/.getTextAlign                {(textAlign) .gget} def
+/.getTextBaseline             {(textBaseline) .gget} def
 
-/setGlobalAlpha              {/globalAlpha .gput} def
-/setGlobalCompositeOperation {/globalCompositeOperation .gput} def % TODO str
-/setStrokeStyle              {/strokeStyle .gput} def % TODO str
-/setFillStyle                {/fillStyle .gput} def % TODO str
-/.setLineWidth               {/lineWidth .gput} def
-/.setLineCap                 {/lineCap .gput} def % TODO str
-/.setLineJoin                {/lineJoin .gput} def % TODO str
-/.setMiterLimit              {/miterLimit .gput} def
-/setShadowOffsetX            {/shadowOffsetX .gput} def
-/setShadowOffsetY            {/shadowOffsetY .gput} def
-/setShadowBlur               {/shadowBlur .gput} def
-/setShadowColor              {/shadowColor .gput} def % TODO str
-/.setFont                    {/font .gput} def % TODO str
-/setTextAlign                {/textAlign .gput} def % TODO str
-/setTextBaseline             {/textBaseline .gput} def % TODO str
+/.setGlobalAlpha              {(globalAlpha) .gput} def
+/.setGlobalCompositeOperation {(globalCompositeOperation) .gput} def
+/.setStrokeStyle              {(strokeStyle) .gput} def
+/.setFillStyle                {(fillStyle) .gput} def
+/.setLineWidth                {(lineWidth) .gput} def
+/.setLineCap                  {(lineCap) .gput} def
+/.setLineJoin                 {(lineJoin) .gput} def
+/.setMiterLimit               {(miterLimit) .gput} def
+/.setShadowOffsetX            {(shadowOffsetX) .gput} def
+/.setShadowOffsetY            {(shadowOffsetY) .gput} def
+/.setShadowBlur               {(shadowBlur) .gput} def
+/.setShadowColor              {(shadowColor) .gput} def
+/.setFont                     {(font) .gput} def
+/.setTextAlign                {(textAlign) .gput} def
+/.setTextBaseline             {(textBaseline) .gput} def
 
-%% PostScript operators
+%% PostScript
+
+% TODO track state, e.g. origin x y
 
 /gsave     {.save} def
 /grestore  {.restore} def
@@ -251,112 +285,105 @@
 
 /setgray { % gray --
   255 mul dup dup
-  rgb setFillStyle
+  .rgb .setFillStyle
 } def
 
 /setrgbcolor { % r g b --
   3 {255 * 3 1 roll} repeat
-  rgb setFillStyle
+  .rgb .setFillStyle
 } def
 
 /setfont { % font --
   % TODO C.font = N + "pt " + F.V;
 } def
 
-%    F["save"] = function() {S.push(true);};
-%    F["restore"] = function() {S.push(true);};
-%    F["bind"] = function() {};
-%    F["dict"] = function() {};
-%    F["load"] = function() {};
-%    F["begin"] = function() {};
-%    F["end"] = function() {};
-%    F["where"] = function() {};
-%    F["currentflat"] = function() {};
-%    F["setflat"] = function() {};
-%    F["_"] = function() {};
-%    F["clippath"] = function() {};
-
-%% PDF operators
-
-/w {
-  setlinewidth
-} def
-
-/J {
-  setlinecap
-} def
-
-/j {
-  setlinejoin
-} def
-
-/M {
-  setmitterlimit
-} def
-
-/q {gsave} def
-/Q {grestore} def
-
-/cm {
-  transform
+/clippath { % --
+  % TODO
 } def
 
-/m {
-  newpath % TODO only if not m previously
-  moveto
+/show { % string --
+  % TODO
+  %0 exch 0 exch .fillText
+  .fillText
 } def
 
-/l {
+/rlineto { % x y --
+  % TODO
   lineto
 } def
 
-/c {
-  bezierCurveTo
-} def
-
-/h {closepath} def
-
-/re {
-  rect
-} def
-
-/S  {stroke} def
-/s  {h S} def
-/f  {fill} def
-/F  {fill} def
-/B  {f S} def
-/B* {f* S} def
-/b  {h B} def
-/b* {h B*} def
-/W  {clip} def
-
-/Tf {
-  setfont
-} def
-
-/Tj {
-  fillText
-} def
-
-/rg {
-  % TODO other color spaces
-  3 {255 * 3 1 roll} repeat
-  rgb setFillStyle
-} def
-
-%% other operators
-
-/pi 3.141592653589 def
-
-/inch { % num --
-  72 mul
-} def
-
-%/black   {0 0 0 setrgbcolor} def
-%/red     {1 0 0 setrgbcolor} def
-%/green   {0 1 0 setrgbcolor} def
-%/blue    {0 0 1 setrgbcolor} def
-%/yellow  {1 1 0 setrgbcolor} def
-%/cyan    {0 1 1 setrgbcolor} def
-%/magenta {1 0 1 setrgbcolor} def
-%/white   {1 1 1 setrgbcolor} def
+%% PDF
+
+/w   {setlinewidth} def
+/J   {setlinecap} def % TODO
+/j   {setlinejoin} def % TODO
+/M   {setmitterlimit} def
+/d   {setdash} def % TODO
+/ri  {} def % TODO
+/i   {} def % TODO
+/gs  {} def % TODO
+/q   {gsave} def
+/Q   {grestore} def
+/cm  {.transform} def
+/m   {newpath moveto} def % TODO only if not m previously
+/l   {lineto} def
+/c   {.bezierCurveTo} def
+/v   {currentpoint cp2 p3 c} def % TODO fix arg order
+/y   {cp1 p3 p3 c} def % TODO fix arg order
+/h   {closepath} def % TODO
+/re  {.rect} def % TODO really, or x y m , x+w y l , x+w y+h l , x y+h l , h
+/S   {stroke} def
+/s   {h S} def
+/f   {fill} def % TODO
+/F   {f} def
+/f*  {} def % TODO
+/B   {f S} def
+/B*  {f* S} def
+/b   {h B} def
+/b*  {h B*} def
+/n   {} def % TODO
+/W   {clip} def % TODO
+/W*  {clip} def % TODO
+/BT  {} def % TODO
+/ET  {} def % TODO
+/Tc  {} def % TODO
+/Tw  {} def % TODO
+/Tz  {} def % TODO
+/TL  {} def % TODO
+/Tf  {setfont} def % TODO
+/Tr  {} def % TODO
+/Ts  {} def % TODO
+/Td  {} def % TODO
+/TD  {} def % TODO
+/Tm  {} def % TODO
+/T*  {} def % TODO
+/Tj  {show} def % TODO
+/TJ  {} def % TODO
+%/'   {} def % TODO
+%/"   {} def % TODO
+/d0  {} def % TODO
+/d1  {} def % TODO
+/CS  {} def % TODO
+/cs  {} def % TODO
+/SC  {} def % TODO
+/SCN {} def % TODO
+/sc  {} def % TODO
+/scn {} def % TODO
+/G   {} def % TODO
+/g   {} def % TODO
+/RG  {} def % TODO
+/rg  {3 {255 * 3 1 roll} repeat .rgb .setFillStyle} def % TODO
+/K   {} def % TODO
+/k   {} def % TODO
+/sh  {} def % TODO
+/BI  {} def % TODO
+/ID  {} def % TODO
+/EI  {} def % TODO
+/Do  {} def % TODO
+/MP  {} def % TODO
+/DP  {} def % TODO
+/BMC {} def % TODO
+/BDC {} def % TODO
+/EMC {} def % TODO
+/BX  {} def % TODO
+/EX  {} def % TODO