commit b9d59e1774d94fa691cdb8921e1d97c1634f1ce4
parent 816e5bef74761f547024a8e25ce1b3f0387d97ee
Author: tomas <tomas@logand.com>
Date: Sat, 23 Jan 2010 14:27:13 +0100
Changes from 2009-06-25
Diffstat:
M | wps.js | | | 444 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
M | wps.wps | | | 156 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- |
2 files changed, 415 insertions(+), 185 deletions(-)
diff --git a/wps.js b/wps.js
@@ -1,27 +1,49 @@
+// TODO one run, exec function or name !quoted
+
+function isQuoted(V) {
+ return V.q;
+}
+
+function quote(V) {
+ V.q = true;
+ return V;
+}
+
+function unquote(V) {
+ delete V.q;
+ return V;
+}
+
function Symbol(N) {
- if("/" == N[0]) {
- this.nm = N.substring(1);
- this.q = true;
- } else this.nm = N;
+ this.nm = N;
return this;
}
function isSymbol(V) {
- return V && V.constructor == Symbol;
-}
-
-function isQuoted(V) {
- return V.q;
+ return V && V.constructor === Symbol;
}
function symbolName(V) {
return V.nm;
}
-function ps0(L, F, S) {
+function isArray(V) {
+ return V && V.constructor === Array;
+}
+
+function inDs(Ds, K) {
+ for(var I = Ds.length - 1; 0 <= I; --I) {
+ if("undefined" != typeof Ds[I][K])
+ return Ds[I];
+ }
+ return false;
+}
+
+function ps0(L, Os, Ds) { // TODO Nd name dict name=>sym?
var N = L.length;
var I = 0;
+ // TODO white space ffeed + null???
function member(C, L) {return 0 <= L.indexOf(C);}
function peek() {return I < N && L[I];}
function xchar() {return I < N && L[I++];}
@@ -35,7 +57,9 @@ function ps0(L, F, S) {
}
}
- function text() { // TODO hex text in <>
+ function text() {
+ // TODO hex text in <>
+ // TODO ASCII base-85 <~ and ~>
xchar();
var L = [];
var N = 1;
@@ -58,6 +82,7 @@ function ps0(L, F, S) {
case "n": C = "\n"; break;
case "r": C = "\r"; break;
case "t": C = "\t"; break;
+ // TODO \n (ignore \n) \b \f \ddd octal
default:
C = false;
}
@@ -69,11 +94,14 @@ function ps0(L, F, S) {
}
function symbol() {
+ // TODO 1e10 1E-5 real numbers
+ // TODO radix numbers 8#1777 16#FFFE 2#1000
var C = xchar();
+ if(member(C, "()<>/% \t\n")) throw "Symbol expected";
var N = member(C, "+-0123456789.");
var F = "." == C;
var L = [C];
- while(peek() && !member(peek(), "%/[]{}<>( \t\n")) {
+ while(peek() && !member(peek(), "()<>[]{}/% \t\n")) {
C = xchar();
L.push(C);
if(N && !member(C, "0123456789")) {
@@ -86,228 +114,310 @@ function ps0(L, F, S) {
return N ? (F ? parseFloat(L) : parseInt(L, 10)) : new Symbol(L);
}
- function proc() {
- xchar();
- var L = [];
- while(peek()) {
- var T = token();
- if("}" == T) break;
- if(T || T == 0) L.push(T);
- }
- return L;
- }
+ var D = 0;
function token() {
skip();
- switch(peek()) { // TODO read dict in <<>>
+ 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 new Symbol(xchar());
+ case "]": return new Symbol(xchar());
+ case "{": D++; return new Symbol(xchar());
+ case "}": D--; return new Symbol(xchar());
+ case "/": xchar(); var X = symbol(); return quote(X);
case "(": return text();
default: return symbol();
}
}
- function parse(E) {
- var G = true;
- while(G && peek()) {
+// var Es = [];
+
+ function exec() {
+ var X = Os.pop();
+ if(isSymbol(X) && !isQuoted(X)) { // executable name
+ var K = symbolName(X);
+ var D = inDs(Ds, K);
+ var V = D && D[K];
+ if(V) {
+ Os.push(V);
+ exec();
+// Es.push(V);
+// if("function" == typeof V) V();
+// //else Os.push(V);
+// else run(V);
+ } else throw "Unknown operator 1 '" + K + "'";
+ } else if(isArray(X) && isQuoted(X)) { // proc
+ var M = X.length;
+ for(var I = 0; I < M; I++) {
+ //Es.push(X[I]);
+ Os.push(X[I]);
+ exec();
+ }
+ } else if("function" == typeof X) X(); // operator
+ else Os.push(X);
+ }
+
+// function run(T) {
+// if(T || T == 0) {
+// // if(isSymbol(T) && !isQuoted(T)) {
+// // var K = symbolName(T);
+// // var D = inDs(Ds, K);
+// // var V = D && D[K];
+// // if(V) {
+// // if("function" == typeof V) V();
+// // //else Os.push(V);
+// // else run(V);
+// // } else throw "Unknown operator 1 '" + K + "'";
+// // } else Os.push(T);
+// }
+// }
+
+ function parse() {
+ while(peek()) {
var T = token();
if(T || T == 0) {
- if(isSymbol(T) && !isQuoted(T)) {
- var X = symbolName(T);
- if(F[X]) F[X]();
- else throw "Unknown operator '" + X + "'";
- if(E == X) G = false;
- } else S.push(T);
+ Os.push(T);
+ if(D <= 0 || 1 == D && isSymbol(T) && "{" == symbolName(T))
+ exec();
}
}
- return S;
+ return Os;
}
return parse();
}
function wps(E, T) {
- var S = [];
- var F = {};
- var C = E.getContext("2d");
+ var Os = [];
+ var Sd = {};
+ var Ds = [Sd];
// trivial
- F["true"] = function() {S.push(true);};
- F["false"] = function() {S.push(false);};
- F["null"] = function() {S.push(null);};
+ Sd[".true"] = function() {Os.push(true);};
+ Sd[".false"] = function() {Os.push(false);};
+ Sd[".null"] = function() {Os.push(null);};
+
+ Sd["cvx"] = function() {
+ var X = Os.pop();
+ if(isSymbol(X) && isQuoted(X)) Os.push(unquote(X)); // executable name
+ else if(isArray(X) && !isQuoted(X)) Os.push(quote(X)); // proc
+ // TODO string -> parse
+ else Os.push(X);
+ };
// math
- F["neg"] = function() {S.push(-1 * 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["mod"] = function() {var X = S.pop();S.push(S.pop() % X);};
-
- // stack
- F["exch"] = function() {
- var Y = S.pop();
- var X = S.pop();
- S.push(Y);
- S.push(X);
+ Sd["neg"] = function() {Os.push(-1 * Os.pop());};
+ Sd["add"] = function() {Os.push(Os.pop() + Os.pop());};
+ Sd["mul"] = function() {Os.push(Os.pop() * Os.pop());};
+ Sd["div"] = function() {var X = Os.pop(); Os.push(Os.pop() / X);};
+ Sd["mod"] = function() {var X = Os.pop(); Os.push(Os.pop() % X);};
+
+ // stack and array
+ var M = {};
+ Sd["mark"] = function() {Os.push(M);};
+ Sd["counttomark"] = function() {
+ var N = 0;
+ for(var I = Os.length - 1; 0 <= I; I--)
+ if(M === Os[I]) return N;
+ else N++;
+ throw "Mark not found";
};
- 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["index"] = function() {S.push(S[S.pop()]);}; // TODO from other end!!!
- F["roll"] = function() {
- var J = S.pop();
- var N = S.pop();
+ Sd["exch"] = function() {
+ var Y = Os.pop();
+ var X = Os.pop();
+ Os.push(Y);
+ Os.push(X);
+ };
+ Sd["clear"] = function() {Os.length = 0;};
+ Sd["pop"] = function() {Os.pop();};
+ Sd["index"] = function() {
+ Os.push(Os[Os.length - 2 - Os.pop()]);
+ };
+ Sd["roll"] = function() {
+ var J = Os.pop();
+ var N = Os.pop();
var X = [];
var Y = [];
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());
+ if(I < J) X.unshift(Os.pop());
+ else Y.unshift(Os.pop());
+ for(I = 0; I < J; I++) Os.push(X.shift());
+ for(I = 0; I < N - J; I++) Os.push(Y.shift());
};
- F["copy"] = function() {
- var N = S.pop();
+ Sd["copy"] = function() {
+ var N = Os.pop();
+ if("object" == typeof N) {
+ var X = Os.pop();
+ for(var I in X)
+ N[I]=X[i];
+ } else {
+ var X = Os.length - N;
+ for(var I = 0; I < N; I++)
+ Os.push(X + I);
+ }
+ };
+
+ Sd["length"] = function() {Os.push(Os.pop().length);};
+ Sd["astore"] = function() {
+ var A = Os.pop();
+ var N = A.length;
+ var X = Os.length - N;
for(var I = 0; I < N; I++)
- S.push(S[N - 1]); // TODO from other end!!!
+ A[I] = Os[X + I];
};
- F["eq"] = 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);};
+ Sd["eq"] = function() {var Y = Os.pop(); var X = Os.pop(); Os.push(X == Y);};
+ Sd["lt"] = function() {var Y = Os.pop(); var X = Os.pop(); Os.push(X < Y);};
- //F["not"] = function() {var X = S.pop(); S.push(X == undefined || X == false);};
- //F[".nand"] = function() {S.push(F["not"]() || F["not"]());};
+ //Sd["not"] = function() {var X = Os.pop(); Os.push(X == undefined || X == false);};
+ //Sd[".nand"] = function() {Os.push(Sd["not"]() || Sd["not"]());};
- F["ifelse"] = function() {
- var N = S.pop();
- var P = S.pop();
- var C = S.pop();
+ Sd["ifelse"] = function() {
+ var N = Os.pop();
+ var P = Os.pop();
+ var C = Os.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();
+ Sd["for"] = function() {
+ var B = Os.pop();
+ var L = Os.pop();
+ var K = Os.pop();
+ var J = Os.pop();
if(K < 0) {
for(var I = J; L <= I; I += K) {
- S.push(I);
+ Os.push(I);
run(B);
}
} else {
for(var I = J; I <= L; I += K) {
- S.push(I);
+ Os.push(I);
run(B);
}
}
};
- F["."] = function() {alert(S.pop());};
- F["pstack"] = function() {alert(S);};
-
- function run(C) {
- if(!C.length) S.push(C);
- else {
- var M = C.length;
- for(var I = 0; I < M; I++) {
- var T = C[I];
- if(isSymbol(T) && !isQuoted(T)) {
- var X = symbolName(T);
- if(F[X]) F[X]();
- else throw "Unknown operator '" + X + "'";
- } else S.push(T);
- }
- }
- }
-
- F["get"] = function() { // dict key -- any
- var K = S.pop();
- var D = S.pop();
+ Sd["="] = function() {alert(Os.pop());};
+ Sd["=="] = function() {alert(Os.pop());}; // TODO
+ Sd["stack"] = function() {alert(Os);}; // TODO
+ Sd["pstack"] = function() {alert(Os);}; // TODO
+
+// function run1(T) {
+// if(T || T == 0) {
+// if(isSymbol(T) && !isQuoted(T)) {
+// var K = symbolName(T);
+// var D = inDs(Ds, K);
+// var V = D && D[K];
+// if(V) {
+// if("function" == typeof V) V();
+// //else Os.push(V);
+// else run(V);
+// } else throw "Unknown operator 1 '" + K + "'";
+// } else Os.push(T);
+// }
+// }
+
+// function run(C) {
+// if(!C.length) Os.push(C); // TODO run?
+// else {
+// var M = C.length;
+// for(var I = 0; I < M; I++) {
+// var T = C[I];
+// run1(T);
+// // if(isSymbol(T) && !isQuoted(T)) {
+// // var X = symbolName(T);
+// // if(Sd[X]) Sd[X]();
+// // else throw "Missing operator '" + X + "'";
+// // } else Os.push(T);
+// }
+// }
+// }
+
+ Sd["dict"] = function() {Os.pop(); Os.push({});};
+ Sd["get"] = function() { // dict key -- any
+ var K = Os.pop();
+ var D = Os.pop();
// TODO other datatypes http://www.capcode.de/help/get
- S.push(D[K]);
+ if(isSymbol(K)) Os.push(D[symbolName(K)]);
+ else Os.push(D[K]);
};
- F["put"] = function() { // dict key any --
- var V = S.pop();
- var K = S.pop();
- var D = S.pop();
+ Sd["put"] = function() { // dict key any --
+ var V = Os.pop();
+ var K = Os.pop();
+ var D = Os.pop();
// TODO other datatypes http://www.capcode.de/help/put
- D[K] = V;
+ if(isSymbol(K)) D[symbolName(K)] = V;
+ else D[K] = V;
};
-
- F["def"] = function() {
- var C = S.pop();
- var N = S.pop();
- if(isSymbol(N) && isQuoted(N)) F[symbolName(N)] = function() {run(C);};
- else throw "Wrong operator name '" + N + "' as '" + typeof N
- + "' for '" + C + "'";
+ Sd["begin"] = function() {Ds.push(Os.pop());};
+ Sd["end"] = function() {Ds.pop();};
+ Sd["currentdict"] = function() {Os.push(Ds[Ds.length - 1]);};
+ Sd["where"] = function() {
+ var K = Os.pop();
+ var D = inDs(Ds, K);
+ if(D) {
+ Os.push(D);
+ Os.push(true);
+ } else Os.push(false);
};
+// Sd["def"] = function() {
+// var C = Os.pop();
+// var N = Os.pop();
+// if(isSymbol(N) && isQuoted(N)) Sd[symbolName(N)] = function() {run(C);};
+// else throw "Wrong operator name '" + N + "' as '" + typeof N
+// + "' for '" + C + "'";
+// };
+
+ Sd["array"] = function() {Os.push(new Array(Os.pop()));};
+
+ Sd["restore"] = function() {Os.pop();}; // TODO
+ Sd["save"] = function() {Os.push([]);}; // TODO
+
+ Sd["bind"] = function() {}; // TODO
+ Sd["load"] = function() {}; // TODO
+
+ //////////////////////////////////////////////////////////
+
// js ffi operators
- F[".call"] = function() { // dict key nargs -- result
- var N = S.pop();
- var K = S.pop();
- var D = S.pop();
+ Sd[".call"] = function() { // dict key nargs -- result
+ var N = Os.pop();
+ var K = Os.pop();
+ var D = Os.pop();
var X = [];
- for(var I = 0; I < N; I++) X.unshift(S.pop());
- S.push(D[K].apply(D, X));
+ for(var I = 0; I < N; I++) X.unshift(Os.pop());
+ Os.push(D[K].apply(D, X));
};
-
- F[".gc"] = function() { // -- gc
- S.push(C);
+ Sd[".math"] = function() { // -- Math
+ Os.push(Math);
};
- F[".math"] = function() { // -- Math
- S.push(Math);
+ Sd[".gc"] = function() { // -- gc
+ Os.push(E.getContext("2d"));
};
+ /////////////////////////////////////////////////////
+
// html5 utility operators
// TODO js ffi to manipulate strings so the following can be in ps
- F[".rgb"] = function() {
- var B = S.pop();
- var G = S.pop();
- var R = S.pop();
- S.push("rgb(" + R + "," + G + "," + B + ")");
+ Sd[".rgb"] = function() {
+ var B = Os.pop();
+ var G = Os.pop();
+ var R = Os.pop();
+ Os.push("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("rgba(" + R + "," + G + "," + B + "," + A + ")");
+ Sd[".rgba"] = function() {
+ var A = Os.pop();
+ var B = Os.pop();
+ var G = Os.pop();
+ var R = Os.pop();
+ Os.push("rgba(" + R + "," + G + "," + B + "," + A + ")");
};
- // "junk" for tiger.eps
-
- 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() {S.push(0);};
- //F["setflat"] = function() {};
- //F["clippath"] = function() {};
- F["transform"] = function() {};
- //F["itransform"] = function() {};
- //F["currentpoint"] = function() {S.push(0); S.push(0);};
- F["*"] = function() {};
- //F["showpage"] = function() {};
-
if(T.length)
for(var I = 0; I < T.length; I++)
- ps0(T[I], F, S);
- else ps0(T, F, S);
+ ps0(T[I], Os, Ds);
+ else ps0(T, Os, Ds);
}
diff --git a/wps.wps b/wps.wps
@@ -1,5 +1,24 @@
%%% (c) 2009 Tomas Hlavaty
+currentdict/systemdict currentdict put
+
+systemdict/{/mark cvx put
+systemdict/[/mark cvx put
+
+systemdict/]
+/counttomark cvx
+/array cvx
+/astore cvx
+/exch cvx
+/pop cvx
+5 array astore cvx put
+
+systemdict/}/] cvx/cvx cvx 2 array astore cvx put
+
+%[1 2 3] =
+
+systemdict/def{currentdict 2 index 2 index put pop pop} put
+
%% math
/abs{.math(abs)1 .call}def
@@ -35,14 +54,25 @@
/sub{neg add}def
/idiv{div .floor}def
+%% stack
+
+/dup{0 index}def
+
%% conditionals
+/true .true def
+/false .false def
+/null .null def
+
/ne{eq not}def
/ge{lt not}def
/le{1 index 1 index eq 3 1 roll lt or}def
/gt{le not}def
/if{{}ifelse}def
+/loop{0 exch 0 exch 1 exch for}def
+/repeat{1 1 4 2 roll for}def
+
%% html5
/.gget{.gc exch get}def
@@ -55,13 +85,11 @@
%% canvas
-% TODO track state, e.g. origin x y
-
/.save{(save)0 .gcall0}def
/.restore{(restore)0 .gcall0}def
-/scale{(scale)2 .gcall0}def
-/rotate{(rotate)1 .gcall0}def
-/translate{(translate)2 .gcall0}def
+/.scale{(scale)2 .gcall0}def
+/.rotate{(rotate)1 .gcall0}def
+/.translate{(translate)2 .gcall0}def
/.transform{(transform)6 .gcall0}def
/.setTransform{(setTransform)6 .gcall0}def
/.createLinearGradient{(createLinearGradient)4 .gcall1}def
@@ -78,10 +106,10 @@
/.bezierCurveTo{(bezierCurveTo)6 .gcall0}def
/.arcTo{(arcTo)5 .gcall0}def
/.rect{(rect)4 .gcall0}def
-/arc{(arc)6 .gcall0}def
-/fill{(fill)0 .gcall0}def
-/stroke{(stroke)0 .gcall0}def
-/clip{(clip)0 .gcall0}def
+/.arc{(arc)6 .gcall0}def
+/.fill{(fill)0 .gcall0}def
+/.stroke{(stroke)0 .gcall0}def
+/.clip{(clip)0 .gcall0}def
/.isPointInPath{(isPointInPath)2 .gcall1}def
/.fillText{(fillText)4 .gcall0}def
/.strokeText{(strokeText)4 .gcall0}def
@@ -127,6 +155,65 @@
%% PostScript
+/.deg2rad{.pi 180 div mul}def
+
+/identmatrix{pop [1 0 0 1 0 0]}def % TODO fill
+/matrix{6 array identmatrix}def
+
+/.cx 0 def
+/.cy 0 def
+/.px 0 def
+/.py 0 def
+/.tm0 matrix def
+/.tm matrix def
+/.tmd matrix def
+
+/.setPoint{/.cy exch def/.cx exch def}def
+/.setPath{/.py exch def/.px exch def}def
+
+/currentpoint{.cx .cy}def
+
+/setmatrix{/.tm exch def}def
+
+/..p{2 dict begin/y exch def/x exch def}def
+/..P{end}def
+/..tm{6 dict begin/ty exch def/tx exch def/d exch def/c exch def/b exch def/a exch def}def
+/..TM{end}def
+/.x{a x mul c y mul tx add add}def
+/.y{b x mul d y mul ty add add}def
+/.mmul{}def % TODO
+/.tmu{/.cx .x def/.cy .y def/.tmd .tmd}def % TODO
+%– initmatrix – Set CTM to device default
+%matrix defaultmatrix matrix Fill matrix with device default matrix
+%matrix currentmatrix matrix Fill matrix with CTM
+
+/translate{2 copy ..p 1 0 0 1 6 4 roll ..tm .tmu ..TM ..P .translate}def % TODO
+%tx ty matrix translate matrix Define translation by (tx , ty)
+
+%sx sy scale – Scale user space by sx and sy
+%sx sy matrix scale matrix Define scaling by sx and sy
+
+%angle rotate – Rotate user space by angle degrees
+%angle matrix rotate matrix Define rotation by angle degrees
+
+%matrix concat – Replace CTM by matrix ´ CTM
+%matrix1 matrix2 matrix3 concatmatrix matrix3 Fill matrix3 with matrix1 ´ matrix2
+
+/transform{..p .tm ..tm .x .y ..TM ..P}def % TODO
+%x y matrix transform x¢ y¢ Transform (x, y) by matrix
+
+%dx dy dtransform dx¢ dy¢ Transform distance (dx, dy) by CTM
+%dx dy matrix dtransform dx¢ dy¢ Transform distance (dx, dy) by matrix
+
+%x¢ y¢ itransform x y Perform inverse transform of (x¢, y¢) by CTM
+%x¢ y¢ matrix itransform x y Perform inverse transform of (x¢, y¢) by matrix
+
+%dx¢ dy¢ idtransform dx dy Perform inverse transform of distance (dx¢, dy¢) by CTM
+%dx¢ dy¢ matrix idtransform dx dy Perform inverse transform of distance (dx¢, dy¢) by matrix
+
+%matrix1 matrix2 invertmatrix matrix2 Fill matrix2 with inverse of matrix1
+
+
/gsave{.save}def
/grestore{.restore}def
/rectclip{.clipRect}def
@@ -134,22 +221,50 @@
/rectstroke{.strokeRect}def
/newpath{.beginPath}def
/closepath{.closePath}def
-/moveto{.moveTo}def
-/lineto{.lineTo}def
+/moveto{2 copy .setPoint 2 copy .setPath .moveTo/.tm0 matrix def}def
+/lineto{2 copy .setPoint 2 copy .setPath .lineTo/.tm0 matrix def}def
/arcto{.arcTo}def
/setlinewidth{.setLineWidth}def
-/setlinecap{.setLineCap}def
-/setlinejoin{.setLineJoin}def
+/setlinecap{.setLineCap}def % TODO
+/setlinejoin{.setLineJoin}def % TODO
/setmiterlimit{.setMiterLimit}def
-/setgray{255 mul dup dup .rgb .setFillStyle}def
-/setrgbcolor{3{255 * 3 1 roll} repeat .rgb .setFillStyle}def
+/currentlinewidth{.getLineWidth}def
+/currentlinecap{<</butt 0/round 1/square 2>> .getLineCap get}def
+/currentlinejoin{<</miter 0/round 1/bevel 2>> .getLineJoin get}def
+/currentmiterlimit{.getMiterLimit}def
+
+/setgray{255 mul dup dup .rgb dup .setStrokeStyle .setFillStyle}def
+/setrgbcolor{3{255 mul 3 1 roll} repeat .rgb dup .setStrokeStyle .setFillStyle}def
/setfont{} def % TODO C.font = N + "pt " + F.V;
-/clippath{}def % TODO
-/show{.fillText}def % TODO 0 exch 0 exch .fillText
+/clippath{0 0 .gcanvas(width)get .gcanvas(height)get .rect}def % TODO
+/show{currentpoint 3 2 roll .fillText .strokeText}def % TODO
/rlineto{lineto}def % TODO
+/currentflat{42}def
+/setflat{pop}def
+
+/transform{}def % TODO
+/itransform{}def % TODO
+
+/currentpoint{0 0}def % TODO
+
+/showpage{}def
+
+/arc{.deg2rad exch .deg2rad exch true(arc)6 .gcall0}def % TODO currentpoint
+/arcn{.deg2rad exch .deg2rad exch false(arc)6 .gcall0}def % TODO currentpoint
+
+/fill{.fill newpath currentpoint moveto}def % TODO
+
+/setdash{pop pop}def
+
+/stroke{.stroke newpath currentpoint moveto}def
+
+/curveto{2 copy .setPoint .bezierCurveTo}def
+
+/grestoreall{}def % TODO
+
%% PDF
/w{setlinewidth}def
@@ -210,7 +325,7 @@
/G{}def % TODO
/g{}def % TODO
/RG{}def % TODO
-/rg{3{255 * 3 1 roll} repeat .rgb .setFillStyle}def % TODO
+/rg{3{255 mul 3 1 roll} repeat .rgb dup .setStrokeStyle .setFillStyle}def % TODO
/K{}def % TODO
/k{}def % TODO
/sh{}def % TODO
@@ -225,3 +340,8 @@
/EMC{}def % TODO
/BX{}def % TODO
/EX{}def % TODO
+
+%% finish
+
+/userdict 1000 dict def
+userdict begin