123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097 |
- MODULE OpenTypeInt; (** AUTHOR "eos, PL"; PURPOSE "Bluebottle port of OpenType"; *)
- CONST
- X* = 1; Y* = 0; (** indices for coordinates into Coord structure **)
- StackSize* = 8192;
- TYPE
- F26D6* = LONGINT; (** fixed point format 26.6 used for fractional pixel coordinates **)
- F2D14* = INTEGER; (** fixed point format 2.14 used for unit vectors **)
- FUnit* = INTEGER; (** unscaled point coordinates **)
- Fixed* = LONGINT; (** fixed point format 16.16 used for scalar fixed point numbers **)
- INT64 = ARRAY 8 OF CHAR; (* huge integers for extended precision arithmetic *)
- (** program code **)
- Code* = POINTER TO ARRAY OF CHAR;
- (** program stack **)
- Stack* = ARRAY StackSize OF LONGINT;
- (** addresses within code blocks **)
- Address* = RECORD
- code*: Code; (** instruction sequence **)
- len*: LONGINT; (** code length **)
- pc*: LONGINT; (** location within code **)
- END;
- (** user defined functions **)
- Functions* = POINTER TO ARRAY OF Address;
- (** user defined instructions **)
- Instruction* = RECORD
- beg*: Address; (* starting point *)
- opcode*: CHAR; (* instruction opcode *)
- END;
- Instructions* = POINTER TO ARRAY OF Instruction;
- (** call stack **)
- Frame* = RECORD
- ret*: Address; (* return address *)
- start*: LONGINT; (* starting pc of function (within context.code) *)
- count*: INTEGER; (* number of times the function has to be evaluated *)
- END;
- CallStack* = ARRAY 32 OF Frame;
- (** program store **)
- Store* = POINTER TO ARRAY OF LONGINT;
- (** control value table **)
- CVT* = POINTER TO ARRAY OF F26D6;
- (** glyph zone **)
- Contours* = POINTER TO ARRAY OF INTEGER;
- Coord* = ARRAY 2 OF F26D6;
- Point* = RECORD
- org*, cur*: Coord; (** original and current point coordinates **)
- onCurve*: BOOLEAN; (** is point on or off the curve? **)
- touched*: ARRAY 2 OF BOOLEAN; (** is point touched in x/y direction? **)
- END;
- Points* = POINTER TO ARRAY OF Point;
- Zone* = POINTER TO ZoneDesc;
- ZoneDesc* = RECORD
- contours*: INTEGER; (** number of contours in this zone **)
- first*: Contours; (** starting points of each contour; first[contours] contains total number of points in zone **)
- pt*: Points; (** points in this zone **)
- END;
- (** unit vector **)
- Vector* = RECORD
- x*, y*: F2D14;
- END;
- (** execution context **)
- Context* = RECORD
- code*: Code; (** program code **)
- codeLen*: LONGINT; (* code length *)
- stack*: Stack; (** program stack **)
- callStack*: CallStack; (** call stack of program **)
- pc*: LONGINT; (* current position within code *)
- tos*: INTEGER; (* stack pointer *)
- ctos*: INTEGER; (* call stack pointer *)
- func*: Functions; (** user defined functions **)
- instr*: Instructions; (** user defined instructions **)
- store*: Store; (** program store **)
- cvt*: CVT; (** control value table **)
- zone*: ARRAY 2 OF Zone; (** twilight and glyph zone **)
- ptsize*: F26D6; (** current point size **)
- xppm*, yppm*, ppm: F26D6; (** number of pixels per Em in x/y direction **)
- upm*: INTEGER; (** units per Em **)
- rotated*, stretched*: BOOLEAN; (* glyph transformation info *)
- xratio, yratio, ratio*: Fixed; (** aspect ratio **)
- minDist*: F26D6; (** feature preserving minimum distance **)
- cvtCutIn*: F26D6; (** control value table cut in **)
- swVal*, swCutIn*: F26D6; (** single width cut in and single width value **)
- deltaBase*, deltaShift*: INTEGER; (** delta exception parameters **)
- autoFlip*: BOOLEAN; (** whether to make CVT entries sign independent **)
- inhibitFit*, ignorePrep*: BOOLEAN; (** instruction control flags **)
- fixDropouts*: BOOLEAN; (** scan control flag **)
- scanType*: INTEGER; (** current scan type **)
- rp0*, rp1*, rp2*: INTEGER; (** reference points **)
- gep0*, gep1*, gep2*: INTEGER; (** zone indices **)
- zp0, zp1, zp2: Zone; (* zone pointers, equal to zone[gepN] *)
- free*, proj*, proj2*: Vector; (** freedom vector, projection vector, and dual projection vector **)
- period*, phase*, threshold*: F26D6; (** parameters of current round state **)
- loop*: INTEGER; (** number of times to execute the next loop-aware instruction **)
- END;
- (** static part of graphics state **)
- State* = RECORD
- minDist: F26D6;
- cvtCutIn: F26D6;
- swVal, swCutIn: F26D6;
- deltaBase, deltaShift: INTEGER;
- autoFlip: BOOLEAN;
- inhibitFit, ignorePrep: BOOLEAN;
- fixDropouts: BOOLEAN;
- scanType: INTEGER;
- END;
- (** debug upcalls **)
- NotifierData* = POINTER TO NotifierDesc;
- NotifierDesc* = RECORD END;
- Notifier* = PROCEDURE (VAR c: Context; data: NotifierData);
- Primitive = PROCEDURE (VAR c: Context);
- VAR
- EmptyZone*: Zone; (** zone containing zero contours and zero points **)
- Builtin: ARRAY 256 OF Primitive; (* instruction for each opcode *)
- Zero64: INT64;
- Notify: Notifier;
- NotifyData: NotifierData;
- (*--- 64bit Arithmetic ---*)
- PROCEDURE ToINT64 (x: LONGINT; VAR y: INT64);
- BEGIN
- y[0] := CHR(x MOD 100H);
- y[1] := CHR(ASH(x, -8) MOD 100H);
- y[2] := CHR(ASH(x, -16) MOD 100H);
- y[3] := CHR(ASH(x, -24) MOD 100H);
- y[4] := CHR(ASH(x, -31) MOD 100H);
- y[5] := y[4]; y[6] := y[4]; y[7] := y[4]
- END ToINT64;
- PROCEDURE FromINT64 (x: INT64; VAR y: LONGINT);
- BEGIN
- y := ASH(ORD(x[3]), 24) + ASH(ORD(x[2]), 16) + ASH(ORD(x[1]), 8) + ORD(x[0])
- END FromINT64;
- PROCEDURE AddINT64 (a, b: INT64; VAR c: INT64);
- VAR sum, i: LONGINT;
- BEGIN
- sum := 0;
- FOR i := 0 TO 7 DO
- sum := ORD(a[i]) + ORD(b[i]) + ASH(sum, -8) MOD 100H;
- c[i] := CHR(sum MOD 100H)
- END
- END AddINT64;
- PROCEDURE SubINT64 (a, b: INT64; VAR c: INT64);
- VAR sum, i: LONGINT;
- BEGIN
- sum := 256;
- FOR i := 0 TO 7 DO
- sum := 255 + ORD(a[i]) - ORD(b[i]) + ASH(sum, -8) MOD 100H;
- c[i] := CHR(sum MOD 100H)
- END
- END SubINT64;
- PROCEDURE LeqINT64 (a, b: INT64): BOOLEAN;
- VAR i: LONGINT;
- BEGIN
- IF (a[7] >= 80X) & (b[7] < 80X) THEN
- RETURN TRUE
- ELSIF (a[7] < 80X) & (b[7] >= 80X) THEN
- RETURN FALSE
- ELSE
- FOR i := 7 TO 0 BY -1 DO
- IF a[i] < b[i] THEN RETURN TRUE
- ELSIF a[i] > b[i] THEN RETURN FALSE
- END
- END;
- RETURN TRUE (* equal *)
- END
- END LeqINT64;
- PROCEDURE ShiftINT64 (VAR a: INT64; n: LONGINT);
- VAR c, i, j, b: LONGINT;
- BEGIN
- c := 0;
- IF n > 0 THEN
- n := n MOD 64;
- i := 7; j := 7 - n DIV 8; n := n MOD 8;
- c := ASH(ORD(a[j]), n) MOD 100H;
- WHILE j > 0 DO
- DEC(j); b := ORD(a[j]);
- a[i] := CHR(c + ASH(b, n-8)); DEC(i);
- c := ASH(b, n) MOD 100H
- END;
- WHILE i >= 0 DO
- a[i] := CHR(c); c := 0; DEC(i)
- END
- ELSIF n < 0 THEN
- n := (-n) MOD 64;
- i := 0; j := n DIV 8; n := n MOD 8;
- c := ASH(ORD(a[j]), -n);
- WHILE j < 7 DO
- INC(j); b := ORD(a[j]);
- a[i] := CHR(c + ASH(b, 8-n) MOD 100H); INC(i);
- c := ASH(b, -n)
- END;
- WHILE i < 8 DO
- a[i] := CHR(c); c := ASH(c, -8); INC(i)
- END
- END
- END ShiftINT64;
- PROCEDURE MulINT64 (a, b: INT64; VAR c: INT64);
- VAR i, sum, j: LONGINT;
- BEGIN
- FOR i := 0 TO 7 DO c[i] := 0X END;
- FOR i := 0 TO 7 DO
- sum := 0;
- FOR j := 0 TO 7-i DO
- sum := LONG(ORD(a[i])) * LONG(ORD(b[j])) + ASH(sum, -8) MOD 100H + ORD(c[i+j]);
- c[i+j] := CHR(sum MOD 100H)
- END
- END
- END MulINT64;
- PROCEDURE DivINT64 (a, b: INT64; VAR q: INT64);
- VAR positive: BOOLEAN; i: LONGINT; e: INT64;
- BEGIN
- positive := TRUE;
- IF ~LeqINT64(Zero64, a) THEN positive := ~positive; SubINT64(Zero64, a, a) END;
- IF ~LeqINT64(Zero64, b) THEN positive := ~positive; SubINT64(Zero64, b, b) END;
- FOR i := 0 TO 7 DO q[i] := 0X; e[i] := 0X END; e[0] := 1X;
- ShiftINT64(b, 32);
- i := 0;
- REPEAT
- ShiftINT64(q, 1); ShiftINT64(b, -1);
- IF LeqINT64(b, a) THEN
- SubINT64(a, b, a); AddINT64(q, e, q)
- END;
- INC(i)
- UNTIL i = 32;
- IF ~positive THEN SubINT64(Zero64, q, q) END
- END DivINT64;
- (**--- Arithmetic ---**)
- PROCEDURE ShiftDiv* (a, n, d: LONGINT): LONGINT;
- VAR b, r: LONGINT; a64, d64, h64: INT64;
- BEGIN
- b := ASH(1, 31-n);
- IF (-b <= a) & (a < b) THEN
- r := (ASH(a, n) + d DIV 2) DIV d
- ELSE
- ToINT64(a, a64); ShiftINT64(a64, n);
- ToINT64(d, d64); h64 := d64; ShiftINT64(h64, -1);
- AddINT64(a64, h64, a64);
- DivINT64(a64, d64, a64);
- FromINT64(a64, r)
- END;
- RETURN r
- END ShiftDiv;
- PROCEDURE MulShift* (a, b, n: LONGINT): LONGINT;
- VAR a64, b64, c64: INT64; c: LONGINT;
- BEGIN
- IF (-10000H <= a) & (a < 10000H) & (-8000H <= b) & (b < 8000H) THEN
- RETURN ASH(a * b, n)
- ELSE
- ToINT64(a, a64); ToINT64(b, b64);
- MulINT64(a64, b64, c64); ShiftINT64(c64, n);
- FromINT64(c64, c);
- RETURN c
- END
- END MulShift;
- PROCEDURE MulDiv* (a, b, c: LONGINT): LONGINT;
- VAR a64, b64, m64, c64, d64: INT64; d: LONGINT;
- BEGIN
- IF (-10000H <= a) & (a < 10000H) & (-8000H <= b) & (b < 8000H) THEN
- IF c > 0 THEN
- RETURN (a * b + c DIV 2) DIV c
- ELSIF c < 0 THEN
- c := -c;
- RETURN -((a * b + c DIV 2) DIV c)
- ELSE
- RETURN 0; (* division by zero -- gracefully ignored ... *)
- HALT(100); (* a trap is an inacceptable behavior during system startup (e.g. if the font is too small ..) *)
- END
- ELSE
- ToINT64(a, a64); ToINT64(b, b64);
- MulINT64(a64, b64, m64);
- ToINT64(c, c64); DivINT64(m64, c64, d64);
- FromINT64(d64, d);
- RETURN d
- END
- END MulDiv;
- PROCEDURE Norm* (x, y: F26D6): F26D6;
- VAR n, r, b, t, i: LONGINT; x64, y64, n64, r64, b64, t64: INT64;
- BEGIN
- IF (-8000H <= x) & (x < 8000H) & (-8000H <= y) & (y < 8000H) THEN (* x*x + y*y representable in 32 bits *)
- n := x * x + y * y;
- r := 0; b := 40000000H;
- REPEAT
- t := r + b;
- IF t <= n THEN
- DEC(n, t);
- r := t + b
- END;
- r := r DIV 2; b := b DIV 4
- UNTIL b = 0
- ELSE
- ToINT64(x, x64); ToINT64(y, y64);
- MulINT64(x64, x64, x64); MulINT64(y64, y64, y64);
- AddINT64(x64, y64, n64);
- FOR i := 0 TO 7 DO r64[i] := 0X; b64[i] := 0X END; b64[7] := 40X;
- REPEAT
- AddINT64(r64, b64, t64);
- IF LeqINT64(t64, n64) THEN
- SubINT64(n64, t64, n64);
- AddINT64(t64, b64, r64)
- END;
- ShiftINT64(r64, -1); ShiftINT64(b64, -2);
- i := 0; WHILE (i < 8) & (b64[i] = 0X) DO INC(i) END
- UNTIL i = 8;
- FromINT64(r64, r)
- END;
- RETURN r
- END Norm;
- (*--- Auxiliary Routines ---*)
- PROCEDURE Ratio (VAR c: Context): Fixed;
- VAR x, y: Fixed;
- BEGIN
- IF c.ratio = 0 THEN
- IF c.proj.y = 0 THEN
- c.ratio := c.xratio
- ELSIF c.proj.x = 0 THEN
- c.ratio := c.yratio
- ELSE
- x := ASH(c.proj.x * c.xratio, -14);
- y := ASH(c.proj.y * c.yratio, -14);
- c.ratio := Norm(x, y)
- END
- END;
- RETURN c.ratio
- END Ratio;
- PROCEDURE PPEm (VAR c: Context): F26D6;
- BEGIN
- RETURN MulShift(c.ppm, Ratio(c), -16)
- END PPEm;
- PROCEDURE FUnitToPixel (fu: FUnit; VAR c: Context): F26D6;
- BEGIN
- RETURN (LONG(fu) * PPEm(c) + c.upm DIV 2) DIV c.upm
- END FUnitToPixel;
- PROCEDURE CVTValue (n: LONGINT; VAR c: Context): F26D6;
- VAR ratio: F26D6;
- BEGIN
- IF n < 0 THEN
- RETURN 0 (* some fonts use CVT[-1]; FreeType and TTI return 0, too *)
- ELSE
- ratio := Ratio(c);
- IF ratio = 10000H THEN RETURN c.cvt[n]
- ELSE RETURN MulShift(c.cvt[n], ratio, -16)
- END
- END
- END CVTValue;
- PROCEDURE Round (x, period, phase, threshold: F26D6): F26D6;
- VAR sign: F26D6;
- BEGIN
- sign := x; x := ABS(x);
- x := x - phase + threshold;
- x := x - x MOD period + phase;
- IF x < 0 THEN INC(x, period) END;
- IF sign < 0 THEN x := -x END;
- RETURN x
- END Round;
- PROCEDURE Project (crd: Coord; proj: Vector): F26D6;
- BEGIN
- RETURN MulShift(crd[X], proj.x, -14) + MulShift(crd[Y], proj.y, -14) (* dot product of point and unit vector *)
- END Project;
- PROCEDURE GetDistance (from, to: Coord; VAR dx, dy: F26D6);
- BEGIN
- dx := to[X] - from[X]; dy := to[Y] - from[Y]
- END GetDistance;
- PROCEDURE Move (VAR p: Point; free, proj: Vector; dist: F26D6);
- VAR dot: LONGINT;
- BEGIN
- IF proj.x = 4000H THEN
- IF free.x # 0 THEN
- INC(p.cur[X], dist); p.touched[X] := TRUE;
- IF free.x # 4000H THEN
- INC(p.cur[Y], MulDiv(free.y, dist, free.x)); p.touched[Y] := TRUE
- END
- END
- ELSIF proj.y = 4000H THEN
- IF free.y # 0 THEN
- INC(p.cur[Y], dist); p.touched[Y] := TRUE;
- IF free.y # 4000H THEN
- INC(p.cur[X], MulDiv(free.x, dist, free.y)); p.touched[X] := TRUE
- END
- END
- ELSE
- dot := LONG(proj.x) * LONG(free.x) + LONG(proj.y) * LONG(free.y);
- INC(p.cur[X], MulDiv(4000H*LONG(free.x), dist, dot)); p.touched[X] := TRUE;
- INC(p.cur[Y], MulDiv(4000H*LONG(free.y), dist, dot)); p.touched[Y] := TRUE
- END
- END Move;
- PROCEDURE GetRefDist (VAR c: Context; flag: BOOLEAN; VAR zone: Zone; VAR ref: LONGINT; VAR dx, dy: F26D6);
- VAR dot: LONGINT; dist: F26D6;
- BEGIN
- IF flag THEN (* rp1 in zp0 *)
- ref := c.rp1; zone := c.zp0
- ELSE (* use rp2 in zp1 *)
- ref := c.rp2; zone := c.zp1
- END;
- dist := Project(zone.pt[ref].cur, c.proj) - Project(zone.pt[ref].org, c.proj);
- dot := LONG(c.proj.x) * LONG(c.free.x) + LONG(c.proj.y) * LONG(c.free.y);
- IF dot # 0 THEN
- IF (c.free.x # 0) & (c.free.y # 0) THEN
- dx := MulDiv(c.free.x, dist, dot);
- dy := MulDiv(c.free.y, dist, dot)
- ELSIF c.free.x # 0 THEN
- dx := dist; dy := 0
- ELSIF c.free.y # 0 THEN
- dy := dist; dx := 0
- END
- ELSE
- dx := 0; dy := 0
- END
- END GetRefDist;
- (*--- Pushing Data onto the Interpreter Stack ---*)
- (* push n bytes *)
- PROCEDURE NPUSHB (VAR c: Context);
- VAR n: LONGINT;
- BEGIN
- INC(c.pc); n := ORD(c.code[c.pc]);
- WHILE n > 0 DO
- INC(c.pc); INC(c.tos); c.stack[c.tos] := ORD(c.code[c.pc]);
- DEC(n)
- END;
- INC(c.pc)
- END NPUSHB;
- (* push n words *)
- PROCEDURE NPUSHW (VAR c: Context);
- VAR n, hi, lo: LONGINT;
- BEGIN
- INC(c.pc); n := ORD(c.code[c.pc]);
- WHILE n > 0 DO
- INC(c.pc); hi := ORD(c.code[c.pc]);
- IF hi >= 128 THEN DEC(hi, 256) END;
- INC(c.pc); lo := ORD(c.code[c.pc]);
- INC(c.tos); c.stack[c.tos] := 256*hi + lo;
- DEC(n)
- END;
- INC(c.pc)
- END NPUSHW;
- (* push bytes *)
- PROCEDURE PUSHB (VAR c: Context);
- VAR n: LONGINT;
- BEGIN
- n := ORD(c.code[c.pc]) - 0B0H;
- WHILE n >= 0 DO
- INC(c.pc); INC(c.tos); c.stack[c.tos] := ORD(c.code[c.pc]);
- DEC(n)
- END;
- INC(c.pc)
- END PUSHB;
- (* push words *)
- PROCEDURE PUSHW (VAR c: Context);
- VAR n, hi, lo: LONGINT;
- BEGIN
- n := ORD(c.code[c.pc]) - 0B8H;
- WHILE n >= 0 DO
- INC(c.pc); hi := ORD(c.code[c.pc]);
- IF hi >= 128 THEN DEC(hi, 256) END;
- INC(c.pc); lo := ORD(c.code[c.pc]);
- INC(c.tos); c.stack[c.tos] := 256*hi + lo;
- DEC(n)
- END;
- INC(c.pc)
- END PUSHW;
- (*--- Managing the Storage Area ---*)
- (* read store *)
- PROCEDURE RS (VAR c: Context);
- BEGIN
- c.stack[c.tos] := c.store[c.stack[c.tos]]; INC(c.pc)
- END RS;
- (* write store *)
- PROCEDURE WS (VAR c: Context);
- VAR value: LONGINT;
- BEGIN
- value := c.stack[c.tos]; DEC(c.tos);
- c.store[c.stack[c.tos]] := value; DEC(c.tos);
- INC(c.pc)
- END WS;
- (*--- Managing the Control Value Table ---*)
- (* write control value table in pixels or FUnits *)
- PROCEDURE WCVT (VAR c: Context);
- VAR value: F26D6;
- BEGIN
- value := c.stack[c.tos]; DEC(c.tos);
- IF c.code[c.pc] = 70X THEN
- value := FUnitToPixel(SHORT(value), c)
- END;
- c.cvt[c.stack[c.tos]] := ShiftDiv(value, 16, Ratio(c)); DEC(c.tos);
- INC(c.pc)
- END WCVT;
- (* read control value table *)
- PROCEDURE RCVT (VAR c: Context);
- BEGIN
- c.stack[c.tos] := CVTValue(c.stack[c.tos], c); INC(c.pc)
- END RCVT;
- (*--- Managing the Graphics State ---*)
- (* set freedom and projection vectors to coordinate axis *)
- PROCEDURE SVTCA (VAR c: Context);
- BEGIN
- IF ODD(ORD(c.code[c.pc])) THEN (* set to x-axis *)
- c.proj.x := 4000H; c.proj.y := 0
- ELSE (* set to y-axis *)
- c.proj.x := 0; c.proj.y := 4000H
- END;
- c.free := c.proj; c.proj2 := c.proj;
- c.ratio := 0;
- INC(c.pc)
- END SVTCA;
- (* set projection vector to coordinate axis *)
- PROCEDURE SPVTCA (VAR c: Context);
- BEGIN
- IF ODD(ORD(c.code[c.pc])) THEN (* set to x-axis *)
- c.proj.x := 4000H; c.proj.y := 0
- ELSE (* set to y-axis *)
- c.proj.x := 0; c.proj.y := 4000H
- END;
- c.proj2 := c.proj;
- c.ratio := 0;
- INC(c.pc)
- END SPVTCA;
- (* set freedom vector to coordinate axis *)
- PROCEDURE SFVTCA (VAR c: Context);
- BEGIN
- IF ODD(ORD(c.code[c.pc])) THEN (* set to x-axis *)
- c.free.x := 4000H; c.free.y := 0
- ELSE (* set to y-axis *)
- c.free.x := 0; c.free.y := 4000H
- END;
- INC(c.pc)
- END SFVTCA;
- (* set projection vector to line *)
- PROCEDURE SPVTL (VAR c: Context);
- VAR p1, p2: LONGINT; dx, dy, d: F26D6;
- BEGIN
- p1 := c.stack[c.tos]; DEC(c.tos);
- p2 := c.stack[c.tos]; DEC(c.tos);
- GetDistance(c.zp2.pt[p1].cur, c.zp1.pt[p2].cur, dx, dy); (* note: TTI had zp1 and zp2 swapped *)
- d := Norm(dx, dy);
- IF d = 0 THEN
- dx := 0; dy := 0
- ELSE
- dx := ShiftDiv(dx, 14, d);
- dy := ShiftDiv(dy, 14, d)
- END;
- IF ODD(ORD(c.code[c.pc])) THEN (* rotate by 90 degrees *)
- c.proj.x := SHORT(-dy); c.proj.y := SHORT(dx)
- ELSE
- c.proj.x := SHORT(dx); c.proj.y := SHORT(dy)
- END;
- c.proj2 := c.proj;
- c.ratio := 0;
- INC(c.pc)
- END SPVTL;
- (* set freedom vector to line *)
- PROCEDURE SFVTL (VAR c: Context);
- VAR p1, p2: LONGINT; dx, dy, d: F26D6;
- BEGIN
- p1 := c.stack[c.tos]; DEC(c.tos);
- p2 := c.stack[c.tos]; DEC(c.tos);
- GetDistance(c.zp2.pt[p1].cur, c.zp1.pt[p2].cur, dx, dy); (* note: TTI had zp1 and zp2 swapped *)
- d := Norm(dx, dy);
- IF d = 0 THEN
- dx := 0; dy := 0
- ELSE
- dx := ShiftDiv(dx, 14, d);
- dy := ShiftDiv(dy, 14, d)
- END;
- IF ODD(ORD(c.code[c.pc])) THEN (* rotate by 90 degrees *)
- c.free.x := SHORT(-dy); c.free.y := SHORT(dx)
- ELSE
- c.free.x := SHORT(dx); c.free.y := SHORT(dy)
- END;
- INC(c.pc)
- END SFVTL;
- (* set freedom vector to projection vector *)
- PROCEDURE SFVTPV (VAR c: Context);
- BEGIN
- c.free := c.proj; INC(c.pc)
- END SFVTPV;
- (* set dual projection vector to line *)
- PROCEDURE SDPVTL (VAR c: Context);
- VAR p1, p2: LONGINT; dx, dy, d: F26D6;
- BEGIN
- p1 := c.stack[c.tos]; DEC(c.tos);
- p2 := c.stack[c.tos]; DEC(c.tos);
- GetDistance(c.zp2.pt[p1].org, c.zp1.pt[p2].org, dx, dy); (* note: TTI had zp1 and zp2 swapped *)
- d := Norm(dx, dy);
- dx := ShiftDiv(dx, 14, d);
- dy := ShiftDiv(dy, 14, d);
- IF ODD(ORD(c.code[c.pc])) THEN (* rotate by 90 degrees *)
- c.proj2.x := SHORT(-dy); c.proj2.y := SHORT(dx)
- ELSE
- c.proj2.x := SHORT(dx); c.proj2.y := SHORT(dy)
- END;
- (* projection vector must be set as well, but with current coordinates (FreeType agrees on this) *)
- GetDistance(c.zp2.pt[p1].cur, c.zp1.pt[p2].cur, dx, dy); (* note: TTI had zp1 and zp2 swapped *)
- d := Norm(dx, dy);
- dx := ShiftDiv(dx, 14, d);
- dy := ShiftDiv(dy, 14, d);
- IF ODD(ORD(c.code[c.pc])) THEN (* rotate by 90 degrees *)
- c.proj.x := SHORT(-dy); c.proj.y := SHORT(dx)
- ELSE
- c.proj.x := SHORT(dx); c.proj.y := SHORT(dy)
- END;
- c.ratio := 0;
- INC(c.pc)
- END SDPVTL;
- (* set projection vector from stack *)
- PROCEDURE SPVFS (VAR c: Context);
- BEGIN
- c.proj.y := SHORT(c.stack[c.tos]); DEC(c.tos);
- c.proj.x := SHORT(c.stack[c.tos]); DEC(c.tos);
- c.proj2 := c.proj;
- c.ratio := 0;
- INC(c.pc)
- END SPVFS;
- (* set freedom vector from stack *)
- PROCEDURE SFVFS (VAR c: Context);
- BEGIN
- c.free.y := SHORT(c.stack[c.tos]); DEC(c.tos);
- c.free.x := SHORT(c.stack[c.tos]); DEC(c.tos);
- INC(c.pc)
- END SFVFS;
- (* get projection vector *)
- PROCEDURE GPV (VAR c: Context);
- BEGIN
- INC(c.tos); c.stack[c.tos] := c.proj.x;
- INC(c.tos); c.stack[c.tos] := c.proj.y;
- INC(c.pc)
- END GPV;
- (* get freedom vector *)
- PROCEDURE GFV (VAR c: Context);
- BEGIN
- INC(c.tos); c.stack[c.tos] := c.free.x;
- INC(c.tos); c.stack[c.tos] := c.free.y;
- INC(c.pc)
- END GFV;
- (* set reference point i *)
- PROCEDURE SRPi (VAR c: Context);
- VAR rp: INTEGER;
- BEGIN
- rp := SHORT(c.stack[c.tos]); DEC(c.tos);
- CASE c.code[c.pc] OF
- | 10X: c.rp0 := rp
- | 11X: c.rp1 := rp
- | 12X: c.rp2 := rp
- END;
- INC(c.pc)
- END SRPi;
- (* set zone pointer i *)
- PROCEDURE SZPi (VAR c: Context);
- VAR gep: INTEGER;
- BEGIN
- gep := SHORT(c.stack[c.tos]); DEC(c.tos);
- CASE c.code[c.pc] OF
- | 13X: c.gep0 := gep; c.zp0 := c.zone[gep]
- | 14X: c.gep1 := gep; c.zp1 := c.zone[gep]
- | 15X: c.gep2 := gep; c.zp2 := c.zone[gep]
- END;
- INC(c.pc)
- END SZPi;
- (* set zone pointers *)
- PROCEDURE SZPS (VAR c: Context);
- BEGIN
- c.gep0 := SHORT(c.stack[c.tos]); DEC(c.tos); c.gep1 := c.gep0; c.gep2 := c.gep2;
- c.zp0 := c.zone[c.gep0]; c.zp1 := c.zp0; c.zp2 := c.zp0;
- INC(c.pc)
- END SZPS;
- (* round to half grid *)
- PROCEDURE RTHG (VAR c: Context);
- BEGIN
- c.period := 40H; c.phase := 20H; c.threshold := 20H; INC(c.pc)
- END RTHG;
- (* round to grid *)
- PROCEDURE RTG (VAR c: Context);
- BEGIN
- c.period := 40H; c.phase := 0; c.threshold := 20H; INC(c.pc)
- END RTG;
- (* round to double grid *)
- PROCEDURE RTDG (VAR c: Context);
- BEGIN
- c.period := 20H; c.phase := 0; c.threshold := 10H; INC(c.pc)
- END RTDG;
- (* round down to grid *)
- PROCEDURE RDTG (VAR c: Context);
- BEGIN
- c.period := 40H; c.phase := 0; c.threshold := 0; INC(c.pc)
- END RDTG;
- (* round up to grid *)
- PROCEDURE RUTG (VAR c: Context);
- BEGIN
- c.period := 40H; c.phase := 0; c.threshold := 3FH; INC(c.pc)
- END RUTG;
- (* round off *)
- PROCEDURE ROFF (VAR c: Context);
- BEGIN
- c.period := 1; c.phase := 0; c.threshold := 0; INC(c.pc)
- END ROFF;
- (* super round and super round 45 degrees *)
- PROCEDURE SROUND (VAR c: Context);
- VAR gridPeriod: F26D6; code, cd: LONGINT;
- BEGIN
- IF ODD(ORD(c.code[c.pc])) THEN (* super round 45 degrees *)
- gridPeriod := 45 (* funnily enough, this is really 64*(1/sqrt(2)) *)
- ELSE
- gridPeriod := 64
- END;
- code := c.stack[c.tos]; DEC(c.tos);
- cd := ASH(code, -6) MOD 4;
- CASE cd OF
- | 0: c.period := gridPeriod DIV 2
- | 1: c.period := gridPeriod
- | 2: c.period := 2*gridPeriod
- END;
- cd := ASH(code, -4) MOD 2;
- c.phase := cd * c.period DIV 4;
- cd := code MOD 16;
- IF cd = 0 THEN
- c.threshold := c.period-1
- ELSE
- c.threshold := c.period * (cd-4) DIV 8
- END;
- INC(c.pc)
- END SROUND;
- (* set loop variable *)
- PROCEDURE SLOOP (VAR c: Context);
- BEGIN
- c.loop := SHORT(c.stack[c.tos]); DEC(c.tos); INC(c.pc);
- IF c.loop = 0 THEN (* ERROR, stop execution *)
- c.pc := c.codeLen;
- END;
- END SLOOP;
- (* set minimum distance *)
- PROCEDURE SMD (VAR c: Context);
- BEGIN
- c.minDist := c.stack[c.tos]; DEC(c.tos); INC(c.pc)
- END SMD;
- (* instruction execution control *)
- PROCEDURE INSTCTRL (VAR c: Context);
- VAR sel, val: LONGINT;
- BEGIN
- sel := c.stack[c.tos]; DEC(c.tos);
- IF sel = 1 THEN c.inhibitFit := FALSE
- ELSIF sel = 2 THEN c.ignorePrep := FALSE
- END;
- val := c.stack[c.tos]; DEC(c.tos);
- IF val # 0 THEN val := sel END;
- IF val = 1 THEN c.inhibitFit := TRUE
- ELSIF val = 2 THEN c.ignorePrep := TRUE
- END;
- INC(c.pc)
- END INSTCTRL;
- (* scan conversion control *)
- PROCEDURE SCANCTRL (VAR c: Context);
- VAR n, thold: LONGINT;
- BEGIN
- n := c.stack[c.tos] MOD 10000H; DEC(c.tos);
- thold := n MOD 256;
- IF thold = 0FFH THEN
- c.fixDropouts := TRUE
- ELSIF thold = 0 THEN
- c.fixDropouts := FALSE
- ELSE
- (* should there be a default value in case no condition holds? FreeType doesn't have one *)
- thold := 40H * thold;
- IF ODD(n DIV 100H) & (PPEm(c) <= thold) THEN c.fixDropouts := TRUE END;
- IF ODD(n DIV 200H) & c.rotated THEN c.fixDropouts := TRUE END;
- IF ODD(n DIV 400H) & c.stretched THEN c.fixDropouts := TRUE END;
- IF ODD(n DIV 800H) & (PPEm(c) > thold) THEN c.fixDropouts := FALSE END;
- IF ODD(n DIV 1000H) & ~c.rotated THEN c.fixDropouts := FALSE END;
- IF ODD(n DIV 2000H) & ~c.stretched THEN c.fixDropouts := FALSE END
- END;
- INC(c.pc)
- END SCANCTRL;
- (* scan type *)
- PROCEDURE SCANTYPE (VAR c: Context);
- VAR st: INTEGER;
- BEGIN
- st := SHORT(c.stack[c.tos]); DEC(c.tos);
- IF st IN {3, 6, 7} THEN st := 2 END;
- IF (0 <= st) & (st <= 5) THEN
- c.scanType := st
- END;
- INC(c.pc)
- END SCANTYPE;
- (* set control value table cut in *)
- PROCEDURE SCVTCI (VAR c: Context);
- BEGIN
- c.cvtCutIn := c.stack[c.tos]; DEC(c.tos); INC(c.pc)
- END SCVTCI;
- (* set single width cut in *)
- PROCEDURE SSWCI (VAR c: Context);
- BEGIN
- c.swCutIn := c.stack[c.tos]; DEC(c.tos); INC(c.pc)
- END SSWCI;
- (* set single width *)
- PROCEDURE SSW (VAR c: Context);
- BEGIN
- (* FreeType says that the Windows engine seems to interpret this as a Fixed value (not FUnits as in Spec) *)
- c.swVal := ASH(c.stack[c.tos], -10); DEC(c.tos); INC(c.pc)
- END SSW;
- (* set the auto flip flag *)
- PROCEDURE FLIPON (VAR c: Context);
- BEGIN
- c.autoFlip := TRUE; INC(c.pc)
- END FLIPON;
- (* clear the auto flip flag *)
- PROCEDURE FLIPOFF (VAR c: Context);
- BEGIN
- c.autoFlip := FALSE; INC(c.pc)
- END FLIPOFF;
- (* set angle weight *)
- PROCEDURE SANGW (VAR c: Context);
- BEGIN
- DEC(c.tos); INC(c.pc) (* corresponding instruction AA is obsolete *)
- END SANGW;
- (* set delta base *)
- PROCEDURE SDB (VAR c: Context);
- BEGIN
- c.deltaBase := SHORT(c.stack[c.tos]); DEC(c.tos); INC(c.pc)
- END SDB;
- (* set delta shift *)
- PROCEDURE SDS (VAR c: Context);
- BEGIN
- c.deltaShift := SHORT(c.stack[c.tos]); DEC(c.tos); INC(c.pc)
- END SDS;
- (*--- Reading and Writing Data ---*)
- (* get coordinate projected onto the projection vector *)
- PROCEDURE GC (VAR c: Context);
- VAR p: LONGINT; dist: F26D6;
- BEGIN
- p := c.stack[c.tos];
- IF ODD(ORD(c.code[c.pc])) THEN (* use original coordinates *)
- (* both TTI and FreeType use the dual projection vector with original coordinates *)
- dist := Project(c.zp2.pt[p].org, c.proj2)
- ELSE (* use current coordinates *)
- dist := Project(c.zp2.pt[p].cur, c.proj)
- END;
- c.stack[c.tos] := dist;
- INC(c.pc)
- END GC;
- (* set coordinate from stack using projection and freedom vector *)
- PROCEDURE SCFS (VAR c: Context);
- VAR dist, d: F26D6; p: LONGINT;
- BEGIN
- dist := c.stack[c.tos]; DEC(c.tos);
- p := c.stack[c.tos]; DEC(c.tos);
- d := Project(c.zp2.pt[p].cur, c.proj);
- Move(c.zp2.pt[p], c.free, c.proj, dist - d);
- INC(c.pc)
- END SCFS;
- (* measure distance *)
- PROCEDURE MD (VAR c: Context);
- VAR p1, p2: LONGINT; d1, d2: F26D6;
- BEGIN
- (*
- - original implementation used zone 0 for p1 and zone 1 for p2
- - both TTI and FreeType swap opcode semantics (probably bug in spec since odd opcode comes first)
- - spec doesn't mention that dual projection vector has to be used with original coordinates
- *)
- p1 := c.stack[c.tos]; DEC(c.tos);
- p2 := c.stack[c.tos];
- IF ODD(ORD(c.code[c.pc])) THEN (* use current coordinates *)
- d1 := Project(c.zp1.pt[p1].cur, c.proj);
- d2 := Project(c.zp0.pt[p2].cur, c.proj)
- ELSE (* use original coordinates *)
- d1 := Project(c.zp1.pt[p1].org, c.proj2);
- d2 := Project(c.zp0.pt[p2].org, c.proj2)
- END;
- c.stack[c.tos] := d2 - d1;
- INC(c.pc)
- END MD;
- (* measure pixels per em *)
- PROCEDURE MPPEM (VAR c: Context);
- BEGIN
- INC(c.tos); c.stack[c.tos] := ASH(PPEm(c) + 20H, -6); INC(c.pc)
- END MPPEM;
- (* measure point size *)
- PROCEDURE MPS (VAR c: Context);
- BEGIN
- INC(c.tos); c.stack[c.tos] := ASH(c.ptsize + 20H, -6); INC(c.pc)
- END MPS;
- (*--- Managing Outlines ---*)
- (* flip point *)
- PROCEDURE FLIPPT (VAR c: Context);
- VAR p: LONGINT; pt: Points;
- BEGIN
- (* both TTI and FreeType don't use zp0; instead they work in zone 1 directly *)
- pt := c.zone[1].pt;
- WHILE c.loop > 0 DO
- p := c.stack[c.tos]; DEC(c.tos);
- pt[p].onCurve := ~pt[p].onCurve;
- DEC(c.loop)
- END;
- c.loop := 1;
- INC(c.pc)
- END FLIPPT;
- (* flip range on/off *)
- PROCEDURE FLIPRG (VAR c: Context);
- VAR on: BOOLEAN; hi, lo: LONGINT; pt: Points;
- BEGIN
- on := ODD(ORD(c.code[c.pc]));
- hi := c.stack[c.tos]; DEC(c.tos);
- lo := c.stack[c.tos]; DEC(c.tos);
- pt := c.zone[1].pt;
- WHILE lo <= hi DO
- pt[lo].onCurve := on;
- INC(lo)
- END;
- INC(c.pc)
- END FLIPRG;
- (* shift point by the last point *)
- PROCEDURE SHP (VAR c: Context);
- VAR zone: Zone; p: LONGINT; dx, dy: F26D6; pt: Points;
- BEGIN
- GetRefDist(c, ODD(ORD(c.code[c.pc])), zone, p, dx, dy);
- pt := c.zp2.pt;
- WHILE c.loop > 0 DO
- p := c.stack[c.tos]; DEC(c.tos);
- IF c.free.x # 0 THEN
- INC(pt[p].cur[X], dx); pt[p].touched[X] := TRUE
- END;
- IF c.free.y # 0 THEN
- INC(pt[p].cur[Y], dy); pt[p].touched[Y] := TRUE
- END;
- DEC(c.loop)
- END;
- c.loop := 1;
- INC(c.pc)
- END SHP;
- (* shift contour by the last point *)
- PROCEDURE SHC (VAR c: Context);
- VAR zone: Zone; ref, cont, cur, last: LONGINT; dx, dy: F26D6; pt: Points;
- BEGIN
- (*
- - TTI uses original coordinates (which is probably wrong)
- - FreeType says that points aren't touched (so I don't)
- *)
- GetRefDist(c, ODD(ORD(c.code[c.pc])), zone, ref, dx, dy);
- pt := c.zp2.pt;
- cont := c.stack[c.tos]; DEC(c.tos);
- cur := c.zp2.first[cont]; last := c.zp2.first[cont+1]-1;
- WHILE cur <= last DO
- IF (zone # c.zp2) OR (cur # ref) THEN
- IF c.free.x # 0 THEN
- INC(pt[cur].cur[X], dx)
- END;
- IF c.free.y # 0 THEN
- INC(pt[cur].cur[Y], dy)
- END
- END;
- INC(cur)
- END;
- INC(c.pc)
- END SHC;
- (* shift zone by the last point *)
- PROCEDURE SHZ (VAR c: Context);
- VAR zone, z: Zone; ref, cur, last: LONGINT; dx, dy: F26D6; pt: Points;
- BEGIN
- (*
- - TTI uses original coordinates (which is probably wrong)
- - FreeType says that points aren't touched (so I don't)
- - FreeType ignores the argument on the stack and always uses zp2
- *)
- GetRefDist(c, ODD(ORD(c.code[c.pc])), zone, ref, dx, dy);
- z := c.zone[c.stack[c.tos]]; DEC(c.tos);
- pt := z.pt;
- cur := 0; last := z.first[z.contours]-1;
- WHILE cur <= last DO
- IF (zone # z) OR (cur # ref) THEN
- IF c.free.x # 0 THEN
- INC(pt[cur].cur[X], dx)
- END;
- IF c.free.y # 0 THEN
- INC(pt[cur].cur[Y], dy)
- END
- END;
- INC(cur)
- END;
- INC(c.pc)
- END SHZ;
- (* shift point by a pixel amount *)
- PROCEDURE SHPIX (VAR c: Context);
- VAR dist, dx, dy: F26D6; pt: Points; p: LONGINT;
- BEGIN
- dist := c.stack[c.tos]; DEC(c.tos);
- dx := MulShift(dist, c.free.x, -14);
- dy := MulShift(dist, c.free.y, -14);
- pt := c.zp2.pt;
- WHILE c.loop > 0 DO
- p := c.stack[c.tos]; DEC(c.tos);
- IF c.free.x # 0 THEN
- INC(pt[p].cur[X], dx); pt[p].touched[X] := TRUE
- END;
- IF c.free.y # 0 THEN
- INC(pt[p].cur[Y], dy); pt[p].touched[Y] := TRUE
- END;
- DEC(c.loop)
- END;
- c.loop := 1;
- INC(c.pc)
- END SHPIX;
- (* move stack indirect relative point *)
- PROCEDURE MSIRP (VAR c: Context);
- VAR dist, d: F26D6; p: LONGINT; org: Coord; pt: Points;
- BEGIN
- dist := c.stack[c.tos]; DEC(c.tos);
- p := c.stack[c.tos]; DEC(c.tos);
- (* undocumented behaviour, suggested by FreeType *)
- IF c.gep0 = 0 THEN
- org := c.zp0.pt[c.rp0].org;
- pt := c.zp1.pt; pt[p].org := org; pt[p].cur := org
- END;
- d := Project(c.zp1.pt[p].cur, c.proj) - Project(c.zp0.pt[c.rp0].cur, c.proj);
- Move(c.zp1.pt[p], c.free, c.proj, dist - d);
- c.rp1 := c.rp0; c.rp2 := SHORT(p); (* TTI didn't implement this *)
- IF ODD(ORD(c.code[c.pc])) THEN
- c.rp0 := SHORT(p)
- END;
- INC(c.pc)
- END MSIRP;
- (* move direct absolute point *)
- PROCEDURE MDAP (VAR c: Context);
- VAR p: LONGINT; d, dist: F26D6;
- BEGIN
- p := c.stack[c.tos]; DEC(c.tos);
- IF ODD(ORD(c.code[c.pc])) THEN
- d := Project(c.zp0.pt[p].cur, c.proj);
- dist := Round(d, c.period, c.phase, c.threshold) - d
- ELSE
- dist := 0
- END;
- Move(c.zp0.pt[p], c.free, c.proj, dist);
- c.rp0 := SHORT(p); c.rp1 := SHORT(p);
- INC(c.pc)
- END MDAP;
- (* move indirect absolute point *)
- PROCEDURE MIAP (VAR c: Context);
- VAR cvt, p: LONGINT; dist, d: F26D6; pt: Points; xy: Coord;
- BEGIN
- cvt := c.stack[c.tos]; DEC(c.tos);
- p := c.stack[c.tos]; DEC(c.tos);
- dist := CVTValue(cvt, c);
- pt := c.zp0.pt;
- IF c.gep0 = 0 THEN (* twilight zone *)
- (* why does FreeType use the freedom vector for this? The spec explicitly mentions the projection vector *)
- xy[X] := MulShift(dist, c.proj.x, -14); xy[Y] := MulShift(dist, c.proj.y, -14);
- pt[p].org := xy; pt[p].cur := xy
- END;
- d := Project(pt[p].cur, c.proj);
- IF c.autoFlip & (dist * d < 0) THEN dist := -dist END; (* got this from TTI; FreeType does nothing similar *)
- IF ODD(ORD(c.code[c.pc])) THEN (* round and apply cvt cutin *)
- IF ABS(dist - d) > c.cvtCutIn THEN dist := d END;
- dist := Round(dist, c.period, c.phase, c.threshold)
- END;
- Move(pt[p], c.free, c.proj, dist - d);
- c.rp0 := SHORT(p); c.rp1 := SHORT(p);
- INC(c.pc)
- END MIAP;
- (* move direct relative point *)
- PROCEDURE MDRP (VAR c: Context);
- VAR p: LONGINT; d, dist: F26D6;
- BEGIN
- p := c.stack[c.tos]; DEC(c.tos);
- d := Project(c.zp1.pt[p].org, c.proj2) - Project(c.zp0.pt[c.rp0].org, c.proj2);
- (* why does FreeType use the absolute value of 'd' for the single width cutin test? *)
- IF (d >= 0) & (ABS(d - c.swVal) < c.swCutIn) THEN d := c.swVal
- ELSIF (d < 0) & (ABS(-d - c.swVal) < c.swCutIn) THEN d := -c.swVal
- END;
- IF ODD(ORD(c.code[c.pc]) DIV 4) THEN (* round distance *)
- dist := Round(d, c.period, c.phase, c.threshold)
- ELSE
- dist := d
- END;
- IF ODD(ORD(c.code[c.pc]) DIV 8) THEN (* keep distance greater than minimum distance *)
- IF (d >= 0) & (dist < c.minDist) THEN dist := c.minDist
- ELSIF (d < 0) & (dist > -c.minDist) THEN dist := -c.minDist
- END
- END;
- d := Project(c.zp1.pt[p].cur, c.proj) - Project(c.zp0.pt[c.rp0].cur, c.proj);
- Move(c.zp1.pt[p], c.free, c.proj, dist - d);
- c.rp1 := c.rp0; c.rp2 := SHORT(p);
- IF ODD(ORD(c.code[c.pc]) DIV 16) THEN
- c.rp0 := SHORT(p)
- END;
- INC(c.pc)
- END MDRP;
- (* move indirect relative point *)
- PROCEDURE MIRP (VAR c: Context);
- VAR cvt, p: LONGINT; dcvt, od, cd, dist: F26D6; pt: Points; xy: Coord;
- BEGIN
- IF LEN(c.stack) <= c.tos THEN RETURN END;
- cvt := c.stack[c.tos]; DEC(c.tos);
- p := c.stack[c.tos]; DEC(c.tos);
- dcvt := CVTValue(cvt, c);
- pt := c.zp1.pt;
- IF c.gep1 = 0 THEN (* according to FreeType, MIRP can be used to create twilight points *)
- xy[X] := c.zp0.pt[c.rp0].org[X] + MulShift(dcvt, c.free.x, -14);
- xy[Y] := c.zp0.pt[c.rp0].org[Y] + MulShift(dcvt, c.free.y, -14);
- pt[p].org := xy; pt[p].cur := xy
- END;
- od := Project(pt[p].org, c.proj2) - Project(c.zp0.pt[c.rp0].org, c.proj2);
- cd := Project(pt[p].cur, c.proj) - Project(c.zp0.pt[c.rp0].cur, c.proj);
- IF c.autoFlip & (od * dcvt < 0) THEN
- dcvt := -dcvt
- END;
- IF ODD(ORD(c.code[c.pc]) DIV 4) THEN (* perform cvtCutIn test and round *)
- IF c.zp0 = c.zp1 THEN (* according to FreeType, both points have to be in the same zone *)
- IF ABS(od - dcvt) >= c.cvtCutIn THEN
- dcvt := od
- END;
- (* for the single width cut in test, FreeType uses again the value of dcvt directly !? *)
- IF (dcvt >= 0) & (ABS(dcvt - c.swVal) < c.swCutIn) THEN dcvt := c.swVal
- ELSIF (dcvt < 0) & (ABS(-dcvt - c.swVal) < c.swCutIn) THEN dcvt := -c.swVal
- END
- END;
- dist := Round(dcvt, c.period, c.phase, c.threshold)
- ELSE
- dist := dcvt (* TTI used the original distance, which is almost certainly wrong *)
- END;
- IF ODD(ORD(c.code[c.pc]) DIV 8) THEN (* perform minimum distance test *)
- IF (od >= 0) & (dist < c.minDist) THEN dist := c.minDist
- ELSIF (od < 0) & (dist > -c.minDist) THEN dist := -c.minDist
- END
- END;
- Move(pt[p], c.free, c.proj, dist - cd);
- c.rp1 := c.rp0; c.rp2 := SHORT(p);
- IF ODD(ORD(c.code[c.pc]) DIV 16) THEN
- c.rp0 := SHORT(p)
- END;
- INC(c.pc)
- END MIRP;
- (* align relative point *)
- PROCEDURE ALIGNRP (VAR c: Context);
- VAR p: LONGINT; dist: F26D6;
- BEGIN
- WHILE c.loop > 0 DO
- p := c.stack[c.tos]; DEC(c.tos);
- dist := Project(c.zp1.pt[p].cur, c.proj) - Project(c.zp0.pt[c.rp0].cur, c.proj);
- Move(c.zp1.pt[p], c.free, c.proj, -dist);
- DEC(c.loop)
- END;
- c.loop := 1;
- INC(c.pc)
- END ALIGNRP;
- (* move point to intersection of two lines *)
- PROCEDURE ISECT (VAR c: Context);
- VAR
- b1, b0, a1, a0, p: LONGINT; pt: Points; ax0, ay0, ax1, ay1, bx0, by0, bx1, by1, d, rx, ry: F26D6;
- dxa, dya, dxb, dyb, dx, dy, u, v, det: INT64;
- BEGIN
- b1 := c.stack[c.tos]; DEC(c.tos);
- b0 := c.stack[c.tos]; DEC(c.tos);
- a1 := c.stack[c.tos]; DEC(c.tos);
- a0 := c.stack[c.tos]; DEC(c.tos);
- p := c.stack[c.tos]; DEC(c.tos);
- pt := c.zp2.pt;
- pt[p].touched[X] := TRUE; pt[p].touched[Y] := TRUE;
- ax0 := c.zp1.pt[a0].cur[X]; ay0 := c.zp1.pt[a0].cur[Y];
- ax1 := c.zp1.pt[a1].cur[X]; ay1 := c.zp1.pt[a1].cur[Y];
- bx0 := c.zp0.pt[b0].cur[X]; by0 := c.zp0.pt[b0].cur[Y];
- bx1 := c.zp0.pt[b1].cur[X]; by1 := c.zp0.pt[b1].cur[Y];
- ToINT64(ax1 - ax0, dxa); ToINT64(ay1 - ay0, dya);
- ToINT64(bx1 - bx0, dxb); ToINT64(by1 - by0, dyb);
- MulINT64(dya, dxb, u); MulINT64(dyb, dxa, v);
- SubINT64(u, v, det);
- FromINT64(det, d);
- IF ABS(d) >= 80H THEN
- ToINT64(bx0 - ax0, dx); ToINT64(by0 - ay0, dy);
- SubINT64(Zero64, dyb, dyb);
- MulINT64(dx, dyb, u); MulINT64(dy, dxb, v); AddINT64(u, v, v);
- MulINT64(v, dxa, u); DivINT64(u, det, u); FromINT64(u, rx);
- MulINT64(v, dya, u); DivINT64(u, det, u); FromINT64(u, ry);
- pt[p].cur[X] := ax0 + rx;
- pt[p].cur[Y] := ay0 + ry
- ELSE (* lines are (almost) parallel *)
- pt[p].cur[X] := (ax0 + ax1 + bx0 + bx1) DIV 4;
- pt[p].cur[Y] := (ay0 + ay1 + by0 + by1) DIV 4
- END;
- INC(c.pc)
- END ISECT;
- (* align points *)
- PROCEDURE ALIGNPTS (VAR c: Context);
- VAR p1, p2: LONGINT; dist: F26D6;
- BEGIN
- p1 := c.stack[c.tos]; DEC(c.tos);
- p2 := c.stack[c.tos]; DEC(c.tos);
- (* both TTI and FreeType swap use p1 with zp0 and p2 with zp1 (contrary to spec) *)
- dist := (Project(c.zp0.pt[p1].cur, c.proj) - Project(c.zp1.pt[p2].cur, c.proj)) DIV 2;
- Move(c.zp0.pt[p1], c.free, c.proj, -dist);
- Move(c.zp1.pt[p2], c.free, c.proj, dist);
- INC(c.pc)
- END ALIGNPTS;
- (* interpolate point by the last relative stretch *)
- PROCEDURE IP (VAR c: Context);
- VAR od1, od2, cd1, cd2, od, cd, dist: F26D6; pt: Points; p: LONGINT;
- BEGIN
- od1 := Project(c.zp0.pt[c.rp1].org, c.proj2);
- od2 := Project(c.zp1.pt[c.rp2].org, c.proj2);
- cd1 := Project(c.zp0.pt[c.rp1].cur, c.proj);
- cd2 := Project(c.zp1.pt[c.rp2].cur, c.proj);
- pt := c.zp2.pt;
- WHILE c.loop > 0 DO
- p := c.stack[c.tos]; DEC(c.tos);
- od := Project(pt[p].org, c.proj2);
- cd := Project(pt[p].cur, c.proj);
- IF (od1 <= od2) & (od <= od1) OR (od1 > od2) & (od >= od1) THEN
- dist := cd1 - od1 + od - cd
- ELSIF (od1 <= od2) & (od2 <= od) OR (od1 > od2) & (od2 >= od) THEN
- dist := cd2 - od2 + od - cd
- ELSE
- dist := MulDiv(cd2 - cd1, od - od1, od2 - od1) + cd1 - cd
- END;
- Move(pt[p], c.free, c.proj, dist);
- DEC(c.loop)
- END;
- c.loop := 1;
- INC(c.pc)
- END IP;
- (* untouch point *)
- PROCEDURE UTP (VAR c: Context);
- VAR p: LONGINT;
- BEGIN
- p := c.stack[c.tos]; DEC(c.tos);
- IF c.free.x # 0 THEN
- c.zp2.pt[p].touched[X] := FALSE
- END;
- IF c.free.y # 0 THEN
- c.zp2.pt[p].touched[Y] := FALSE
- END;
- INC(c.pc)
- END UTP;
- (* interpolate untouched points through the outline *)
- PROCEDURE IUP (VAR c: Context);
- VAR
- z: Zone; pt: Points; n, xy, beg, nil, first, end, cur: LONGINT; dxy: F26D6;
- PROCEDURE interpol (p0, p1, rp0, rp1: LONGINT);
- VAR oxy0, cxy0, dxy0, oxy1, cxy1, dxy1, cxy: F26D6;
- BEGIN
- IF p0 <= p1 THEN
- oxy0 := pt[rp0].org[xy]; cxy0 := pt[rp0].cur[xy]; dxy0 := cxy0 - oxy0;
- oxy1 := pt[rp1].org[xy]; cxy1 := pt[rp1].cur[xy]; dxy1 := cxy1 - oxy1;
- IF oxy0 < oxy1 THEN
- WHILE p0 <= p1 DO
- cxy := pt[p0].org[xy];
- IF cxy <= oxy0 THEN INC(cxy, dxy0)
- ELSIF oxy1 <= cxy THEN INC(cxy, dxy1)
- ELSE cxy := cxy0 + MulDiv(cxy - oxy0, cxy1 - cxy0, oxy1 - oxy0)
- END;
- pt[p0].cur[xy] := cxy;
- INC(p0)
- END
- ELSIF oxy1 < oxy0 THEN
- WHILE p0 <= p1 DO
- cxy := pt[p0].org[xy];
- IF cxy <= oxy1 THEN INC(cxy, dxy1)
- ELSIF oxy0 <= cxy THEN INC(cxy, dxy0)
- ELSE cxy := cxy0 + MulDiv(cxy - oxy0, cxy1 - cxy0, oxy1 - oxy0)
- END;
- pt[p0].cur[xy] := cxy;
- INC(p0)
- END
- ELSE
- WHILE p0 <= p1 DO
- cxy := pt[p0].org[xy];
- IF cxy <= oxy0 THEN INC(cxy, dxy0)
- ELSE INC(cxy, dxy1)
- END;
- pt[p0].cur[xy] := cxy;
- INC(p0)
- END
- END
- END
- END interpol;
- BEGIN
- z := c.zp2; pt := z.pt; n := 0;
- xy := ORD(c.code[c.pc]) MOD 2;
- WHILE n < z.contours DO
- beg := z.first[n]; nil := z.first[n+1];
- WHILE (beg < nil) & ~pt[beg].touched[xy] DO INC(beg) END;
- IF beg < nil THEN
- first := beg;
- REPEAT
- end := beg+1;
- WHILE (end < nil) & ~pt[end].touched[xy] DO INC(end) END;
- IF end < nil THEN
- interpol(beg+1, end-1, beg, end);
- beg := end+1;
- WHILE (beg < nil) & pt[beg].touched[xy] DO INC(beg) END;
- DEC(beg)
- END
- UNTIL end = nil;
- IF beg = first THEN (* only one touched point in whole contour => FreeType applies shift here *)
- dxy := pt[beg].cur[xy] - pt[beg].org[xy];
- cur := z.first[n];
- WHILE cur < beg DO INC(pt[cur].cur[xy], dxy); INC(cur) END;
- cur := beg+1;
- WHILE cur < nil DO INC(pt[cur].cur[xy], dxy); INC(cur) END
- ELSE
- interpol(beg+1, nil-1, beg, first);
- IF first > z.first[n] THEN interpol(z.first[n], first-1, beg, first) END
- END
- END;
- INC(n)
- END;
- INC(c.pc)
- END IUP;
- (*--- Managing Exceptions ---*)
- (* delta exception Pn *)
- PROCEDURE DELTAP (VAR c: Context);
- VAR base, ppm, n, p, arg: LONGINT;
- BEGIN
- base := c.deltaBase;
- IF c.code[c.pc] = 71X THEN INC(base, 16) (* DELTAP2 *)
- ELSIF c.code[c.pc] = 72X THEN INC(base, 32) (* DELTAP3 *)
- END;
- ppm := ASH(PPEm(c) + 20H, -6);
- n := c.stack[c.tos]; DEC(c.tos);
- WHILE n > 0 DO
- p := c.stack[c.tos]; DEC(c.tos);
- arg := c.stack[c.tos]; DEC(c.tos);
- IF (base + arg DIV 10H MOD 10H = ppm) & (0 <= p) & (p < LEN(c.zp0.pt^)) THEN
- arg := arg MOD 10H - 8;
- IF arg >= 0 THEN INC(arg) END;
- arg := 40H * arg DIV ASH(1, c.deltaShift);
- Move(c.zp0.pt[p], c.free, c.proj, arg)
- END;
- DEC(n)
- END;
- INC(c.pc)
- END DELTAP;
- (* delta exception Cn *)
- PROCEDURE DELTAC (VAR c: Context);
- VAR base, ppm, n, cvt, arg: LONGINT;
- BEGIN
- base := c.deltaBase;
- IF c.code[c.pc] = 74X THEN INC(base, 16) (* DELTAC2 *)
- ELSIF c.code[c.pc] = 75X THEN INC(base, 32) (* DELTAC3 *)
- END;
- ppm := ASH(PPEm(c) + 20H, -6);
- n := c.stack[c.tos]; DEC(c.tos);
- WHILE n > 0 DO
- cvt := c.stack[c.tos]; DEC(c.tos);
- arg := c.stack[c.tos]; DEC(c.tos);
- IF base + arg DIV 10H MOD 10H = ppm THEN
- arg := arg MOD 10H - 8;
- IF arg >= 0 THEN INC(arg) END;
- arg := 40H * arg DIV ASH(1, c.deltaShift);
- INC(c.cvt[cvt], ShiftDiv(arg, 16, Ratio(c)))
- END;
- DEC(n)
- END;
- INC(c.pc)
- END DELTAC;
- (*--- Managing the Stack ---*)
- (* duplicate top stack element *)
- PROCEDURE DUP (VAR c: Context);
- BEGIN
- INC(c.tos); c.stack[c.tos] := c.stack[c.tos-1]; INC(c.pc)
- END DUP;
- (* pop top stack element *)
- PROCEDURE POP (VAR c: Context);
- BEGIN
- DEC(c.tos); INC(c.pc)
- END POP;
- (* clear the entire stack *)
- PROCEDURE CLEAR (VAR c: Context);
- BEGIN
- c.tos := -1; INC(c.pc)
- END CLEAR;
- (* swap the top two elements on the stack *)
- PROCEDURE SWAP (VAR c: Context);
- VAR tmp: LONGINT;
- BEGIN
- tmp := c.stack[c.tos]; c.stack[c.tos] := c.stack[c.tos-1]; c.stack[c.tos-1] := tmp; INC(c.pc)
- END SWAP;
- (* return depth of the stack *)
- PROCEDURE DEPTH (VAR c: Context);
- BEGIN
- INC(c.tos); c.stack[c.tos] := c.tos; INC(c.pc)
- END DEPTH;
- (* copy the indexed element to the top of the stack *)
- PROCEDURE CINDEX (VAR c: Context);
- VAR idx: LONGINT;
- BEGIN
- idx := c.stack[c.tos]; c.stack[c.tos] := c.stack[c.tos - idx]; INC(c.pc)
- END CINDEX;
- (* move the indexed element to the top of the stack *)
- PROCEDURE MINDEX (VAR c: Context);
- VAR idx, pos, elem: LONGINT;
- BEGIN
- idx := c.stack[c.tos];
- pos := c.tos - idx; elem := c.stack[pos];
- WHILE idx > 1 DO
- c.stack[pos] := c.stack[pos+1]; INC(pos); DEC(idx)
- END;
- c.stack[pos] := elem; DEC(c.tos);
- INC(c.pc)
- END MINDEX;
- (* roll the top three stack elements *)
- PROCEDURE ROLL (VAR c: Context);
- VAR elem: LONGINT;
- BEGIN
- elem := c.stack[c.tos-2]; c.stack[c.tos-2] := c.stack[c.tos-1]; c.stack[c.tos-1] := c.stack[c.tos]; c.stack[c.tos] := elem;
- INC(c.pc)
- END ROLL;
- (*--- Managing the Flow of Control ---*)
- PROCEDURE Skip (VAR c: Context);
- BEGIN
- CASE c.code[c.pc] OF
- | 40X: INC(c.pc, LONG(2 + ORD(c.code[c.pc+1]))) (* NPUSHB *)
- | 41X: INC(c.pc, LONG(2 + 2*ORD(c.code[c.pc+1]))) (* NPUSHW *)
- | 0B0X..0B7X: INC(c.pc, LONG(2 + ORD(c.code[c.pc]) MOD 8)) (* PUSHBx *)
- | 0B8X..0BFX: INC(c.pc, LONG(3 + 2*(ORD(c.code[c.pc]) MOD 8))) (* PUSHWx *)
- | 58X: INC(c.pc); WHILE c.code[c.pc] # 59X DO Skip(c) END; INC(c.pc) (* IF..EIF *)
- ELSE INC(c.pc)
- END
- END Skip;
- (* if test *)
- PROCEDURE iF (VAR c: Context);
- BEGIN
- IF c.stack[c.tos] = 0 THEN
- INC(c.pc);
- WHILE (c.code[c.pc] # 1BX) & (c.code[c.pc] # 59X) DO (* terminated by ELSE or EIF *)
- Skip(c)
- END
- END;
- DEC(c.tos); INC(c.pc)
- END iF;
- (* else part of if-clause *)
- PROCEDURE eLSE (VAR c: Context);
- BEGIN
- (* only executed if previous IF-test was successful => skip until EIF *)
- REPEAT Skip(c) UNTIL c.code[c.pc] = 59X;
- INC(c.pc)
- END eLSE;
- (* end mark of if-clause *)
- PROCEDURE EIF (VAR c: Context);
- BEGIN
- INC(c.pc)
- END EIF;
- (* jump relative on true *)
- PROCEDURE JROT (VAR c: Context);
- VAR true: BOOLEAN;
- BEGIN
- true := c.stack[c.tos] # 0; DEC(c.tos);
- IF true THEN
- INC(c.pc, c.stack[c.tos]);
- ELSE
- INC(c.pc)
- END;
- DEC(c.tos)
- END JROT;
- (* jump relative *)
- PROCEDURE JUMPR (VAR c: Context);
- BEGIN
- INC(c.pc, c.stack[c.tos]); DEC(c.tos)
- END JUMPR;
- (* jump relative on false *)
- PROCEDURE JROF (VAR c: Context);
- VAR false: BOOLEAN;
- BEGIN
- false := c.stack[c.tos] = 0; DEC(c.tos);
- IF false THEN
- INC(c.pc, c.stack[c.tos]);
- ELSE
- INC(c.pc)
- END;
- DEC(c.tos)
- END JROF;
- (*--- Logical Functions ---*)
- (* comparison *)
- PROCEDURE COMPARE (VAR c: Context);
- VAR b, a: LONGINT; res: BOOLEAN;
- BEGIN
- b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
- CASE c.code[c.pc] OF
- | 50X: res := a < b
- | 51X: res := a <= b
- | 52X: res := a > b
- | 53X: res := a >= b
- | 54X: res := a = b
- | 55X: res := a # b
- END;
- IF res THEN c.stack[c.tos] := 1
- ELSE c.stack[c.tos] := 0
- END;
- INC(c.pc)
- END COMPARE;
- (* odd *)
- PROCEDURE oDD (VAR c: Context);
- VAR r: LONGINT;
- BEGIN
- r := Round(c.stack[c.tos], c.period, c.phase, c.threshold) DIV 40H;
- IF ODD(r) THEN c.stack[c.tos] := 1 ELSE c.stack[c.tos] := 0 END;
- INC(c.pc)
- END oDD;
- (* even *)
- PROCEDURE EVEN (VAR c: Context);
- VAR r: LONGINT;
- BEGIN
- r := Round(c.stack[c.tos], c.period, c.phase, c.threshold) DIV 40H;
- IF ODD(r) THEN c.stack[c.tos] := 0 ELSE c.stack[c.tos] := 1 END;
- INC(c.pc)
- END EVEN;
- (* logical and *)
- PROCEDURE AND (VAR c: Context);
- VAR b, a: LONGINT;
- BEGIN
- b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
- IF a * b # 0 THEN c.stack[c.tos] := 1 ELSE c.stack[c.tos] := 0 END;
- INC(c.pc)
- END AND;
- (* logical or *)
- PROCEDURE oR (VAR c: Context);
- VAR b, a: LONGINT;
- BEGIN
- b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
- IF (a # 0) OR (b # 0) THEN c.stack[c.tos] := 1 ELSE c.stack[c.tos] := 0 END;
- INC(c.pc)
- END oR;
- (* logical not *)
- PROCEDURE NOT (VAR c: Context);
- BEGIN
- IF c.stack[c.tos] = 0 THEN c.stack[c.tos] := 1 ELSE c.stack[c.tos] := 0 END;
- INC(c.pc)
- END NOT;
- (*--- Arithmetic and Math Instructions ---*)
- PROCEDURE ADD (VAR c: Context);
- VAR b: F26D6;
- BEGIN
- b := c.stack[c.tos]; DEC(c.tos); INC(c.stack[c.tos], b); INC(c.pc)
- END ADD;
- PROCEDURE SUB (VAR c: Context);
- VAR b: F26D6;
- BEGIN
- b := c.stack[c.tos]; DEC(c.tos); DEC(c.stack[c.tos], b); INC(c.pc)
- END SUB;
- PROCEDURE dIV (VAR c: Context);
- VAR b, a: F26D6;
- BEGIN
- b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
- IF b > 0 THEN c.stack[c.tos] := ShiftDiv(a, 6, b)
- ELSIF b < 0 THEN c.stack[c.tos] := ShiftDiv(-a, 6, -b)
- ELSE c.stack[c.tos] := 0 (* division by zero *)
- END;
- INC(c.pc)
- END dIV;
- PROCEDURE MUL (VAR c: Context);
- VAR b, a: F26D6;
- BEGIN
- b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
- c.stack[c.tos] := MulShift(a, b, -6);
- INC(c.pc)
- END MUL;
- PROCEDURE aBS (VAR c: Context);
- BEGIN
- c.stack[c.tos] := ABS(c.stack[c.tos]); INC(c.pc)
- END aBS;
- PROCEDURE NEG (VAR c: Context);
- BEGIN
- c.stack[c.tos] := -c.stack[c.tos]; INC(c.pc)
- END NEG;
- PROCEDURE Floor (VAR c: Context);
- VAR x: F26D6;
- BEGIN
- x := c.stack[c.tos];
- c.stack[c.tos] := x - x MOD 40H;
- INC(c.pc)
- END Floor;
- PROCEDURE CEILING (VAR c: Context);
- VAR x: F26D6;
- BEGIN
- x := c.stack[c.tos] + 3FH;
- c.stack[c.tos] := x - x MOD 40H;
- INC(c.pc)
- END CEILING;
- PROCEDURE mAX (VAR c: Context);
- VAR b, a: F26D6;
- BEGIN
- b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
- IF a < b THEN c.stack[c.tos] := b END;
- INC(c.pc)
- END mAX;
- PROCEDURE mIN (VAR c: Context);
- VAR b, a: F26D6;
- BEGIN
- b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
- IF a > b THEN c.stack[c.tos] := b END;
- INC(c.pc)
- END mIN;
- (*--- Compensating for the Engine Characteristics ---*)
- (* round value *)
- PROCEDURE ROUND (VAR c: Context);
- BEGIN
- (* no engine characteristics are implemented *)
- c.stack[c.tos] := Round(c.stack[c.tos], c.period, c.phase, c.threshold);
- INC(c.pc)
- END ROUND;
- (* compensate without rounding value *)
- PROCEDURE NROUND (VAR c: Context);
- BEGIN
- INC(c.pc) (* nothing happens *)
- END NROUND;
- (*--- Defining and Using Functions and Instructions ---*)
- (* function definition *)
- PROCEDURE FDEF (VAR c: Context);
- VAR n: LONGINT;
- BEGIN
- n := c.stack[c.tos]; DEC(c.tos);
- c.func[n].code := c.code; c.func[n].len := c.codeLen; c.func[n].pc := c.pc;
- REPEAT Skip(c) UNTIL c.code[c.pc] = 2DX; (* skip until ENDF *)
- INC(c.pc)
- END FDEF;
- (* end function definition *)
- PROCEDURE ENDF (VAR c: Context);
- BEGIN
- DEC(c.callStack[c.ctos].count);
- IF c.callStack[c.ctos].count < 0 THEN c.pc := c.codeLen; RETURN END; (* ERROR, prevent stack trap *)
- IF c.callStack[c.ctos].count = 0 THEN
- c.code := c.callStack[c.ctos].ret.code; c.codeLen := c.callStack[c.ctos].ret.len; c.pc := c.callStack[c.ctos].ret.pc;
- DEC(c.ctos)
- ELSE
- c.pc := c.callStack[c.ctos].start (* code remains the same *)
- END;
- INC(c.pc) (* make PC point to instruction after FDEF/IDEF/(LOOP)CALL *)
- END ENDF;
- (* call function *)
- PROCEDURE CALL (VAR c: Context);
- VAR n: LONGINT;
- BEGIN
- n := c.stack[c.tos]; DEC(c.tos);
- INC(c.ctos);
- c.callStack[c.ctos].ret.code := c.code; c.callStack[c.ctos].ret.len := c.codeLen;
- c.callStack[c.ctos].ret.pc := c.pc; c.callStack[c.ctos].count := 1;
- c.code := c.func[n].code; c.codeLen := c.func[n].len; c.pc := c.func[n].pc+1 (* make PC point to first instruction after FDEF *)
- END CALL;
- (* loop and call function *)
- PROCEDURE LOOPCALL (VAR c: Context);
- VAR n, count: LONGINT;
- BEGIN
- n := c.stack[c.tos]; DEC(c.tos);
- count := c.stack[c.tos]; DEC(c.tos);
- INC(c.ctos);
- c.callStack[c.ctos].ret.code := c.code; c.callStack[c.ctos].ret.len := c.codeLen; c.callStack[c.ctos].ret.pc := c.pc;
- c.callStack[c.ctos].count := SHORT(count); c.callStack[c.ctos].start := c.func[n].pc;
- c.code := c.func[n].code; c.codeLen := c.func[n].len; c.pc := c.func[n].pc+1 (* make PC point to first instruction after FDEF *)
- END LOOPCALL;
- (* instruction definition *)
- PROCEDURE IDEF (VAR c: Context);
- VAR op: CHAR; i: LONGINT;
- BEGIN
- op := CHR(c.stack[c.tos]); DEC(c.tos);
- i := 0; WHILE (c.instr[i].beg.code # NIL) & (c.instr[i].opcode # op) DO INC(i) END;
- IF c.instr[i].beg.code = NIL THEN
- c.instr[i].opcode := op; c.instr[i].beg.code := c.code; c.instr[i].beg.len := c.codeLen; c.instr[i].beg.pc := c.pc
- END;
- REPEAT Skip(c) UNTIL c.code[c.pc] = 2DX; (* skip until ENDF *)
- INC(c.pc)
- END IDEF;
- (* user defined instructions *)
- PROCEDURE UNDEF (VAR c: Context);
- VAR i: LONGINT;
- BEGIN
- i := 0; WHILE (c.instr[i].beg.code # NIL) & (c.instr[i].opcode # c.code[c.pc]) DO INC(i) END;
- IF c.instr[i].beg.code # NIL THEN (* found instruction *)
- INC(c.ctos);
- c.callStack[c.ctos].ret.code := c.code; c.callStack[c.ctos].ret.len := c.codeLen;
- c.callStack[c.ctos].ret.pc := c.pc; c.callStack[c.ctos].count := 1;
- c.code := c.instr[i].beg.code; c.pc := c.instr[i].beg.pc
- END;
- INC(c.pc)
- END UNDEF;
- (*--- Miscellaneous Instructions ---*)
- (* debug call *)
- PROCEDURE DEBUG (VAR c: Context);
- BEGIN
- DEC(c.tos); INC(c.pc); (* pop the value off the stack *)
- IF Notify # NIL THEN Notify(c, NotifyData) END
- END DEBUG;
- (* get information *)
- PROCEDURE GETINFO (VAR c: Context);
- VAR sel, val: LONGINT;
- BEGIN
- sel := c.stack[c.tos]; val := 0;
- IF ODD(sel) THEN END; (* give back version number 0 *)
- IF ODD(sel DIV 2) & c.rotated THEN INC(val, 100H) END; (* glyph rotation status *)
- IF ODD(sel DIV 4) & c.stretched THEN INC(val, 200H) END; (* glyph scale status *)
- c.stack[c.tos] := val;
- INC(c.pc)
- END GETINFO;
- (*--- Initialization ---*)
- PROCEDURE InitBuiltins;
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO 0FFH DO Builtin[i] := UNDEF END;
- (* pushing data onto the interpreter stack *)
- Builtin[40H] := NPUSHB; Builtin[41H] := NPUSHW;
- FOR i := 0B0H TO 0B7H DO Builtin[i] := PUSHB END;
- FOR i := 0B8H TO 0BFH DO Builtin[i] := PUSHW END;
- (* managing the storage area *)
- Builtin[43H] := RS; Builtin[42H] := WS;
- (* managing the control value table *)
- Builtin[44H] := WCVT; Builtin[70H] := WCVT; Builtin[45H] := RCVT;
- (* managing the graphics state *)
- Builtin[0] := SVTCA; Builtin[1] := SVTCA;
- Builtin[2] := SPVTCA; Builtin[3] := SPVTCA;
- Builtin[4] := SFVTCA; Builtin[5] := SFVTCA;
- Builtin[6] := SPVTL; Builtin[7] := SPVTL;
- Builtin[8] := SFVTL; Builtin[9] := SFVTL;
- Builtin[0EH] := SFVTPV;
- Builtin[86H] := SDPVTL; Builtin[87H] := SDPVTL;
- Builtin[0AH] := SPVFS; Builtin[0BH] := SFVFS;
- Builtin[0CH] := GPV; Builtin[0DH] := GFV;
- Builtin[10H] := SRPi; Builtin[11H] := SRPi; Builtin[12H] := SRPi;
- Builtin[13H] := SZPi; Builtin[14H] := SZPi; Builtin[15H] := SZPi; Builtin[16H] := SZPS;
- Builtin[19H] := RTHG; Builtin[18H] := RTG; Builtin[3DH] := RTDG; Builtin[7DH] := RDTG; Builtin[7CH] := RUTG;
- Builtin[7AH] := ROFF; Builtin[76H] := SROUND; Builtin[77H] := SROUND;
- Builtin[17H] := SLOOP; Builtin[1AH] := SMD; Builtin[8EH] := INSTCTRL;
- Builtin[85H] := SCANCTRL; Builtin[8DH] := SCANTYPE;
- Builtin[1DH] := SCVTCI; Builtin[1EH] := SSWCI; Builtin[1FH] := SSW;
- Builtin[4DH] := FLIPON; Builtin[4EH] := FLIPOFF;
- Builtin[7EH] := SANGW; Builtin[5EH] := SDB; Builtin[5FH] := SDS;
- (* reading and writing data *)
- Builtin[46H] := GC; Builtin[47H] := GC; Builtin[48H] := SCFS; Builtin[49H] := MD; Builtin[4AH] := MD;
- Builtin[4BH] := MPPEM; Builtin[4CH] := MPS;
- (* managing outlines *)
- Builtin[80H] := FLIPPT; Builtin[81H] := FLIPRG; Builtin[82H] := FLIPRG;
- Builtin[32H] := SHP; Builtin[33H] := SHP; Builtin[34H] := SHC; Builtin[35H] := SHC;
- Builtin[36H] := SHZ; Builtin[37H] := SHZ; Builtin[38H] := SHPIX;
- Builtin[3AH] := MSIRP; Builtin[3BH] := MSIRP; Builtin[2EH] := MDAP; Builtin[2FH] := MDAP;
- Builtin[3EH] := MIAP; Builtin[3FH] := MIAP;
- FOR i := 0C0H TO 0DFH DO Builtin[i] := MDRP END;
- FOR i := 0E0H TO 0FFH DO Builtin[i] := MIRP END;
- Builtin[3CH] := ALIGNRP; Builtin[0FH] := ISECT; Builtin[27H] := ALIGNPTS;
- Builtin[39H] := IP; Builtin[29H] := UTP; Builtin[30H] := IUP; Builtin[31H] := IUP;
- (* managing exceptions *)
- Builtin[5DH] := DELTAP; Builtin[71H] := DELTAP; Builtin[72H] := DELTAP;
- Builtin[73H] := DELTAC; Builtin[74H] := DELTAC; Builtin[75H] := DELTAC;
- (* managing the stack *)
- Builtin[20H] := DUP; Builtin[21H] := POP; Builtin[22H] := CLEAR; Builtin[23H] := SWAP;
- Builtin[24H] := DEPTH; Builtin[25H] := CINDEX; Builtin[26H] := MINDEX; Builtin[8AH] := ROLL;
- (* managing the flow of control *)
- Builtin[58H] := iF; Builtin[1BH] := eLSE; Builtin[59H] := EIF;
- Builtin[78H] := JROT; Builtin[1CH] := JUMPR; Builtin[79H] := JROF;
- (* logical functions *)
- Builtin[50H] := COMPARE; Builtin[51H] := COMPARE; Builtin[52H] := COMPARE;
- Builtin[53H] := COMPARE; Builtin[54H] := COMPARE; Builtin[55H] := COMPARE;
- Builtin[56H] := oDD; Builtin[57H] := EVEN;
- Builtin[5AH] := AND; Builtin[5BH] := oR; Builtin[5CH] := NOT;
- (* arithmetic and math instructions *)
- Builtin[60H] := ADD; Builtin[61H] := SUB; Builtin[62H] := dIV; Builtin[63H] := MUL;
- Builtin[64H] := aBS; Builtin[65H] := NEG; Builtin[66H] := Floor; Builtin[67H] := CEILING;
- Builtin[8BH] := mAX; Builtin[8CH] := mIN;
- (* compensating for the engine characteristics *)
- FOR i := 68H TO 6BH DO Builtin[i] := ROUND END;
- FOR i := 6CH TO 6FH DO Builtin[i] := NROUND END;
- (* defining and using functions and instructions *)
- Builtin[2CH] := FDEF; Builtin[2DH] := ENDF; Builtin[2BH] := CALL; Builtin[2AH] := LOOPCALL; Builtin[89H] := IDEF;
- (* miscellaneous instructions *)
- Builtin[4FH] := DEBUG; Builtin[88H] := GETINFO
- END InitBuiltins;
- (*--- Exported Interface ---*)
- (** allocation procedures for all dynamically sized memory structures **)
- PROCEDURE NewCode* (VAR code: Code; size: LONGINT);
- BEGIN
- IF size > 0 THEN NEW(code, size) ELSE code := NIL END
- END NewCode;
- PROCEDURE NewFunctions* (VAR func: Functions; size: LONGINT);
- BEGIN
- IF size > 0 THEN NEW(func, size) ELSE func := NIL END
- END NewFunctions;
- PROCEDURE NewInstructions* (VAR instr: Instructions; size: LONGINT);
- BEGIN
- IF size > 0 THEN NEW(instr, size) ELSE instr := NIL END
- END NewInstructions;
- PROCEDURE NewStore* (VAR store: Store; size: LONGINT);
- BEGIN
- IF size > 0 THEN NEW(store, size) ELSE store := NIL END
- END NewStore;
- PROCEDURE NewCVT* (VAR cvt: CVT; size: LONGINT);
- BEGIN
- IF size > 0 THEN NEW(cvt, size) ELSE cvt := NIL END
- END NewCVT;
- PROCEDURE NewZone* (VAR zone: Zone; contours, points: INTEGER);
- BEGIN
- NEW(zone); zone.contours := contours;
- NEW(zone.first, contours+1);
- IF points > 0 THEN NEW(zone.pt, points) ELSE zone.pt := NIL END;
- zone.first[contours] := points
- END NewZone;
- (** set context stacks **)
- PROCEDURE SetStacks* (VAR c: Context; stack: Stack; callStack: CallStack);
- BEGIN
- c.stack := stack; c.callStack := callStack
- END SetStacks;
- (** set context structures **)
- PROCEDURE SetStructures* (VAR c: Context; func: Functions; instr: Instructions; store: Store; cvt: CVT);
- BEGIN
- c.func := func; c.instr := instr; c.store := store; c.cvt := cvt
- END SetStructures;
- (** set instance specific context parameters **)
- PROCEDURE SetResolution* (VAR c: Context; ptsize, xppm, yppm: F26D6; upm: INTEGER; rotated, stretched: BOOLEAN);
- BEGIN
- c.ptsize := ptsize; c.xppm := xppm; c.yppm := yppm;
- IF xppm >= yppm THEN
- c.ppm := xppm; c.xratio := 10000H; c.yratio := ShiftDiv(yppm, 10H, xppm)
- ELSE
- c.ppm := yppm; c.xratio := ShiftDiv(xppm, 10H, yppm); c.yratio := 10000H
- END;
- c.upm := upm; c.rotated := rotated; c.stretched := stretched
- END SetResolution;
- (** initialize graphic state default values **)
- PROCEDURE InitState* (VAR c: Context);
- BEGIN
- c.cvtCutIn := 40H * 17 DIV 16;
- c.swCutIn := 0; c.swVal := 0;
- c.minDist := 40H;
- c.deltaBase := 9; c.deltaShift := 3;
- c.autoFlip := TRUE;
- c.inhibitFit := FALSE; c.ignorePrep := FALSE;
- c.fixDropouts := FALSE
- END InitState;
- (** save static part of graphic state (e.g. after executing CVT program) **)
- PROCEDURE SaveState* (VAR c: Context; VAR s: State);
- BEGIN
- s.cvtCutIn := c.cvtCutIn;
- s.swCutIn := c.swCutIn; s.swVal := c.swVal;
- s.minDist := c.minDist;
- s.deltaBase := c.deltaBase; s.deltaShift := c.deltaShift;
- s.autoFlip := c.autoFlip;
- s.inhibitFit := c.inhibitFit; s.ignorePrep := c.ignorePrep;
- s.fixDropouts := c.fixDropouts; s.scanType := c.scanType
- END SaveState;
- (** restore static part of graphic state (e.g. before executing a glyph program) **)
- PROCEDURE RestoreState* (VAR c: Context; VAR s: State);
- BEGIN
- c.cvtCutIn := s.cvtCutIn;
- c.swCutIn := s.swCutIn; c.swVal := s.swVal;
- c.minDist := s.minDist;
- c.deltaBase := s.deltaBase; c.deltaShift := s.deltaShift;
- c.autoFlip := s.autoFlip;
- c.inhibitFit := s.inhibitFit; c.ignorePrep := s.ignorePrep;
- c.fixDropouts := s.fixDropouts; c.scanType := s.scanType
- END RestoreState;
- (** execute program **)
- PROCEDURE Execute* (VAR c: Context; code: Code; len: LONGINT; z0, z1: Zone);
- BEGIN
- c.code := code; c.codeLen := len; c.pc := 0; c.tos := -1; c.ctos := -1;
- c.zone[0] := z0; c.zone[1] := z1;
- c.free.x := 4000H; c.free.y := 0;
- c.proj := c.free; c.proj2 := c.free;
- c.gep0 := 1; c.gep1 := 1; c.gep2 := 1;
- c.zp0 := c.zone[c.gep0]; c.zp1 := c.zone[c.gep1]; c.zp2 := c.zone[c.gep2];
- c.rp0 := 0; c.rp1 := 0; c.rp2 := 0;
- c.period := 40H; c.phase := 0; c.threshold := 20H;
- c.loop := 1;
- c.ratio := 0;
- IF Notify # NIL THEN Notify(c, NotifyData) END;
- WHILE c.pc < c.codeLen DO
- Builtin[ORD(c.code[c.pc])](c) (* call primitive for current instruction *)
- END;
- IF Notify # NIL THEN Notify(c, NotifyData) END
- END Execute;
- (** install notify procedure for debug events **)
- PROCEDURE InstallNotifier* (notify: Notifier; data: NotifierData);
- BEGIN
- Notify := notify; NotifyData := data
- END InstallNotifier;
- BEGIN
- InitBuiltins;
- Zero64[0] := 0X; Zero64[1] := 0X; Zero64[2] := 0X; Zero64[3] := 0X;
- Zero64[4] := 0X; Zero64[5] := 0X; Zero64[6] := 0X; Zero64[7] := 0X;
- NewZone(EmptyZone, 0, 0);
- Notify := NIL; NotifyData := NIL
- END OpenTypeInt.
|