OpenTypeInt.Mod 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097
  1. MODULE OpenTypeInt; (** AUTHOR "eos, PL"; PURPOSE "Bluebottle port of OpenType"; *)
  2. CONST
  3. X* = 1; Y* = 0; (** indices for coordinates into Coord structure **)
  4. StackSize* = 8192;
  5. TYPE
  6. F26D6* = LONGINT; (** fixed point format 26.6 used for fractional pixel coordinates **)
  7. F2D14* = INTEGER; (** fixed point format 2.14 used for unit vectors **)
  8. FUnit* = INTEGER; (** unscaled point coordinates **)
  9. Fixed* = LONGINT; (** fixed point format 16.16 used for scalar fixed point numbers **)
  10. INT64 = ARRAY 8 OF CHAR; (* huge integers for extended precision arithmetic *)
  11. (** program code **)
  12. Code* = POINTER TO ARRAY OF CHAR;
  13. (** program stack **)
  14. Stack* = ARRAY StackSize OF LONGINT;
  15. (** addresses within code blocks **)
  16. Address* = RECORD
  17. code*: Code; (** instruction sequence **)
  18. len*: LONGINT; (** code length **)
  19. pc*: LONGINT; (** location within code **)
  20. END;
  21. (** user defined functions **)
  22. Functions* = POINTER TO ARRAY OF Address;
  23. (** user defined instructions **)
  24. Instruction* = RECORD
  25. beg*: Address; (* starting point *)
  26. opcode*: CHAR; (* instruction opcode *)
  27. END;
  28. Instructions* = POINTER TO ARRAY OF Instruction;
  29. (** call stack **)
  30. Frame* = RECORD
  31. ret*: Address; (* return address *)
  32. start*: LONGINT; (* starting pc of function (within context.code) *)
  33. count*: INTEGER; (* number of times the function has to be evaluated *)
  34. END;
  35. CallStack* = ARRAY 32 OF Frame;
  36. (** program store **)
  37. Store* = POINTER TO ARRAY OF LONGINT;
  38. (** control value table **)
  39. CVT* = POINTER TO ARRAY OF F26D6;
  40. (** glyph zone **)
  41. Contours* = POINTER TO ARRAY OF INTEGER;
  42. Coord* = ARRAY 2 OF F26D6;
  43. Point* = RECORD
  44. org*, cur*: Coord; (** original and current point coordinates **)
  45. onCurve*: BOOLEAN; (** is point on or off the curve? **)
  46. touched*: ARRAY 2 OF BOOLEAN; (** is point touched in x/y direction? **)
  47. END;
  48. Points* = POINTER TO ARRAY OF Point;
  49. Zone* = POINTER TO ZoneDesc;
  50. ZoneDesc* = RECORD
  51. contours*: INTEGER; (** number of contours in this zone **)
  52. first*: Contours; (** starting points of each contour; first[contours] contains total number of points in zone **)
  53. pt*: Points; (** points in this zone **)
  54. END;
  55. (** unit vector **)
  56. Vector* = RECORD
  57. x*, y*: F2D14;
  58. END;
  59. (** execution context **)
  60. Context* = RECORD
  61. code*: Code; (** program code **)
  62. codeLen*: LONGINT; (* code length *)
  63. stack*: Stack; (** program stack **)
  64. callStack*: CallStack; (** call stack of program **)
  65. pc*: LONGINT; (* current position within code *)
  66. tos*: INTEGER; (* stack pointer *)
  67. ctos*: INTEGER; (* call stack pointer *)
  68. func*: Functions; (** user defined functions **)
  69. instr*: Instructions; (** user defined instructions **)
  70. store*: Store; (** program store **)
  71. cvt*: CVT; (** control value table **)
  72. zone*: ARRAY 2 OF Zone; (** twilight and glyph zone **)
  73. ptsize*: F26D6; (** current point size **)
  74. xppm*, yppm*, ppm: F26D6; (** number of pixels per Em in x/y direction **)
  75. upm*: INTEGER; (** units per Em **)
  76. rotated*, stretched*: BOOLEAN; (* glyph transformation info *)
  77. xratio, yratio, ratio*: Fixed; (** aspect ratio **)
  78. minDist*: F26D6; (** feature preserving minimum distance **)
  79. cvtCutIn*: F26D6; (** control value table cut in **)
  80. swVal*, swCutIn*: F26D6; (** single width cut in and single width value **)
  81. deltaBase*, deltaShift*: INTEGER; (** delta exception parameters **)
  82. autoFlip*: BOOLEAN; (** whether to make CVT entries sign independent **)
  83. inhibitFit*, ignorePrep*: BOOLEAN; (** instruction control flags **)
  84. fixDropouts*: BOOLEAN; (** scan control flag **)
  85. scanType*: INTEGER; (** current scan type **)
  86. rp0*, rp1*, rp2*: INTEGER; (** reference points **)
  87. gep0*, gep1*, gep2*: INTEGER; (** zone indices **)
  88. zp0, zp1, zp2: Zone; (* zone pointers, equal to zone[gepN] *)
  89. free*, proj*, proj2*: Vector; (** freedom vector, projection vector, and dual projection vector **)
  90. period*, phase*, threshold*: F26D6; (** parameters of current round state **)
  91. loop*: INTEGER; (** number of times to execute the next loop-aware instruction **)
  92. END;
  93. (** static part of graphics state **)
  94. State* = RECORD
  95. minDist: F26D6;
  96. cvtCutIn: F26D6;
  97. swVal, swCutIn: F26D6;
  98. deltaBase, deltaShift: INTEGER;
  99. autoFlip: BOOLEAN;
  100. inhibitFit, ignorePrep: BOOLEAN;
  101. fixDropouts: BOOLEAN;
  102. scanType: INTEGER;
  103. END;
  104. (** debug upcalls **)
  105. NotifierData* = POINTER TO NotifierDesc;
  106. NotifierDesc* = RECORD END;
  107. Notifier* = PROCEDURE (VAR c: Context; data: NotifierData);
  108. Primitive = PROCEDURE (VAR c: Context);
  109. VAR
  110. EmptyZone*: Zone; (** zone containing zero contours and zero points **)
  111. Builtin: ARRAY 256 OF Primitive; (* instruction for each opcode *)
  112. Zero64: INT64;
  113. Notify: Notifier;
  114. NotifyData: NotifierData;
  115. (*--- 64bit Arithmetic ---*)
  116. PROCEDURE ToINT64 (x: LONGINT; VAR y: INT64);
  117. BEGIN
  118. y[0] := CHR(x MOD 100H);
  119. y[1] := CHR(ASH(x, -8) MOD 100H);
  120. y[2] := CHR(ASH(x, -16) MOD 100H);
  121. y[3] := CHR(ASH(x, -24) MOD 100H);
  122. y[4] := CHR(ASH(x, -31) MOD 100H);
  123. y[5] := y[4]; y[6] := y[4]; y[7] := y[4]
  124. END ToINT64;
  125. PROCEDURE FromINT64 (x: INT64; VAR y: LONGINT);
  126. BEGIN
  127. y := ASH(ORD(x[3]), 24) + ASH(ORD(x[2]), 16) + ASH(ORD(x[1]), 8) + ORD(x[0])
  128. END FromINT64;
  129. PROCEDURE AddINT64 (a, b: INT64; VAR c: INT64);
  130. VAR sum, i: LONGINT;
  131. BEGIN
  132. sum := 0;
  133. FOR i := 0 TO 7 DO
  134. sum := ORD(a[i]) + ORD(b[i]) + ASH(sum, -8) MOD 100H;
  135. c[i] := CHR(sum MOD 100H)
  136. END
  137. END AddINT64;
  138. PROCEDURE SubINT64 (a, b: INT64; VAR c: INT64);
  139. VAR sum, i: LONGINT;
  140. BEGIN
  141. sum := 256;
  142. FOR i := 0 TO 7 DO
  143. sum := 255 + ORD(a[i]) - ORD(b[i]) + ASH(sum, -8) MOD 100H;
  144. c[i] := CHR(sum MOD 100H)
  145. END
  146. END SubINT64;
  147. PROCEDURE LeqINT64 (a, b: INT64): BOOLEAN;
  148. VAR i: LONGINT;
  149. BEGIN
  150. IF (a[7] >= 80X) & (b[7] < 80X) THEN
  151. RETURN TRUE
  152. ELSIF (a[7] < 80X) & (b[7] >= 80X) THEN
  153. RETURN FALSE
  154. ELSE
  155. FOR i := 7 TO 0 BY -1 DO
  156. IF a[i] < b[i] THEN RETURN TRUE
  157. ELSIF a[i] > b[i] THEN RETURN FALSE
  158. END
  159. END;
  160. RETURN TRUE (* equal *)
  161. END
  162. END LeqINT64;
  163. PROCEDURE ShiftINT64 (VAR a: INT64; n: LONGINT);
  164. VAR c, i, j, b: LONGINT;
  165. BEGIN
  166. c := 0;
  167. IF n > 0 THEN
  168. n := n MOD 64;
  169. i := 7; j := 7 - n DIV 8; n := n MOD 8;
  170. c := ASH(ORD(a[j]), n) MOD 100H;
  171. WHILE j > 0 DO
  172. DEC(j); b := ORD(a[j]);
  173. a[i] := CHR(c + ASH(b, n-8)); DEC(i);
  174. c := ASH(b, n) MOD 100H
  175. END;
  176. WHILE i >= 0 DO
  177. a[i] := CHR(c); c := 0; DEC(i)
  178. END
  179. ELSIF n < 0 THEN
  180. n := (-n) MOD 64;
  181. i := 0; j := n DIV 8; n := n MOD 8;
  182. c := ASH(ORD(a[j]), -n);
  183. WHILE j < 7 DO
  184. INC(j); b := ORD(a[j]);
  185. a[i] := CHR(c + ASH(b, 8-n) MOD 100H); INC(i);
  186. c := ASH(b, -n)
  187. END;
  188. WHILE i < 8 DO
  189. a[i] := CHR(c); c := ASH(c, -8); INC(i)
  190. END
  191. END
  192. END ShiftINT64;
  193. PROCEDURE MulINT64 (a, b: INT64; VAR c: INT64);
  194. VAR i, sum, j: LONGINT;
  195. BEGIN
  196. FOR i := 0 TO 7 DO c[i] := 0X END;
  197. FOR i := 0 TO 7 DO
  198. sum := 0;
  199. FOR j := 0 TO 7-i DO
  200. sum := LONG(ORD(a[i])) * LONG(ORD(b[j])) + ASH(sum, -8) MOD 100H + ORD(c[i+j]);
  201. c[i+j] := CHR(sum MOD 100H)
  202. END
  203. END
  204. END MulINT64;
  205. PROCEDURE DivINT64 (a, b: INT64; VAR q: INT64);
  206. VAR positive: BOOLEAN; i: LONGINT; e: INT64;
  207. BEGIN
  208. positive := TRUE;
  209. IF ~LeqINT64(Zero64, a) THEN positive := ~positive; SubINT64(Zero64, a, a) END;
  210. IF ~LeqINT64(Zero64, b) THEN positive := ~positive; SubINT64(Zero64, b, b) END;
  211. FOR i := 0 TO 7 DO q[i] := 0X; e[i] := 0X END; e[0] := 1X;
  212. ShiftINT64(b, 32);
  213. i := 0;
  214. REPEAT
  215. ShiftINT64(q, 1); ShiftINT64(b, -1);
  216. IF LeqINT64(b, a) THEN
  217. SubINT64(a, b, a); AddINT64(q, e, q)
  218. END;
  219. INC(i)
  220. UNTIL i = 32;
  221. IF ~positive THEN SubINT64(Zero64, q, q) END
  222. END DivINT64;
  223. (**--- Arithmetic ---**)
  224. PROCEDURE ShiftDiv* (a, n, d: LONGINT): LONGINT;
  225. VAR b, r: LONGINT; a64, d64, h64: INT64;
  226. BEGIN
  227. b := ASH(1, 31-n);
  228. IF (-b <= a) & (a < b) THEN
  229. r := (ASH(a, n) + d DIV 2) DIV d
  230. ELSE
  231. ToINT64(a, a64); ShiftINT64(a64, n);
  232. ToINT64(d, d64); h64 := d64; ShiftINT64(h64, -1);
  233. AddINT64(a64, h64, a64);
  234. DivINT64(a64, d64, a64);
  235. FromINT64(a64, r)
  236. END;
  237. RETURN r
  238. END ShiftDiv;
  239. PROCEDURE MulShift* (a, b, n: LONGINT): LONGINT;
  240. VAR a64, b64, c64: INT64; c: LONGINT;
  241. BEGIN
  242. IF (-10000H <= a) & (a < 10000H) & (-8000H <= b) & (b < 8000H) THEN
  243. RETURN ASH(a * b, n)
  244. ELSE
  245. ToINT64(a, a64); ToINT64(b, b64);
  246. MulINT64(a64, b64, c64); ShiftINT64(c64, n);
  247. FromINT64(c64, c);
  248. RETURN c
  249. END
  250. END MulShift;
  251. PROCEDURE MulDiv* (a, b, c: LONGINT): LONGINT;
  252. VAR a64, b64, m64, c64, d64: INT64; d: LONGINT;
  253. BEGIN
  254. IF (-10000H <= a) & (a < 10000H) & (-8000H <= b) & (b < 8000H) THEN
  255. IF c > 0 THEN
  256. RETURN (a * b + c DIV 2) DIV c
  257. ELSIF c < 0 THEN
  258. c := -c;
  259. RETURN -((a * b + c DIV 2) DIV c)
  260. ELSE
  261. RETURN 0; (* division by zero -- gracefully ignored ... *)
  262. HALT(100); (* a trap is an inacceptable behavior during system startup (e.g. if the font is too small ..) *)
  263. END
  264. ELSE
  265. ToINT64(a, a64); ToINT64(b, b64);
  266. MulINT64(a64, b64, m64);
  267. ToINT64(c, c64); DivINT64(m64, c64, d64);
  268. FromINT64(d64, d);
  269. RETURN d
  270. END
  271. END MulDiv;
  272. PROCEDURE Norm* (x, y: F26D6): F26D6;
  273. VAR n, r, b, t, i: LONGINT; x64, y64, n64, r64, b64, t64: INT64;
  274. BEGIN
  275. IF (-8000H <= x) & (x < 8000H) & (-8000H <= y) & (y < 8000H) THEN (* x*x + y*y representable in 32 bits *)
  276. n := x * x + y * y;
  277. r := 0; b := 40000000H;
  278. REPEAT
  279. t := r + b;
  280. IF t <= n THEN
  281. DEC(n, t);
  282. r := t + b
  283. END;
  284. r := r DIV 2; b := b DIV 4
  285. UNTIL b = 0
  286. ELSE
  287. ToINT64(x, x64); ToINT64(y, y64);
  288. MulINT64(x64, x64, x64); MulINT64(y64, y64, y64);
  289. AddINT64(x64, y64, n64);
  290. FOR i := 0 TO 7 DO r64[i] := 0X; b64[i] := 0X END; b64[7] := 40X;
  291. REPEAT
  292. AddINT64(r64, b64, t64);
  293. IF LeqINT64(t64, n64) THEN
  294. SubINT64(n64, t64, n64);
  295. AddINT64(t64, b64, r64)
  296. END;
  297. ShiftINT64(r64, -1); ShiftINT64(b64, -2);
  298. i := 0; WHILE (i < 8) & (b64[i] = 0X) DO INC(i) END
  299. UNTIL i = 8;
  300. FromINT64(r64, r)
  301. END;
  302. RETURN r
  303. END Norm;
  304. (*--- Auxiliary Routines ---*)
  305. PROCEDURE Ratio (VAR c: Context): Fixed;
  306. VAR x, y: Fixed;
  307. BEGIN
  308. IF c.ratio = 0 THEN
  309. IF c.proj.y = 0 THEN
  310. c.ratio := c.xratio
  311. ELSIF c.proj.x = 0 THEN
  312. c.ratio := c.yratio
  313. ELSE
  314. x := ASH(c.proj.x * c.xratio, -14);
  315. y := ASH(c.proj.y * c.yratio, -14);
  316. c.ratio := Norm(x, y)
  317. END
  318. END;
  319. RETURN c.ratio
  320. END Ratio;
  321. PROCEDURE PPEm (VAR c: Context): F26D6;
  322. BEGIN
  323. RETURN MulShift(c.ppm, Ratio(c), -16)
  324. END PPEm;
  325. PROCEDURE FUnitToPixel (fu: FUnit; VAR c: Context): F26D6;
  326. BEGIN
  327. RETURN (LONG(fu) * PPEm(c) + c.upm DIV 2) DIV c.upm
  328. END FUnitToPixel;
  329. PROCEDURE CVTValue (n: LONGINT; VAR c: Context): F26D6;
  330. VAR ratio: F26D6;
  331. BEGIN
  332. IF n < 0 THEN
  333. RETURN 0 (* some fonts use CVT[-1]; FreeType and TTI return 0, too *)
  334. ELSE
  335. ratio := Ratio(c);
  336. IF ratio = 10000H THEN RETURN c.cvt[n]
  337. ELSE RETURN MulShift(c.cvt[n], ratio, -16)
  338. END
  339. END
  340. END CVTValue;
  341. PROCEDURE Round (x, period, phase, threshold: F26D6): F26D6;
  342. VAR sign: F26D6;
  343. BEGIN
  344. sign := x; x := ABS(x);
  345. x := x - phase + threshold;
  346. x := x - x MOD period + phase;
  347. IF x < 0 THEN INC(x, period) END;
  348. IF sign < 0 THEN x := -x END;
  349. RETURN x
  350. END Round;
  351. PROCEDURE Project (crd: Coord; proj: Vector): F26D6;
  352. BEGIN
  353. RETURN MulShift(crd[X], proj.x, -14) + MulShift(crd[Y], proj.y, -14) (* dot product of point and unit vector *)
  354. END Project;
  355. PROCEDURE GetDistance (from, to: Coord; VAR dx, dy: F26D6);
  356. BEGIN
  357. dx := to[X] - from[X]; dy := to[Y] - from[Y]
  358. END GetDistance;
  359. PROCEDURE Move (VAR p: Point; free, proj: Vector; dist: F26D6);
  360. VAR dot: LONGINT;
  361. BEGIN
  362. IF proj.x = 4000H THEN
  363. IF free.x # 0 THEN
  364. INC(p.cur[X], dist); p.touched[X] := TRUE;
  365. IF free.x # 4000H THEN
  366. INC(p.cur[Y], MulDiv(free.y, dist, free.x)); p.touched[Y] := TRUE
  367. END
  368. END
  369. ELSIF proj.y = 4000H THEN
  370. IF free.y # 0 THEN
  371. INC(p.cur[Y], dist); p.touched[Y] := TRUE;
  372. IF free.y # 4000H THEN
  373. INC(p.cur[X], MulDiv(free.x, dist, free.y)); p.touched[X] := TRUE
  374. END
  375. END
  376. ELSE
  377. dot := LONG(proj.x) * LONG(free.x) + LONG(proj.y) * LONG(free.y);
  378. INC(p.cur[X], MulDiv(4000H*LONG(free.x), dist, dot)); p.touched[X] := TRUE;
  379. INC(p.cur[Y], MulDiv(4000H*LONG(free.y), dist, dot)); p.touched[Y] := TRUE
  380. END
  381. END Move;
  382. PROCEDURE GetRefDist (VAR c: Context; flag: BOOLEAN; VAR zone: Zone; VAR ref: LONGINT; VAR dx, dy: F26D6);
  383. VAR dot: LONGINT; dist: F26D6;
  384. BEGIN
  385. IF flag THEN (* rp1 in zp0 *)
  386. ref := c.rp1; zone := c.zp0
  387. ELSE (* use rp2 in zp1 *)
  388. ref := c.rp2; zone := c.zp1
  389. END;
  390. dist := Project(zone.pt[ref].cur, c.proj) - Project(zone.pt[ref].org, c.proj);
  391. dot := LONG(c.proj.x) * LONG(c.free.x) + LONG(c.proj.y) * LONG(c.free.y);
  392. IF dot # 0 THEN
  393. IF (c.free.x # 0) & (c.free.y # 0) THEN
  394. dx := MulDiv(c.free.x, dist, dot);
  395. dy := MulDiv(c.free.y, dist, dot)
  396. ELSIF c.free.x # 0 THEN
  397. dx := dist; dy := 0
  398. ELSIF c.free.y # 0 THEN
  399. dy := dist; dx := 0
  400. END
  401. ELSE
  402. dx := 0; dy := 0
  403. END
  404. END GetRefDist;
  405. (*--- Pushing Data onto the Interpreter Stack ---*)
  406. (* push n bytes *)
  407. PROCEDURE NPUSHB (VAR c: Context);
  408. VAR n: LONGINT;
  409. BEGIN
  410. INC(c.pc); n := ORD(c.code[c.pc]);
  411. WHILE n > 0 DO
  412. INC(c.pc); INC(c.tos); c.stack[c.tos] := ORD(c.code[c.pc]);
  413. DEC(n)
  414. END;
  415. INC(c.pc)
  416. END NPUSHB;
  417. (* push n words *)
  418. PROCEDURE NPUSHW (VAR c: Context);
  419. VAR n, hi, lo: LONGINT;
  420. BEGIN
  421. INC(c.pc); n := ORD(c.code[c.pc]);
  422. WHILE n > 0 DO
  423. INC(c.pc); hi := ORD(c.code[c.pc]);
  424. IF hi >= 128 THEN DEC(hi, 256) END;
  425. INC(c.pc); lo := ORD(c.code[c.pc]);
  426. INC(c.tos); c.stack[c.tos] := 256*hi + lo;
  427. DEC(n)
  428. END;
  429. INC(c.pc)
  430. END NPUSHW;
  431. (* push bytes *)
  432. PROCEDURE PUSHB (VAR c: Context);
  433. VAR n: LONGINT;
  434. BEGIN
  435. n := ORD(c.code[c.pc]) - 0B0H;
  436. WHILE n >= 0 DO
  437. INC(c.pc); INC(c.tos); c.stack[c.tos] := ORD(c.code[c.pc]);
  438. DEC(n)
  439. END;
  440. INC(c.pc)
  441. END PUSHB;
  442. (* push words *)
  443. PROCEDURE PUSHW (VAR c: Context);
  444. VAR n, hi, lo: LONGINT;
  445. BEGIN
  446. n := ORD(c.code[c.pc]) - 0B8H;
  447. WHILE n >= 0 DO
  448. INC(c.pc); hi := ORD(c.code[c.pc]);
  449. IF hi >= 128 THEN DEC(hi, 256) END;
  450. INC(c.pc); lo := ORD(c.code[c.pc]);
  451. INC(c.tos); c.stack[c.tos] := 256*hi + lo;
  452. DEC(n)
  453. END;
  454. INC(c.pc)
  455. END PUSHW;
  456. (*--- Managing the Storage Area ---*)
  457. (* read store *)
  458. PROCEDURE RS (VAR c: Context);
  459. BEGIN
  460. c.stack[c.tos] := c.store[c.stack[c.tos]]; INC(c.pc)
  461. END RS;
  462. (* write store *)
  463. PROCEDURE WS (VAR c: Context);
  464. VAR value: LONGINT;
  465. BEGIN
  466. value := c.stack[c.tos]; DEC(c.tos);
  467. c.store[c.stack[c.tos]] := value; DEC(c.tos);
  468. INC(c.pc)
  469. END WS;
  470. (*--- Managing the Control Value Table ---*)
  471. (* write control value table in pixels or FUnits *)
  472. PROCEDURE WCVT (VAR c: Context);
  473. VAR value: F26D6;
  474. BEGIN
  475. value := c.stack[c.tos]; DEC(c.tos);
  476. IF c.code[c.pc] = 70X THEN
  477. value := FUnitToPixel(SHORT(value), c)
  478. END;
  479. c.cvt[c.stack[c.tos]] := ShiftDiv(value, 16, Ratio(c)); DEC(c.tos);
  480. INC(c.pc)
  481. END WCVT;
  482. (* read control value table *)
  483. PROCEDURE RCVT (VAR c: Context);
  484. BEGIN
  485. c.stack[c.tos] := CVTValue(c.stack[c.tos], c); INC(c.pc)
  486. END RCVT;
  487. (*--- Managing the Graphics State ---*)
  488. (* set freedom and projection vectors to coordinate axis *)
  489. PROCEDURE SVTCA (VAR c: Context);
  490. BEGIN
  491. IF ODD(ORD(c.code[c.pc])) THEN (* set to x-axis *)
  492. c.proj.x := 4000H; c.proj.y := 0
  493. ELSE (* set to y-axis *)
  494. c.proj.x := 0; c.proj.y := 4000H
  495. END;
  496. c.free := c.proj; c.proj2 := c.proj;
  497. c.ratio := 0;
  498. INC(c.pc)
  499. END SVTCA;
  500. (* set projection vector to coordinate axis *)
  501. PROCEDURE SPVTCA (VAR c: Context);
  502. BEGIN
  503. IF ODD(ORD(c.code[c.pc])) THEN (* set to x-axis *)
  504. c.proj.x := 4000H; c.proj.y := 0
  505. ELSE (* set to y-axis *)
  506. c.proj.x := 0; c.proj.y := 4000H
  507. END;
  508. c.proj2 := c.proj;
  509. c.ratio := 0;
  510. INC(c.pc)
  511. END SPVTCA;
  512. (* set freedom vector to coordinate axis *)
  513. PROCEDURE SFVTCA (VAR c: Context);
  514. BEGIN
  515. IF ODD(ORD(c.code[c.pc])) THEN (* set to x-axis *)
  516. c.free.x := 4000H; c.free.y := 0
  517. ELSE (* set to y-axis *)
  518. c.free.x := 0; c.free.y := 4000H
  519. END;
  520. INC(c.pc)
  521. END SFVTCA;
  522. (* set projection vector to line *)
  523. PROCEDURE SPVTL (VAR c: Context);
  524. VAR p1, p2: LONGINT; dx, dy, d: F26D6;
  525. BEGIN
  526. p1 := c.stack[c.tos]; DEC(c.tos);
  527. p2 := c.stack[c.tos]; DEC(c.tos);
  528. GetDistance(c.zp2.pt[p1].cur, c.zp1.pt[p2].cur, dx, dy); (* note: TTI had zp1 and zp2 swapped *)
  529. d := Norm(dx, dy);
  530. IF d = 0 THEN
  531. dx := 0; dy := 0
  532. ELSE
  533. dx := ShiftDiv(dx, 14, d);
  534. dy := ShiftDiv(dy, 14, d)
  535. END;
  536. IF ODD(ORD(c.code[c.pc])) THEN (* rotate by 90 degrees *)
  537. c.proj.x := SHORT(-dy); c.proj.y := SHORT(dx)
  538. ELSE
  539. c.proj.x := SHORT(dx); c.proj.y := SHORT(dy)
  540. END;
  541. c.proj2 := c.proj;
  542. c.ratio := 0;
  543. INC(c.pc)
  544. END SPVTL;
  545. (* set freedom vector to line *)
  546. PROCEDURE SFVTL (VAR c: Context);
  547. VAR p1, p2: LONGINT; dx, dy, d: F26D6;
  548. BEGIN
  549. p1 := c.stack[c.tos]; DEC(c.tos);
  550. p2 := c.stack[c.tos]; DEC(c.tos);
  551. GetDistance(c.zp2.pt[p1].cur, c.zp1.pt[p2].cur, dx, dy); (* note: TTI had zp1 and zp2 swapped *)
  552. d := Norm(dx, dy);
  553. IF d = 0 THEN
  554. dx := 0; dy := 0
  555. ELSE
  556. dx := ShiftDiv(dx, 14, d);
  557. dy := ShiftDiv(dy, 14, d)
  558. END;
  559. IF ODD(ORD(c.code[c.pc])) THEN (* rotate by 90 degrees *)
  560. c.free.x := SHORT(-dy); c.free.y := SHORT(dx)
  561. ELSE
  562. c.free.x := SHORT(dx); c.free.y := SHORT(dy)
  563. END;
  564. INC(c.pc)
  565. END SFVTL;
  566. (* set freedom vector to projection vector *)
  567. PROCEDURE SFVTPV (VAR c: Context);
  568. BEGIN
  569. c.free := c.proj; INC(c.pc)
  570. END SFVTPV;
  571. (* set dual projection vector to line *)
  572. PROCEDURE SDPVTL (VAR c: Context);
  573. VAR p1, p2: LONGINT; dx, dy, d: F26D6;
  574. BEGIN
  575. p1 := c.stack[c.tos]; DEC(c.tos);
  576. p2 := c.stack[c.tos]; DEC(c.tos);
  577. GetDistance(c.zp2.pt[p1].org, c.zp1.pt[p2].org, dx, dy); (* note: TTI had zp1 and zp2 swapped *)
  578. d := Norm(dx, dy);
  579. dx := ShiftDiv(dx, 14, d);
  580. dy := ShiftDiv(dy, 14, d);
  581. IF ODD(ORD(c.code[c.pc])) THEN (* rotate by 90 degrees *)
  582. c.proj2.x := SHORT(-dy); c.proj2.y := SHORT(dx)
  583. ELSE
  584. c.proj2.x := SHORT(dx); c.proj2.y := SHORT(dy)
  585. END;
  586. (* projection vector must be set as well, but with current coordinates (FreeType agrees on this) *)
  587. GetDistance(c.zp2.pt[p1].cur, c.zp1.pt[p2].cur, dx, dy); (* note: TTI had zp1 and zp2 swapped *)
  588. d := Norm(dx, dy);
  589. dx := ShiftDiv(dx, 14, d);
  590. dy := ShiftDiv(dy, 14, d);
  591. IF ODD(ORD(c.code[c.pc])) THEN (* rotate by 90 degrees *)
  592. c.proj.x := SHORT(-dy); c.proj.y := SHORT(dx)
  593. ELSE
  594. c.proj.x := SHORT(dx); c.proj.y := SHORT(dy)
  595. END;
  596. c.ratio := 0;
  597. INC(c.pc)
  598. END SDPVTL;
  599. (* set projection vector from stack *)
  600. PROCEDURE SPVFS (VAR c: Context);
  601. BEGIN
  602. c.proj.y := SHORT(c.stack[c.tos]); DEC(c.tos);
  603. c.proj.x := SHORT(c.stack[c.tos]); DEC(c.tos);
  604. c.proj2 := c.proj;
  605. c.ratio := 0;
  606. INC(c.pc)
  607. END SPVFS;
  608. (* set freedom vector from stack *)
  609. PROCEDURE SFVFS (VAR c: Context);
  610. BEGIN
  611. c.free.y := SHORT(c.stack[c.tos]); DEC(c.tos);
  612. c.free.x := SHORT(c.stack[c.tos]); DEC(c.tos);
  613. INC(c.pc)
  614. END SFVFS;
  615. (* get projection vector *)
  616. PROCEDURE GPV (VAR c: Context);
  617. BEGIN
  618. INC(c.tos); c.stack[c.tos] := c.proj.x;
  619. INC(c.tos); c.stack[c.tos] := c.proj.y;
  620. INC(c.pc)
  621. END GPV;
  622. (* get freedom vector *)
  623. PROCEDURE GFV (VAR c: Context);
  624. BEGIN
  625. INC(c.tos); c.stack[c.tos] := c.free.x;
  626. INC(c.tos); c.stack[c.tos] := c.free.y;
  627. INC(c.pc)
  628. END GFV;
  629. (* set reference point i *)
  630. PROCEDURE SRPi (VAR c: Context);
  631. VAR rp: INTEGER;
  632. BEGIN
  633. rp := SHORT(c.stack[c.tos]); DEC(c.tos);
  634. CASE c.code[c.pc] OF
  635. | 10X: c.rp0 := rp
  636. | 11X: c.rp1 := rp
  637. | 12X: c.rp2 := rp
  638. END;
  639. INC(c.pc)
  640. END SRPi;
  641. (* set zone pointer i *)
  642. PROCEDURE SZPi (VAR c: Context);
  643. VAR gep: INTEGER;
  644. BEGIN
  645. gep := SHORT(c.stack[c.tos]); DEC(c.tos);
  646. CASE c.code[c.pc] OF
  647. | 13X: c.gep0 := gep; c.zp0 := c.zone[gep]
  648. | 14X: c.gep1 := gep; c.zp1 := c.zone[gep]
  649. | 15X: c.gep2 := gep; c.zp2 := c.zone[gep]
  650. END;
  651. INC(c.pc)
  652. END SZPi;
  653. (* set zone pointers *)
  654. PROCEDURE SZPS (VAR c: Context);
  655. BEGIN
  656. c.gep0 := SHORT(c.stack[c.tos]); DEC(c.tos); c.gep1 := c.gep0; c.gep2 := c.gep2;
  657. c.zp0 := c.zone[c.gep0]; c.zp1 := c.zp0; c.zp2 := c.zp0;
  658. INC(c.pc)
  659. END SZPS;
  660. (* round to half grid *)
  661. PROCEDURE RTHG (VAR c: Context);
  662. BEGIN
  663. c.period := 40H; c.phase := 20H; c.threshold := 20H; INC(c.pc)
  664. END RTHG;
  665. (* round to grid *)
  666. PROCEDURE RTG (VAR c: Context);
  667. BEGIN
  668. c.period := 40H; c.phase := 0; c.threshold := 20H; INC(c.pc)
  669. END RTG;
  670. (* round to double grid *)
  671. PROCEDURE RTDG (VAR c: Context);
  672. BEGIN
  673. c.period := 20H; c.phase := 0; c.threshold := 10H; INC(c.pc)
  674. END RTDG;
  675. (* round down to grid *)
  676. PROCEDURE RDTG (VAR c: Context);
  677. BEGIN
  678. c.period := 40H; c.phase := 0; c.threshold := 0; INC(c.pc)
  679. END RDTG;
  680. (* round up to grid *)
  681. PROCEDURE RUTG (VAR c: Context);
  682. BEGIN
  683. c.period := 40H; c.phase := 0; c.threshold := 3FH; INC(c.pc)
  684. END RUTG;
  685. (* round off *)
  686. PROCEDURE ROFF (VAR c: Context);
  687. BEGIN
  688. c.period := 1; c.phase := 0; c.threshold := 0; INC(c.pc)
  689. END ROFF;
  690. (* super round and super round 45 degrees *)
  691. PROCEDURE SROUND (VAR c: Context);
  692. VAR gridPeriod: F26D6; code, cd: LONGINT;
  693. BEGIN
  694. IF ODD(ORD(c.code[c.pc])) THEN (* super round 45 degrees *)
  695. gridPeriod := 45 (* funnily enough, this is really 64*(1/sqrt(2)) *)
  696. ELSE
  697. gridPeriod := 64
  698. END;
  699. code := c.stack[c.tos]; DEC(c.tos);
  700. cd := ASH(code, -6) MOD 4;
  701. CASE cd OF
  702. | 0: c.period := gridPeriod DIV 2
  703. | 1: c.period := gridPeriod
  704. | 2: c.period := 2*gridPeriod
  705. END;
  706. cd := ASH(code, -4) MOD 2;
  707. c.phase := cd * c.period DIV 4;
  708. cd := code MOD 16;
  709. IF cd = 0 THEN
  710. c.threshold := c.period-1
  711. ELSE
  712. c.threshold := c.period * (cd-4) DIV 8
  713. END;
  714. INC(c.pc)
  715. END SROUND;
  716. (* set loop variable *)
  717. PROCEDURE SLOOP (VAR c: Context);
  718. BEGIN
  719. c.loop := SHORT(c.stack[c.tos]); DEC(c.tos); INC(c.pc);
  720. IF c.loop = 0 THEN (* ERROR, stop execution *)
  721. c.pc := c.codeLen;
  722. END;
  723. END SLOOP;
  724. (* set minimum distance *)
  725. PROCEDURE SMD (VAR c: Context);
  726. BEGIN
  727. c.minDist := c.stack[c.tos]; DEC(c.tos); INC(c.pc)
  728. END SMD;
  729. (* instruction execution control *)
  730. PROCEDURE INSTCTRL (VAR c: Context);
  731. VAR sel, val: LONGINT;
  732. BEGIN
  733. sel := c.stack[c.tos]; DEC(c.tos);
  734. IF sel = 1 THEN c.inhibitFit := FALSE
  735. ELSIF sel = 2 THEN c.ignorePrep := FALSE
  736. END;
  737. val := c.stack[c.tos]; DEC(c.tos);
  738. IF val # 0 THEN val := sel END;
  739. IF val = 1 THEN c.inhibitFit := TRUE
  740. ELSIF val = 2 THEN c.ignorePrep := TRUE
  741. END;
  742. INC(c.pc)
  743. END INSTCTRL;
  744. (* scan conversion control *)
  745. PROCEDURE SCANCTRL (VAR c: Context);
  746. VAR n, thold: LONGINT;
  747. BEGIN
  748. n := c.stack[c.tos] MOD 10000H; DEC(c.tos);
  749. thold := n MOD 256;
  750. IF thold = 0FFH THEN
  751. c.fixDropouts := TRUE
  752. ELSIF thold = 0 THEN
  753. c.fixDropouts := FALSE
  754. ELSE
  755. (* should there be a default value in case no condition holds? FreeType doesn't have one *)
  756. thold := 40H * thold;
  757. IF ODD(n DIV 100H) & (PPEm(c) <= thold) THEN c.fixDropouts := TRUE END;
  758. IF ODD(n DIV 200H) & c.rotated THEN c.fixDropouts := TRUE END;
  759. IF ODD(n DIV 400H) & c.stretched THEN c.fixDropouts := TRUE END;
  760. IF ODD(n DIV 800H) & (PPEm(c) > thold) THEN c.fixDropouts := FALSE END;
  761. IF ODD(n DIV 1000H) & ~c.rotated THEN c.fixDropouts := FALSE END;
  762. IF ODD(n DIV 2000H) & ~c.stretched THEN c.fixDropouts := FALSE END
  763. END;
  764. INC(c.pc)
  765. END SCANCTRL;
  766. (* scan type *)
  767. PROCEDURE SCANTYPE (VAR c: Context);
  768. VAR st: INTEGER;
  769. BEGIN
  770. st := SHORT(c.stack[c.tos]); DEC(c.tos);
  771. IF st IN {3, 6, 7} THEN st := 2 END;
  772. IF (0 <= st) & (st <= 5) THEN
  773. c.scanType := st
  774. END;
  775. INC(c.pc)
  776. END SCANTYPE;
  777. (* set control value table cut in *)
  778. PROCEDURE SCVTCI (VAR c: Context);
  779. BEGIN
  780. c.cvtCutIn := c.stack[c.tos]; DEC(c.tos); INC(c.pc)
  781. END SCVTCI;
  782. (* set single width cut in *)
  783. PROCEDURE SSWCI (VAR c: Context);
  784. BEGIN
  785. c.swCutIn := c.stack[c.tos]; DEC(c.tos); INC(c.pc)
  786. END SSWCI;
  787. (* set single width *)
  788. PROCEDURE SSW (VAR c: Context);
  789. BEGIN
  790. (* FreeType says that the Windows engine seems to interpret this as a Fixed value (not FUnits as in Spec) *)
  791. c.swVal := ASH(c.stack[c.tos], -10); DEC(c.tos); INC(c.pc)
  792. END SSW;
  793. (* set the auto flip flag *)
  794. PROCEDURE FLIPON (VAR c: Context);
  795. BEGIN
  796. c.autoFlip := TRUE; INC(c.pc)
  797. END FLIPON;
  798. (* clear the auto flip flag *)
  799. PROCEDURE FLIPOFF (VAR c: Context);
  800. BEGIN
  801. c.autoFlip := FALSE; INC(c.pc)
  802. END FLIPOFF;
  803. (* set angle weight *)
  804. PROCEDURE SANGW (VAR c: Context);
  805. BEGIN
  806. DEC(c.tos); INC(c.pc) (* corresponding instruction AA is obsolete *)
  807. END SANGW;
  808. (* set delta base *)
  809. PROCEDURE SDB (VAR c: Context);
  810. BEGIN
  811. c.deltaBase := SHORT(c.stack[c.tos]); DEC(c.tos); INC(c.pc)
  812. END SDB;
  813. (* set delta shift *)
  814. PROCEDURE SDS (VAR c: Context);
  815. BEGIN
  816. c.deltaShift := SHORT(c.stack[c.tos]); DEC(c.tos); INC(c.pc)
  817. END SDS;
  818. (*--- Reading and Writing Data ---*)
  819. (* get coordinate projected onto the projection vector *)
  820. PROCEDURE GC (VAR c: Context);
  821. VAR p: LONGINT; dist: F26D6;
  822. BEGIN
  823. p := c.stack[c.tos];
  824. IF ODD(ORD(c.code[c.pc])) THEN (* use original coordinates *)
  825. (* both TTI and FreeType use the dual projection vector with original coordinates *)
  826. dist := Project(c.zp2.pt[p].org, c.proj2)
  827. ELSE (* use current coordinates *)
  828. dist := Project(c.zp2.pt[p].cur, c.proj)
  829. END;
  830. c.stack[c.tos] := dist;
  831. INC(c.pc)
  832. END GC;
  833. (* set coordinate from stack using projection and freedom vector *)
  834. PROCEDURE SCFS (VAR c: Context);
  835. VAR dist, d: F26D6; p: LONGINT;
  836. BEGIN
  837. dist := c.stack[c.tos]; DEC(c.tos);
  838. p := c.stack[c.tos]; DEC(c.tos);
  839. d := Project(c.zp2.pt[p].cur, c.proj);
  840. Move(c.zp2.pt[p], c.free, c.proj, dist - d);
  841. INC(c.pc)
  842. END SCFS;
  843. (* measure distance *)
  844. PROCEDURE MD (VAR c: Context);
  845. VAR p1, p2: LONGINT; d1, d2: F26D6;
  846. BEGIN
  847. (*
  848. - original implementation used zone 0 for p1 and zone 1 for p2
  849. - both TTI and FreeType swap opcode semantics (probably bug in spec since odd opcode comes first)
  850. - spec doesn't mention that dual projection vector has to be used with original coordinates
  851. *)
  852. p1 := c.stack[c.tos]; DEC(c.tos);
  853. p2 := c.stack[c.tos];
  854. IF ODD(ORD(c.code[c.pc])) THEN (* use current coordinates *)
  855. d1 := Project(c.zp1.pt[p1].cur, c.proj);
  856. d2 := Project(c.zp0.pt[p2].cur, c.proj)
  857. ELSE (* use original coordinates *)
  858. d1 := Project(c.zp1.pt[p1].org, c.proj2);
  859. d2 := Project(c.zp0.pt[p2].org, c.proj2)
  860. END;
  861. c.stack[c.tos] := d2 - d1;
  862. INC(c.pc)
  863. END MD;
  864. (* measure pixels per em *)
  865. PROCEDURE MPPEM (VAR c: Context);
  866. BEGIN
  867. INC(c.tos); c.stack[c.tos] := ASH(PPEm(c) + 20H, -6); INC(c.pc)
  868. END MPPEM;
  869. (* measure point size *)
  870. PROCEDURE MPS (VAR c: Context);
  871. BEGIN
  872. INC(c.tos); c.stack[c.tos] := ASH(c.ptsize + 20H, -6); INC(c.pc)
  873. END MPS;
  874. (*--- Managing Outlines ---*)
  875. (* flip point *)
  876. PROCEDURE FLIPPT (VAR c: Context);
  877. VAR p: LONGINT; pt: Points;
  878. BEGIN
  879. (* both TTI and FreeType don't use zp0; instead they work in zone 1 directly *)
  880. pt := c.zone[1].pt;
  881. WHILE c.loop > 0 DO
  882. p := c.stack[c.tos]; DEC(c.tos);
  883. pt[p].onCurve := ~pt[p].onCurve;
  884. DEC(c.loop)
  885. END;
  886. c.loop := 1;
  887. INC(c.pc)
  888. END FLIPPT;
  889. (* flip range on/off *)
  890. PROCEDURE FLIPRG (VAR c: Context);
  891. VAR on: BOOLEAN; hi, lo: LONGINT; pt: Points;
  892. BEGIN
  893. on := ODD(ORD(c.code[c.pc]));
  894. hi := c.stack[c.tos]; DEC(c.tos);
  895. lo := c.stack[c.tos]; DEC(c.tos);
  896. pt := c.zone[1].pt;
  897. WHILE lo <= hi DO
  898. pt[lo].onCurve := on;
  899. INC(lo)
  900. END;
  901. INC(c.pc)
  902. END FLIPRG;
  903. (* shift point by the last point *)
  904. PROCEDURE SHP (VAR c: Context);
  905. VAR zone: Zone; p: LONGINT; dx, dy: F26D6; pt: Points;
  906. BEGIN
  907. GetRefDist(c, ODD(ORD(c.code[c.pc])), zone, p, dx, dy);
  908. pt := c.zp2.pt;
  909. WHILE c.loop > 0 DO
  910. p := c.stack[c.tos]; DEC(c.tos);
  911. IF c.free.x # 0 THEN
  912. INC(pt[p].cur[X], dx); pt[p].touched[X] := TRUE
  913. END;
  914. IF c.free.y # 0 THEN
  915. INC(pt[p].cur[Y], dy); pt[p].touched[Y] := TRUE
  916. END;
  917. DEC(c.loop)
  918. END;
  919. c.loop := 1;
  920. INC(c.pc)
  921. END SHP;
  922. (* shift contour by the last point *)
  923. PROCEDURE SHC (VAR c: Context);
  924. VAR zone: Zone; ref, cont, cur, last: LONGINT; dx, dy: F26D6; pt: Points;
  925. BEGIN
  926. (*
  927. - TTI uses original coordinates (which is probably wrong)
  928. - FreeType says that points aren't touched (so I don't)
  929. *)
  930. GetRefDist(c, ODD(ORD(c.code[c.pc])), zone, ref, dx, dy);
  931. pt := c.zp2.pt;
  932. cont := c.stack[c.tos]; DEC(c.tos);
  933. cur := c.zp2.first[cont]; last := c.zp2.first[cont+1]-1;
  934. WHILE cur <= last DO
  935. IF (zone # c.zp2) OR (cur # ref) THEN
  936. IF c.free.x # 0 THEN
  937. INC(pt[cur].cur[X], dx)
  938. END;
  939. IF c.free.y # 0 THEN
  940. INC(pt[cur].cur[Y], dy)
  941. END
  942. END;
  943. INC(cur)
  944. END;
  945. INC(c.pc)
  946. END SHC;
  947. (* shift zone by the last point *)
  948. PROCEDURE SHZ (VAR c: Context);
  949. VAR zone, z: Zone; ref, cur, last: LONGINT; dx, dy: F26D6; pt: Points;
  950. BEGIN
  951. (*
  952. - TTI uses original coordinates (which is probably wrong)
  953. - FreeType says that points aren't touched (so I don't)
  954. - FreeType ignores the argument on the stack and always uses zp2
  955. *)
  956. GetRefDist(c, ODD(ORD(c.code[c.pc])), zone, ref, dx, dy);
  957. z := c.zone[c.stack[c.tos]]; DEC(c.tos);
  958. pt := z.pt;
  959. cur := 0; last := z.first[z.contours]-1;
  960. WHILE cur <= last DO
  961. IF (zone # z) OR (cur # ref) THEN
  962. IF c.free.x # 0 THEN
  963. INC(pt[cur].cur[X], dx)
  964. END;
  965. IF c.free.y # 0 THEN
  966. INC(pt[cur].cur[Y], dy)
  967. END
  968. END;
  969. INC(cur)
  970. END;
  971. INC(c.pc)
  972. END SHZ;
  973. (* shift point by a pixel amount *)
  974. PROCEDURE SHPIX (VAR c: Context);
  975. VAR dist, dx, dy: F26D6; pt: Points; p: LONGINT;
  976. BEGIN
  977. dist := c.stack[c.tos]; DEC(c.tos);
  978. dx := MulShift(dist, c.free.x, -14);
  979. dy := MulShift(dist, c.free.y, -14);
  980. pt := c.zp2.pt;
  981. WHILE c.loop > 0 DO
  982. p := c.stack[c.tos]; DEC(c.tos);
  983. IF c.free.x # 0 THEN
  984. INC(pt[p].cur[X], dx); pt[p].touched[X] := TRUE
  985. END;
  986. IF c.free.y # 0 THEN
  987. INC(pt[p].cur[Y], dy); pt[p].touched[Y] := TRUE
  988. END;
  989. DEC(c.loop)
  990. END;
  991. c.loop := 1;
  992. INC(c.pc)
  993. END SHPIX;
  994. (* move stack indirect relative point *)
  995. PROCEDURE MSIRP (VAR c: Context);
  996. VAR dist, d: F26D6; p: LONGINT; org: Coord; pt: Points;
  997. BEGIN
  998. dist := c.stack[c.tos]; DEC(c.tos);
  999. p := c.stack[c.tos]; DEC(c.tos);
  1000. (* undocumented behaviour, suggested by FreeType *)
  1001. IF c.gep0 = 0 THEN
  1002. org := c.zp0.pt[c.rp0].org;
  1003. pt := c.zp1.pt; pt[p].org := org; pt[p].cur := org
  1004. END;
  1005. d := Project(c.zp1.pt[p].cur, c.proj) - Project(c.zp0.pt[c.rp0].cur, c.proj);
  1006. Move(c.zp1.pt[p], c.free, c.proj, dist - d);
  1007. c.rp1 := c.rp0; c.rp2 := SHORT(p); (* TTI didn't implement this *)
  1008. IF ODD(ORD(c.code[c.pc])) THEN
  1009. c.rp0 := SHORT(p)
  1010. END;
  1011. INC(c.pc)
  1012. END MSIRP;
  1013. (* move direct absolute point *)
  1014. PROCEDURE MDAP (VAR c: Context);
  1015. VAR p: LONGINT; d, dist: F26D6;
  1016. BEGIN
  1017. p := c.stack[c.tos]; DEC(c.tos);
  1018. IF ODD(ORD(c.code[c.pc])) THEN
  1019. d := Project(c.zp0.pt[p].cur, c.proj);
  1020. dist := Round(d, c.period, c.phase, c.threshold) - d
  1021. ELSE
  1022. dist := 0
  1023. END;
  1024. Move(c.zp0.pt[p], c.free, c.proj, dist);
  1025. c.rp0 := SHORT(p); c.rp1 := SHORT(p);
  1026. INC(c.pc)
  1027. END MDAP;
  1028. (* move indirect absolute point *)
  1029. PROCEDURE MIAP (VAR c: Context);
  1030. VAR cvt, p: LONGINT; dist, d: F26D6; pt: Points; xy: Coord;
  1031. BEGIN
  1032. cvt := c.stack[c.tos]; DEC(c.tos);
  1033. p := c.stack[c.tos]; DEC(c.tos);
  1034. dist := CVTValue(cvt, c);
  1035. pt := c.zp0.pt;
  1036. IF c.gep0 = 0 THEN (* twilight zone *)
  1037. (* why does FreeType use the freedom vector for this? The spec explicitly mentions the projection vector *)
  1038. xy[X] := MulShift(dist, c.proj.x, -14); xy[Y] := MulShift(dist, c.proj.y, -14);
  1039. pt[p].org := xy; pt[p].cur := xy
  1040. END;
  1041. d := Project(pt[p].cur, c.proj);
  1042. IF c.autoFlip & (dist * d < 0) THEN dist := -dist END; (* got this from TTI; FreeType does nothing similar *)
  1043. IF ODD(ORD(c.code[c.pc])) THEN (* round and apply cvt cutin *)
  1044. IF ABS(dist - d) > c.cvtCutIn THEN dist := d END;
  1045. dist := Round(dist, c.period, c.phase, c.threshold)
  1046. END;
  1047. Move(pt[p], c.free, c.proj, dist - d);
  1048. c.rp0 := SHORT(p); c.rp1 := SHORT(p);
  1049. INC(c.pc)
  1050. END MIAP;
  1051. (* move direct relative point *)
  1052. PROCEDURE MDRP (VAR c: Context);
  1053. VAR p: LONGINT; d, dist: F26D6;
  1054. BEGIN
  1055. p := c.stack[c.tos]; DEC(c.tos);
  1056. d := Project(c.zp1.pt[p].org, c.proj2) - Project(c.zp0.pt[c.rp0].org, c.proj2);
  1057. (* why does FreeType use the absolute value of 'd' for the single width cutin test? *)
  1058. IF (d >= 0) & (ABS(d - c.swVal) < c.swCutIn) THEN d := c.swVal
  1059. ELSIF (d < 0) & (ABS(-d - c.swVal) < c.swCutIn) THEN d := -c.swVal
  1060. END;
  1061. IF ODD(ORD(c.code[c.pc]) DIV 4) THEN (* round distance *)
  1062. dist := Round(d, c.period, c.phase, c.threshold)
  1063. ELSE
  1064. dist := d
  1065. END;
  1066. IF ODD(ORD(c.code[c.pc]) DIV 8) THEN (* keep distance greater than minimum distance *)
  1067. IF (d >= 0) & (dist < c.minDist) THEN dist := c.minDist
  1068. ELSIF (d < 0) & (dist > -c.minDist) THEN dist := -c.minDist
  1069. END
  1070. END;
  1071. d := Project(c.zp1.pt[p].cur, c.proj) - Project(c.zp0.pt[c.rp0].cur, c.proj);
  1072. Move(c.zp1.pt[p], c.free, c.proj, dist - d);
  1073. c.rp1 := c.rp0; c.rp2 := SHORT(p);
  1074. IF ODD(ORD(c.code[c.pc]) DIV 16) THEN
  1075. c.rp0 := SHORT(p)
  1076. END;
  1077. INC(c.pc)
  1078. END MDRP;
  1079. (* move indirect relative point *)
  1080. PROCEDURE MIRP (VAR c: Context);
  1081. VAR cvt, p: LONGINT; dcvt, od, cd, dist: F26D6; pt: Points; xy: Coord;
  1082. BEGIN
  1083. IF LEN(c.stack) <= c.tos THEN RETURN END;
  1084. cvt := c.stack[c.tos]; DEC(c.tos);
  1085. p := c.stack[c.tos]; DEC(c.tos);
  1086. dcvt := CVTValue(cvt, c);
  1087. pt := c.zp1.pt;
  1088. IF c.gep1 = 0 THEN (* according to FreeType, MIRP can be used to create twilight points *)
  1089. xy[X] := c.zp0.pt[c.rp0].org[X] + MulShift(dcvt, c.free.x, -14);
  1090. xy[Y] := c.zp0.pt[c.rp0].org[Y] + MulShift(dcvt, c.free.y, -14);
  1091. pt[p].org := xy; pt[p].cur := xy
  1092. END;
  1093. od := Project(pt[p].org, c.proj2) - Project(c.zp0.pt[c.rp0].org, c.proj2);
  1094. cd := Project(pt[p].cur, c.proj) - Project(c.zp0.pt[c.rp0].cur, c.proj);
  1095. IF c.autoFlip & (od * dcvt < 0) THEN
  1096. dcvt := -dcvt
  1097. END;
  1098. IF ODD(ORD(c.code[c.pc]) DIV 4) THEN (* perform cvtCutIn test and round *)
  1099. IF c.zp0 = c.zp1 THEN (* according to FreeType, both points have to be in the same zone *)
  1100. IF ABS(od - dcvt) >= c.cvtCutIn THEN
  1101. dcvt := od
  1102. END;
  1103. (* for the single width cut in test, FreeType uses again the value of dcvt directly !? *)
  1104. IF (dcvt >= 0) & (ABS(dcvt - c.swVal) < c.swCutIn) THEN dcvt := c.swVal
  1105. ELSIF (dcvt < 0) & (ABS(-dcvt - c.swVal) < c.swCutIn) THEN dcvt := -c.swVal
  1106. END
  1107. END;
  1108. dist := Round(dcvt, c.period, c.phase, c.threshold)
  1109. ELSE
  1110. dist := dcvt (* TTI used the original distance, which is almost certainly wrong *)
  1111. END;
  1112. IF ODD(ORD(c.code[c.pc]) DIV 8) THEN (* perform minimum distance test *)
  1113. IF (od >= 0) & (dist < c.minDist) THEN dist := c.minDist
  1114. ELSIF (od < 0) & (dist > -c.minDist) THEN dist := -c.minDist
  1115. END
  1116. END;
  1117. Move(pt[p], c.free, c.proj, dist - cd);
  1118. c.rp1 := c.rp0; c.rp2 := SHORT(p);
  1119. IF ODD(ORD(c.code[c.pc]) DIV 16) THEN
  1120. c.rp0 := SHORT(p)
  1121. END;
  1122. INC(c.pc)
  1123. END MIRP;
  1124. (* align relative point *)
  1125. PROCEDURE ALIGNRP (VAR c: Context);
  1126. VAR p: LONGINT; dist: F26D6;
  1127. BEGIN
  1128. WHILE c.loop > 0 DO
  1129. p := c.stack[c.tos]; DEC(c.tos);
  1130. dist := Project(c.zp1.pt[p].cur, c.proj) - Project(c.zp0.pt[c.rp0].cur, c.proj);
  1131. Move(c.zp1.pt[p], c.free, c.proj, -dist);
  1132. DEC(c.loop)
  1133. END;
  1134. c.loop := 1;
  1135. INC(c.pc)
  1136. END ALIGNRP;
  1137. (* move point to intersection of two lines *)
  1138. PROCEDURE ISECT (VAR c: Context);
  1139. VAR
  1140. b1, b0, a1, a0, p: LONGINT; pt: Points; ax0, ay0, ax1, ay1, bx0, by0, bx1, by1, d, rx, ry: F26D6;
  1141. dxa, dya, dxb, dyb, dx, dy, u, v, det: INT64;
  1142. BEGIN
  1143. b1 := c.stack[c.tos]; DEC(c.tos);
  1144. b0 := c.stack[c.tos]; DEC(c.tos);
  1145. a1 := c.stack[c.tos]; DEC(c.tos);
  1146. a0 := c.stack[c.tos]; DEC(c.tos);
  1147. p := c.stack[c.tos]; DEC(c.tos);
  1148. pt := c.zp2.pt;
  1149. pt[p].touched[X] := TRUE; pt[p].touched[Y] := TRUE;
  1150. ax0 := c.zp1.pt[a0].cur[X]; ay0 := c.zp1.pt[a0].cur[Y];
  1151. ax1 := c.zp1.pt[a1].cur[X]; ay1 := c.zp1.pt[a1].cur[Y];
  1152. bx0 := c.zp0.pt[b0].cur[X]; by0 := c.zp0.pt[b0].cur[Y];
  1153. bx1 := c.zp0.pt[b1].cur[X]; by1 := c.zp0.pt[b1].cur[Y];
  1154. ToINT64(ax1 - ax0, dxa); ToINT64(ay1 - ay0, dya);
  1155. ToINT64(bx1 - bx0, dxb); ToINT64(by1 - by0, dyb);
  1156. MulINT64(dya, dxb, u); MulINT64(dyb, dxa, v);
  1157. SubINT64(u, v, det);
  1158. FromINT64(det, d);
  1159. IF ABS(d) >= 80H THEN
  1160. ToINT64(bx0 - ax0, dx); ToINT64(by0 - ay0, dy);
  1161. SubINT64(Zero64, dyb, dyb);
  1162. MulINT64(dx, dyb, u); MulINT64(dy, dxb, v); AddINT64(u, v, v);
  1163. MulINT64(v, dxa, u); DivINT64(u, det, u); FromINT64(u, rx);
  1164. MulINT64(v, dya, u); DivINT64(u, det, u); FromINT64(u, ry);
  1165. pt[p].cur[X] := ax0 + rx;
  1166. pt[p].cur[Y] := ay0 + ry
  1167. ELSE (* lines are (almost) parallel *)
  1168. pt[p].cur[X] := (ax0 + ax1 + bx0 + bx1) DIV 4;
  1169. pt[p].cur[Y] := (ay0 + ay1 + by0 + by1) DIV 4
  1170. END;
  1171. INC(c.pc)
  1172. END ISECT;
  1173. (* align points *)
  1174. PROCEDURE ALIGNPTS (VAR c: Context);
  1175. VAR p1, p2: LONGINT; dist: F26D6;
  1176. BEGIN
  1177. p1 := c.stack[c.tos]; DEC(c.tos);
  1178. p2 := c.stack[c.tos]; DEC(c.tos);
  1179. (* both TTI and FreeType swap use p1 with zp0 and p2 with zp1 (contrary to spec) *)
  1180. dist := (Project(c.zp0.pt[p1].cur, c.proj) - Project(c.zp1.pt[p2].cur, c.proj)) DIV 2;
  1181. Move(c.zp0.pt[p1], c.free, c.proj, -dist);
  1182. Move(c.zp1.pt[p2], c.free, c.proj, dist);
  1183. INC(c.pc)
  1184. END ALIGNPTS;
  1185. (* interpolate point by the last relative stretch *)
  1186. PROCEDURE IP (VAR c: Context);
  1187. VAR od1, od2, cd1, cd2, od, cd, dist: F26D6; pt: Points; p: LONGINT;
  1188. BEGIN
  1189. od1 := Project(c.zp0.pt[c.rp1].org, c.proj2);
  1190. od2 := Project(c.zp1.pt[c.rp2].org, c.proj2);
  1191. cd1 := Project(c.zp0.pt[c.rp1].cur, c.proj);
  1192. cd2 := Project(c.zp1.pt[c.rp2].cur, c.proj);
  1193. pt := c.zp2.pt;
  1194. WHILE c.loop > 0 DO
  1195. p := c.stack[c.tos]; DEC(c.tos);
  1196. od := Project(pt[p].org, c.proj2);
  1197. cd := Project(pt[p].cur, c.proj);
  1198. IF (od1 <= od2) & (od <= od1) OR (od1 > od2) & (od >= od1) THEN
  1199. dist := cd1 - od1 + od - cd
  1200. ELSIF (od1 <= od2) & (od2 <= od) OR (od1 > od2) & (od2 >= od) THEN
  1201. dist := cd2 - od2 + od - cd
  1202. ELSE
  1203. dist := MulDiv(cd2 - cd1, od - od1, od2 - od1) + cd1 - cd
  1204. END;
  1205. Move(pt[p], c.free, c.proj, dist);
  1206. DEC(c.loop)
  1207. END;
  1208. c.loop := 1;
  1209. INC(c.pc)
  1210. END IP;
  1211. (* untouch point *)
  1212. PROCEDURE UTP (VAR c: Context);
  1213. VAR p: LONGINT;
  1214. BEGIN
  1215. p := c.stack[c.tos]; DEC(c.tos);
  1216. IF c.free.x # 0 THEN
  1217. c.zp2.pt[p].touched[X] := FALSE
  1218. END;
  1219. IF c.free.y # 0 THEN
  1220. c.zp2.pt[p].touched[Y] := FALSE
  1221. END;
  1222. INC(c.pc)
  1223. END UTP;
  1224. (* interpolate untouched points through the outline *)
  1225. PROCEDURE IUP (VAR c: Context);
  1226. VAR
  1227. z: Zone; pt: Points; n, xy, beg, nil, first, end, cur: LONGINT; dxy: F26D6;
  1228. PROCEDURE interpol (p0, p1, rp0, rp1: LONGINT);
  1229. VAR oxy0, cxy0, dxy0, oxy1, cxy1, dxy1, cxy: F26D6;
  1230. BEGIN
  1231. IF p0 <= p1 THEN
  1232. oxy0 := pt[rp0].org[xy]; cxy0 := pt[rp0].cur[xy]; dxy0 := cxy0 - oxy0;
  1233. oxy1 := pt[rp1].org[xy]; cxy1 := pt[rp1].cur[xy]; dxy1 := cxy1 - oxy1;
  1234. IF oxy0 < oxy1 THEN
  1235. WHILE p0 <= p1 DO
  1236. cxy := pt[p0].org[xy];
  1237. IF cxy <= oxy0 THEN INC(cxy, dxy0)
  1238. ELSIF oxy1 <= cxy THEN INC(cxy, dxy1)
  1239. ELSE cxy := cxy0 + MulDiv(cxy - oxy0, cxy1 - cxy0, oxy1 - oxy0)
  1240. END;
  1241. pt[p0].cur[xy] := cxy;
  1242. INC(p0)
  1243. END
  1244. ELSIF oxy1 < oxy0 THEN
  1245. WHILE p0 <= p1 DO
  1246. cxy := pt[p0].org[xy];
  1247. IF cxy <= oxy1 THEN INC(cxy, dxy1)
  1248. ELSIF oxy0 <= cxy THEN INC(cxy, dxy0)
  1249. ELSE cxy := cxy0 + MulDiv(cxy - oxy0, cxy1 - cxy0, oxy1 - oxy0)
  1250. END;
  1251. pt[p0].cur[xy] := cxy;
  1252. INC(p0)
  1253. END
  1254. ELSE
  1255. WHILE p0 <= p1 DO
  1256. cxy := pt[p0].org[xy];
  1257. IF cxy <= oxy0 THEN INC(cxy, dxy0)
  1258. ELSE INC(cxy, dxy1)
  1259. END;
  1260. pt[p0].cur[xy] := cxy;
  1261. INC(p0)
  1262. END
  1263. END
  1264. END
  1265. END interpol;
  1266. BEGIN
  1267. z := c.zp2; pt := z.pt; n := 0;
  1268. xy := ORD(c.code[c.pc]) MOD 2;
  1269. WHILE n < z.contours DO
  1270. beg := z.first[n]; nil := z.first[n+1];
  1271. WHILE (beg < nil) & ~pt[beg].touched[xy] DO INC(beg) END;
  1272. IF beg < nil THEN
  1273. first := beg;
  1274. REPEAT
  1275. end := beg+1;
  1276. WHILE (end < nil) & ~pt[end].touched[xy] DO INC(end) END;
  1277. IF end < nil THEN
  1278. interpol(beg+1, end-1, beg, end);
  1279. beg := end+1;
  1280. WHILE (beg < nil) & pt[beg].touched[xy] DO INC(beg) END;
  1281. DEC(beg)
  1282. END
  1283. UNTIL end = nil;
  1284. IF beg = first THEN (* only one touched point in whole contour => FreeType applies shift here *)
  1285. dxy := pt[beg].cur[xy] - pt[beg].org[xy];
  1286. cur := z.first[n];
  1287. WHILE cur < beg DO INC(pt[cur].cur[xy], dxy); INC(cur) END;
  1288. cur := beg+1;
  1289. WHILE cur < nil DO INC(pt[cur].cur[xy], dxy); INC(cur) END
  1290. ELSE
  1291. interpol(beg+1, nil-1, beg, first);
  1292. IF first > z.first[n] THEN interpol(z.first[n], first-1, beg, first) END
  1293. END
  1294. END;
  1295. INC(n)
  1296. END;
  1297. INC(c.pc)
  1298. END IUP;
  1299. (*--- Managing Exceptions ---*)
  1300. (* delta exception Pn *)
  1301. PROCEDURE DELTAP (VAR c: Context);
  1302. VAR base, ppm, n, p, arg: LONGINT;
  1303. BEGIN
  1304. base := c.deltaBase;
  1305. IF c.code[c.pc] = 71X THEN INC(base, 16) (* DELTAP2 *)
  1306. ELSIF c.code[c.pc] = 72X THEN INC(base, 32) (* DELTAP3 *)
  1307. END;
  1308. ppm := ASH(PPEm(c) + 20H, -6);
  1309. n := c.stack[c.tos]; DEC(c.tos);
  1310. WHILE n > 0 DO
  1311. p := c.stack[c.tos]; DEC(c.tos);
  1312. arg := c.stack[c.tos]; DEC(c.tos);
  1313. IF (base + arg DIV 10H MOD 10H = ppm) & (0 <= p) & (p < LEN(c.zp0.pt^)) THEN
  1314. arg := arg MOD 10H - 8;
  1315. IF arg >= 0 THEN INC(arg) END;
  1316. arg := 40H * arg DIV ASH(1, c.deltaShift);
  1317. Move(c.zp0.pt[p], c.free, c.proj, arg)
  1318. END;
  1319. DEC(n)
  1320. END;
  1321. INC(c.pc)
  1322. END DELTAP;
  1323. (* delta exception Cn *)
  1324. PROCEDURE DELTAC (VAR c: Context);
  1325. VAR base, ppm, n, cvt, arg: LONGINT;
  1326. BEGIN
  1327. base := c.deltaBase;
  1328. IF c.code[c.pc] = 74X THEN INC(base, 16) (* DELTAC2 *)
  1329. ELSIF c.code[c.pc] = 75X THEN INC(base, 32) (* DELTAC3 *)
  1330. END;
  1331. ppm := ASH(PPEm(c) + 20H, -6);
  1332. n := c.stack[c.tos]; DEC(c.tos);
  1333. WHILE n > 0 DO
  1334. cvt := c.stack[c.tos]; DEC(c.tos);
  1335. arg := c.stack[c.tos]; DEC(c.tos);
  1336. IF base + arg DIV 10H MOD 10H = ppm THEN
  1337. arg := arg MOD 10H - 8;
  1338. IF arg >= 0 THEN INC(arg) END;
  1339. arg := 40H * arg DIV ASH(1, c.deltaShift);
  1340. INC(c.cvt[cvt], ShiftDiv(arg, 16, Ratio(c)))
  1341. END;
  1342. DEC(n)
  1343. END;
  1344. INC(c.pc)
  1345. END DELTAC;
  1346. (*--- Managing the Stack ---*)
  1347. (* duplicate top stack element *)
  1348. PROCEDURE DUP (VAR c: Context);
  1349. BEGIN
  1350. INC(c.tos); c.stack[c.tos] := c.stack[c.tos-1]; INC(c.pc)
  1351. END DUP;
  1352. (* pop top stack element *)
  1353. PROCEDURE POP (VAR c: Context);
  1354. BEGIN
  1355. DEC(c.tos); INC(c.pc)
  1356. END POP;
  1357. (* clear the entire stack *)
  1358. PROCEDURE CLEAR (VAR c: Context);
  1359. BEGIN
  1360. c.tos := -1; INC(c.pc)
  1361. END CLEAR;
  1362. (* swap the top two elements on the stack *)
  1363. PROCEDURE SWAP (VAR c: Context);
  1364. VAR tmp: LONGINT;
  1365. BEGIN
  1366. tmp := c.stack[c.tos]; c.stack[c.tos] := c.stack[c.tos-1]; c.stack[c.tos-1] := tmp; INC(c.pc)
  1367. END SWAP;
  1368. (* return depth of the stack *)
  1369. PROCEDURE DEPTH (VAR c: Context);
  1370. BEGIN
  1371. INC(c.tos); c.stack[c.tos] := c.tos; INC(c.pc)
  1372. END DEPTH;
  1373. (* copy the indexed element to the top of the stack *)
  1374. PROCEDURE CINDEX (VAR c: Context);
  1375. VAR idx: LONGINT;
  1376. BEGIN
  1377. idx := c.stack[c.tos]; c.stack[c.tos] := c.stack[c.tos - idx]; INC(c.pc)
  1378. END CINDEX;
  1379. (* move the indexed element to the top of the stack *)
  1380. PROCEDURE MINDEX (VAR c: Context);
  1381. VAR idx, pos, elem: LONGINT;
  1382. BEGIN
  1383. idx := c.stack[c.tos];
  1384. pos := c.tos - idx; elem := c.stack[pos];
  1385. WHILE idx > 1 DO
  1386. c.stack[pos] := c.stack[pos+1]; INC(pos); DEC(idx)
  1387. END;
  1388. c.stack[pos] := elem; DEC(c.tos);
  1389. INC(c.pc)
  1390. END MINDEX;
  1391. (* roll the top three stack elements *)
  1392. PROCEDURE ROLL (VAR c: Context);
  1393. VAR elem: LONGINT;
  1394. BEGIN
  1395. 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;
  1396. INC(c.pc)
  1397. END ROLL;
  1398. (*--- Managing the Flow of Control ---*)
  1399. PROCEDURE Skip (VAR c: Context);
  1400. BEGIN
  1401. CASE c.code[c.pc] OF
  1402. | 40X: INC(c.pc, LONG(2 + ORD(c.code[c.pc+1]))) (* NPUSHB *)
  1403. | 41X: INC(c.pc, LONG(2 + 2*ORD(c.code[c.pc+1]))) (* NPUSHW *)
  1404. | 0B0X..0B7X: INC(c.pc, LONG(2 + ORD(c.code[c.pc]) MOD 8)) (* PUSHBx *)
  1405. | 0B8X..0BFX: INC(c.pc, LONG(3 + 2*(ORD(c.code[c.pc]) MOD 8))) (* PUSHWx *)
  1406. | 58X: INC(c.pc); WHILE c.code[c.pc] # 59X DO Skip(c) END; INC(c.pc) (* IF..EIF *)
  1407. ELSE INC(c.pc)
  1408. END
  1409. END Skip;
  1410. (* if test *)
  1411. PROCEDURE iF (VAR c: Context);
  1412. BEGIN
  1413. IF c.stack[c.tos] = 0 THEN
  1414. INC(c.pc);
  1415. WHILE (c.code[c.pc] # 1BX) & (c.code[c.pc] # 59X) DO (* terminated by ELSE or EIF *)
  1416. Skip(c)
  1417. END
  1418. END;
  1419. DEC(c.tos); INC(c.pc)
  1420. END iF;
  1421. (* else part of if-clause *)
  1422. PROCEDURE eLSE (VAR c: Context);
  1423. BEGIN
  1424. (* only executed if previous IF-test was successful => skip until EIF *)
  1425. REPEAT Skip(c) UNTIL c.code[c.pc] = 59X;
  1426. INC(c.pc)
  1427. END eLSE;
  1428. (* end mark of if-clause *)
  1429. PROCEDURE EIF (VAR c: Context);
  1430. BEGIN
  1431. INC(c.pc)
  1432. END EIF;
  1433. (* jump relative on true *)
  1434. PROCEDURE JROT (VAR c: Context);
  1435. VAR true: BOOLEAN;
  1436. BEGIN
  1437. true := c.stack[c.tos] # 0; DEC(c.tos);
  1438. IF true THEN
  1439. INC(c.pc, c.stack[c.tos]);
  1440. ELSE
  1441. INC(c.pc)
  1442. END;
  1443. DEC(c.tos)
  1444. END JROT;
  1445. (* jump relative *)
  1446. PROCEDURE JUMPR (VAR c: Context);
  1447. BEGIN
  1448. INC(c.pc, c.stack[c.tos]); DEC(c.tos)
  1449. END JUMPR;
  1450. (* jump relative on false *)
  1451. PROCEDURE JROF (VAR c: Context);
  1452. VAR false: BOOLEAN;
  1453. BEGIN
  1454. false := c.stack[c.tos] = 0; DEC(c.tos);
  1455. IF false THEN
  1456. INC(c.pc, c.stack[c.tos]);
  1457. ELSE
  1458. INC(c.pc)
  1459. END;
  1460. DEC(c.tos)
  1461. END JROF;
  1462. (*--- Logical Functions ---*)
  1463. (* comparison *)
  1464. PROCEDURE COMPARE (VAR c: Context);
  1465. VAR b, a: LONGINT; res: BOOLEAN;
  1466. BEGIN
  1467. b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
  1468. CASE c.code[c.pc] OF
  1469. | 50X: res := a < b
  1470. | 51X: res := a <= b
  1471. | 52X: res := a > b
  1472. | 53X: res := a >= b
  1473. | 54X: res := a = b
  1474. | 55X: res := a # b
  1475. END;
  1476. IF res THEN c.stack[c.tos] := 1
  1477. ELSE c.stack[c.tos] := 0
  1478. END;
  1479. INC(c.pc)
  1480. END COMPARE;
  1481. (* odd *)
  1482. PROCEDURE oDD (VAR c: Context);
  1483. VAR r: LONGINT;
  1484. BEGIN
  1485. r := Round(c.stack[c.tos], c.period, c.phase, c.threshold) DIV 40H;
  1486. IF ODD(r) THEN c.stack[c.tos] := 1 ELSE c.stack[c.tos] := 0 END;
  1487. INC(c.pc)
  1488. END oDD;
  1489. (* even *)
  1490. PROCEDURE EVEN (VAR c: Context);
  1491. VAR r: LONGINT;
  1492. BEGIN
  1493. r := Round(c.stack[c.tos], c.period, c.phase, c.threshold) DIV 40H;
  1494. IF ODD(r) THEN c.stack[c.tos] := 0 ELSE c.stack[c.tos] := 1 END;
  1495. INC(c.pc)
  1496. END EVEN;
  1497. (* logical and *)
  1498. PROCEDURE AND (VAR c: Context);
  1499. VAR b, a: LONGINT;
  1500. BEGIN
  1501. b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
  1502. IF a * b # 0 THEN c.stack[c.tos] := 1 ELSE c.stack[c.tos] := 0 END;
  1503. INC(c.pc)
  1504. END AND;
  1505. (* logical or *)
  1506. PROCEDURE oR (VAR c: Context);
  1507. VAR b, a: LONGINT;
  1508. BEGIN
  1509. b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
  1510. IF (a # 0) OR (b # 0) THEN c.stack[c.tos] := 1 ELSE c.stack[c.tos] := 0 END;
  1511. INC(c.pc)
  1512. END oR;
  1513. (* logical not *)
  1514. PROCEDURE NOT (VAR c: Context);
  1515. BEGIN
  1516. IF c.stack[c.tos] = 0 THEN c.stack[c.tos] := 1 ELSE c.stack[c.tos] := 0 END;
  1517. INC(c.pc)
  1518. END NOT;
  1519. (*--- Arithmetic and Math Instructions ---*)
  1520. PROCEDURE ADD (VAR c: Context);
  1521. VAR b: F26D6;
  1522. BEGIN
  1523. b := c.stack[c.tos]; DEC(c.tos); INC(c.stack[c.tos], b); INC(c.pc)
  1524. END ADD;
  1525. PROCEDURE SUB (VAR c: Context);
  1526. VAR b: F26D6;
  1527. BEGIN
  1528. b := c.stack[c.tos]; DEC(c.tos); DEC(c.stack[c.tos], b); INC(c.pc)
  1529. END SUB;
  1530. PROCEDURE dIV (VAR c: Context);
  1531. VAR b, a: F26D6;
  1532. BEGIN
  1533. b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
  1534. IF b > 0 THEN c.stack[c.tos] := ShiftDiv(a, 6, b)
  1535. ELSIF b < 0 THEN c.stack[c.tos] := ShiftDiv(-a, 6, -b)
  1536. ELSE c.stack[c.tos] := 0 (* division by zero *)
  1537. END;
  1538. INC(c.pc)
  1539. END dIV;
  1540. PROCEDURE MUL (VAR c: Context);
  1541. VAR b, a: F26D6;
  1542. BEGIN
  1543. b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
  1544. c.stack[c.tos] := MulShift(a, b, -6);
  1545. INC(c.pc)
  1546. END MUL;
  1547. PROCEDURE aBS (VAR c: Context);
  1548. BEGIN
  1549. c.stack[c.tos] := ABS(c.stack[c.tos]); INC(c.pc)
  1550. END aBS;
  1551. PROCEDURE NEG (VAR c: Context);
  1552. BEGIN
  1553. c.stack[c.tos] := -c.stack[c.tos]; INC(c.pc)
  1554. END NEG;
  1555. PROCEDURE Floor (VAR c: Context);
  1556. VAR x: F26D6;
  1557. BEGIN
  1558. x := c.stack[c.tos];
  1559. c.stack[c.tos] := x - x MOD 40H;
  1560. INC(c.pc)
  1561. END Floor;
  1562. PROCEDURE CEILING (VAR c: Context);
  1563. VAR x: F26D6;
  1564. BEGIN
  1565. x := c.stack[c.tos] + 3FH;
  1566. c.stack[c.tos] := x - x MOD 40H;
  1567. INC(c.pc)
  1568. END CEILING;
  1569. PROCEDURE mAX (VAR c: Context);
  1570. VAR b, a: F26D6;
  1571. BEGIN
  1572. b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
  1573. IF a < b THEN c.stack[c.tos] := b END;
  1574. INC(c.pc)
  1575. END mAX;
  1576. PROCEDURE mIN (VAR c: Context);
  1577. VAR b, a: F26D6;
  1578. BEGIN
  1579. b := c.stack[c.tos]; DEC(c.tos); a := c.stack[c.tos];
  1580. IF a > b THEN c.stack[c.tos] := b END;
  1581. INC(c.pc)
  1582. END mIN;
  1583. (*--- Compensating for the Engine Characteristics ---*)
  1584. (* round value *)
  1585. PROCEDURE ROUND (VAR c: Context);
  1586. BEGIN
  1587. (* no engine characteristics are implemented *)
  1588. c.stack[c.tos] := Round(c.stack[c.tos], c.period, c.phase, c.threshold);
  1589. INC(c.pc)
  1590. END ROUND;
  1591. (* compensate without rounding value *)
  1592. PROCEDURE NROUND (VAR c: Context);
  1593. BEGIN
  1594. INC(c.pc) (* nothing happens *)
  1595. END NROUND;
  1596. (*--- Defining and Using Functions and Instructions ---*)
  1597. (* function definition *)
  1598. PROCEDURE FDEF (VAR c: Context);
  1599. VAR n: LONGINT;
  1600. BEGIN
  1601. n := c.stack[c.tos]; DEC(c.tos);
  1602. c.func[n].code := c.code; c.func[n].len := c.codeLen; c.func[n].pc := c.pc;
  1603. REPEAT Skip(c) UNTIL c.code[c.pc] = 2DX; (* skip until ENDF *)
  1604. INC(c.pc)
  1605. END FDEF;
  1606. (* end function definition *)
  1607. PROCEDURE ENDF (VAR c: Context);
  1608. BEGIN
  1609. DEC(c.callStack[c.ctos].count);
  1610. IF c.callStack[c.ctos].count < 0 THEN c.pc := c.codeLen; RETURN END; (* ERROR, prevent stack trap *)
  1611. IF c.callStack[c.ctos].count = 0 THEN
  1612. c.code := c.callStack[c.ctos].ret.code; c.codeLen := c.callStack[c.ctos].ret.len; c.pc := c.callStack[c.ctos].ret.pc;
  1613. DEC(c.ctos)
  1614. ELSE
  1615. c.pc := c.callStack[c.ctos].start (* code remains the same *)
  1616. END;
  1617. INC(c.pc) (* make PC point to instruction after FDEF/IDEF/(LOOP)CALL *)
  1618. END ENDF;
  1619. (* call function *)
  1620. PROCEDURE CALL (VAR c: Context);
  1621. VAR n: LONGINT;
  1622. BEGIN
  1623. n := c.stack[c.tos]; DEC(c.tos);
  1624. INC(c.ctos);
  1625. c.callStack[c.ctos].ret.code := c.code; c.callStack[c.ctos].ret.len := c.codeLen;
  1626. c.callStack[c.ctos].ret.pc := c.pc; c.callStack[c.ctos].count := 1;
  1627. 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 *)
  1628. END CALL;
  1629. (* loop and call function *)
  1630. PROCEDURE LOOPCALL (VAR c: Context);
  1631. VAR n, count: LONGINT;
  1632. BEGIN
  1633. n := c.stack[c.tos]; DEC(c.tos);
  1634. count := c.stack[c.tos]; DEC(c.tos);
  1635. INC(c.ctos);
  1636. c.callStack[c.ctos].ret.code := c.code; c.callStack[c.ctos].ret.len := c.codeLen; c.callStack[c.ctos].ret.pc := c.pc;
  1637. c.callStack[c.ctos].count := SHORT(count); c.callStack[c.ctos].start := c.func[n].pc;
  1638. 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 *)
  1639. END LOOPCALL;
  1640. (* instruction definition *)
  1641. PROCEDURE IDEF (VAR c: Context);
  1642. VAR op: CHAR; i: LONGINT;
  1643. BEGIN
  1644. op := CHR(c.stack[c.tos]); DEC(c.tos);
  1645. i := 0; WHILE (c.instr[i].beg.code # NIL) & (c.instr[i].opcode # op) DO INC(i) END;
  1646. IF c.instr[i].beg.code = NIL THEN
  1647. 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
  1648. END;
  1649. REPEAT Skip(c) UNTIL c.code[c.pc] = 2DX; (* skip until ENDF *)
  1650. INC(c.pc)
  1651. END IDEF;
  1652. (* user defined instructions *)
  1653. PROCEDURE UNDEF (VAR c: Context);
  1654. VAR i: LONGINT;
  1655. BEGIN
  1656. i := 0; WHILE (c.instr[i].beg.code # NIL) & (c.instr[i].opcode # c.code[c.pc]) DO INC(i) END;
  1657. IF c.instr[i].beg.code # NIL THEN (* found instruction *)
  1658. INC(c.ctos);
  1659. c.callStack[c.ctos].ret.code := c.code; c.callStack[c.ctos].ret.len := c.codeLen;
  1660. c.callStack[c.ctos].ret.pc := c.pc; c.callStack[c.ctos].count := 1;
  1661. c.code := c.instr[i].beg.code; c.pc := c.instr[i].beg.pc
  1662. END;
  1663. INC(c.pc)
  1664. END UNDEF;
  1665. (*--- Miscellaneous Instructions ---*)
  1666. (* debug call *)
  1667. PROCEDURE DEBUG (VAR c: Context);
  1668. BEGIN
  1669. DEC(c.tos); INC(c.pc); (* pop the value off the stack *)
  1670. IF Notify # NIL THEN Notify(c, NotifyData) END
  1671. END DEBUG;
  1672. (* get information *)
  1673. PROCEDURE GETINFO (VAR c: Context);
  1674. VAR sel, val: LONGINT;
  1675. BEGIN
  1676. sel := c.stack[c.tos]; val := 0;
  1677. IF ODD(sel) THEN END; (* give back version number 0 *)
  1678. IF ODD(sel DIV 2) & c.rotated THEN INC(val, 100H) END; (* glyph rotation status *)
  1679. IF ODD(sel DIV 4) & c.stretched THEN INC(val, 200H) END; (* glyph scale status *)
  1680. c.stack[c.tos] := val;
  1681. INC(c.pc)
  1682. END GETINFO;
  1683. (*--- Initialization ---*)
  1684. PROCEDURE InitBuiltins;
  1685. VAR i: LONGINT;
  1686. BEGIN
  1687. FOR i := 0 TO 0FFH DO Builtin[i] := UNDEF END;
  1688. (* pushing data onto the interpreter stack *)
  1689. Builtin[40H] := NPUSHB; Builtin[41H] := NPUSHW;
  1690. FOR i := 0B0H TO 0B7H DO Builtin[i] := PUSHB END;
  1691. FOR i := 0B8H TO 0BFH DO Builtin[i] := PUSHW END;
  1692. (* managing the storage area *)
  1693. Builtin[43H] := RS; Builtin[42H] := WS;
  1694. (* managing the control value table *)
  1695. Builtin[44H] := WCVT; Builtin[70H] := WCVT; Builtin[45H] := RCVT;
  1696. (* managing the graphics state *)
  1697. Builtin[0] := SVTCA; Builtin[1] := SVTCA;
  1698. Builtin[2] := SPVTCA; Builtin[3] := SPVTCA;
  1699. Builtin[4] := SFVTCA; Builtin[5] := SFVTCA;
  1700. Builtin[6] := SPVTL; Builtin[7] := SPVTL;
  1701. Builtin[8] := SFVTL; Builtin[9] := SFVTL;
  1702. Builtin[0EH] := SFVTPV;
  1703. Builtin[86H] := SDPVTL; Builtin[87H] := SDPVTL;
  1704. Builtin[0AH] := SPVFS; Builtin[0BH] := SFVFS;
  1705. Builtin[0CH] := GPV; Builtin[0DH] := GFV;
  1706. Builtin[10H] := SRPi; Builtin[11H] := SRPi; Builtin[12H] := SRPi;
  1707. Builtin[13H] := SZPi; Builtin[14H] := SZPi; Builtin[15H] := SZPi; Builtin[16H] := SZPS;
  1708. Builtin[19H] := RTHG; Builtin[18H] := RTG; Builtin[3DH] := RTDG; Builtin[7DH] := RDTG; Builtin[7CH] := RUTG;
  1709. Builtin[7AH] := ROFF; Builtin[76H] := SROUND; Builtin[77H] := SROUND;
  1710. Builtin[17H] := SLOOP; Builtin[1AH] := SMD; Builtin[8EH] := INSTCTRL;
  1711. Builtin[85H] := SCANCTRL; Builtin[8DH] := SCANTYPE;
  1712. Builtin[1DH] := SCVTCI; Builtin[1EH] := SSWCI; Builtin[1FH] := SSW;
  1713. Builtin[4DH] := FLIPON; Builtin[4EH] := FLIPOFF;
  1714. Builtin[7EH] := SANGW; Builtin[5EH] := SDB; Builtin[5FH] := SDS;
  1715. (* reading and writing data *)
  1716. Builtin[46H] := GC; Builtin[47H] := GC; Builtin[48H] := SCFS; Builtin[49H] := MD; Builtin[4AH] := MD;
  1717. Builtin[4BH] := MPPEM; Builtin[4CH] := MPS;
  1718. (* managing outlines *)
  1719. Builtin[80H] := FLIPPT; Builtin[81H] := FLIPRG; Builtin[82H] := FLIPRG;
  1720. Builtin[32H] := SHP; Builtin[33H] := SHP; Builtin[34H] := SHC; Builtin[35H] := SHC;
  1721. Builtin[36H] := SHZ; Builtin[37H] := SHZ; Builtin[38H] := SHPIX;
  1722. Builtin[3AH] := MSIRP; Builtin[3BH] := MSIRP; Builtin[2EH] := MDAP; Builtin[2FH] := MDAP;
  1723. Builtin[3EH] := MIAP; Builtin[3FH] := MIAP;
  1724. FOR i := 0C0H TO 0DFH DO Builtin[i] := MDRP END;
  1725. FOR i := 0E0H TO 0FFH DO Builtin[i] := MIRP END;
  1726. Builtin[3CH] := ALIGNRP; Builtin[0FH] := ISECT; Builtin[27H] := ALIGNPTS;
  1727. Builtin[39H] := IP; Builtin[29H] := UTP; Builtin[30H] := IUP; Builtin[31H] := IUP;
  1728. (* managing exceptions *)
  1729. Builtin[5DH] := DELTAP; Builtin[71H] := DELTAP; Builtin[72H] := DELTAP;
  1730. Builtin[73H] := DELTAC; Builtin[74H] := DELTAC; Builtin[75H] := DELTAC;
  1731. (* managing the stack *)
  1732. Builtin[20H] := DUP; Builtin[21H] := POP; Builtin[22H] := CLEAR; Builtin[23H] := SWAP;
  1733. Builtin[24H] := DEPTH; Builtin[25H] := CINDEX; Builtin[26H] := MINDEX; Builtin[8AH] := ROLL;
  1734. (* managing the flow of control *)
  1735. Builtin[58H] := iF; Builtin[1BH] := eLSE; Builtin[59H] := EIF;
  1736. Builtin[78H] := JROT; Builtin[1CH] := JUMPR; Builtin[79H] := JROF;
  1737. (* logical functions *)
  1738. Builtin[50H] := COMPARE; Builtin[51H] := COMPARE; Builtin[52H] := COMPARE;
  1739. Builtin[53H] := COMPARE; Builtin[54H] := COMPARE; Builtin[55H] := COMPARE;
  1740. Builtin[56H] := oDD; Builtin[57H] := EVEN;
  1741. Builtin[5AH] := AND; Builtin[5BH] := oR; Builtin[5CH] := NOT;
  1742. (* arithmetic and math instructions *)
  1743. Builtin[60H] := ADD; Builtin[61H] := SUB; Builtin[62H] := dIV; Builtin[63H] := MUL;
  1744. Builtin[64H] := aBS; Builtin[65H] := NEG; Builtin[66H] := Floor; Builtin[67H] := CEILING;
  1745. Builtin[8BH] := mAX; Builtin[8CH] := mIN;
  1746. (* compensating for the engine characteristics *)
  1747. FOR i := 68H TO 6BH DO Builtin[i] := ROUND END;
  1748. FOR i := 6CH TO 6FH DO Builtin[i] := NROUND END;
  1749. (* defining and using functions and instructions *)
  1750. Builtin[2CH] := FDEF; Builtin[2DH] := ENDF; Builtin[2BH] := CALL; Builtin[2AH] := LOOPCALL; Builtin[89H] := IDEF;
  1751. (* miscellaneous instructions *)
  1752. Builtin[4FH] := DEBUG; Builtin[88H] := GETINFO
  1753. END InitBuiltins;
  1754. (*--- Exported Interface ---*)
  1755. (** allocation procedures for all dynamically sized memory structures **)
  1756. PROCEDURE NewCode* (VAR code: Code; size: LONGINT);
  1757. BEGIN
  1758. IF size > 0 THEN NEW(code, size) ELSE code := NIL END
  1759. END NewCode;
  1760. PROCEDURE NewFunctions* (VAR func: Functions; size: LONGINT);
  1761. BEGIN
  1762. IF size > 0 THEN NEW(func, size) ELSE func := NIL END
  1763. END NewFunctions;
  1764. PROCEDURE NewInstructions* (VAR instr: Instructions; size: LONGINT);
  1765. BEGIN
  1766. IF size > 0 THEN NEW(instr, size) ELSE instr := NIL END
  1767. END NewInstructions;
  1768. PROCEDURE NewStore* (VAR store: Store; size: LONGINT);
  1769. BEGIN
  1770. IF size > 0 THEN NEW(store, size) ELSE store := NIL END
  1771. END NewStore;
  1772. PROCEDURE NewCVT* (VAR cvt: CVT; size: LONGINT);
  1773. BEGIN
  1774. IF size > 0 THEN NEW(cvt, size) ELSE cvt := NIL END
  1775. END NewCVT;
  1776. PROCEDURE NewZone* (VAR zone: Zone; contours, points: INTEGER);
  1777. BEGIN
  1778. NEW(zone); zone.contours := contours;
  1779. NEW(zone.first, contours+1);
  1780. IF points > 0 THEN NEW(zone.pt, points) ELSE zone.pt := NIL END;
  1781. zone.first[contours] := points
  1782. END NewZone;
  1783. (** set context stacks **)
  1784. PROCEDURE SetStacks* (VAR c: Context; stack: Stack; callStack: CallStack);
  1785. BEGIN
  1786. c.stack := stack; c.callStack := callStack
  1787. END SetStacks;
  1788. (** set context structures **)
  1789. PROCEDURE SetStructures* (VAR c: Context; func: Functions; instr: Instructions; store: Store; cvt: CVT);
  1790. BEGIN
  1791. c.func := func; c.instr := instr; c.store := store; c.cvt := cvt
  1792. END SetStructures;
  1793. (** set instance specific context parameters **)
  1794. PROCEDURE SetResolution* (VAR c: Context; ptsize, xppm, yppm: F26D6; upm: INTEGER; rotated, stretched: BOOLEAN);
  1795. BEGIN
  1796. c.ptsize := ptsize; c.xppm := xppm; c.yppm := yppm;
  1797. IF xppm >= yppm THEN
  1798. c.ppm := xppm; c.xratio := 10000H; c.yratio := ShiftDiv(yppm, 10H, xppm)
  1799. ELSE
  1800. c.ppm := yppm; c.xratio := ShiftDiv(xppm, 10H, yppm); c.yratio := 10000H
  1801. END;
  1802. c.upm := upm; c.rotated := rotated; c.stretched := stretched
  1803. END SetResolution;
  1804. (** initialize graphic state default values **)
  1805. PROCEDURE InitState* (VAR c: Context);
  1806. BEGIN
  1807. c.cvtCutIn := 40H * 17 DIV 16;
  1808. c.swCutIn := 0; c.swVal := 0;
  1809. c.minDist := 40H;
  1810. c.deltaBase := 9; c.deltaShift := 3;
  1811. c.autoFlip := TRUE;
  1812. c.inhibitFit := FALSE; c.ignorePrep := FALSE;
  1813. c.fixDropouts := FALSE
  1814. END InitState;
  1815. (** save static part of graphic state (e.g. after executing CVT program) **)
  1816. PROCEDURE SaveState* (VAR c: Context; VAR s: State);
  1817. BEGIN
  1818. s.cvtCutIn := c.cvtCutIn;
  1819. s.swCutIn := c.swCutIn; s.swVal := c.swVal;
  1820. s.minDist := c.minDist;
  1821. s.deltaBase := c.deltaBase; s.deltaShift := c.deltaShift;
  1822. s.autoFlip := c.autoFlip;
  1823. s.inhibitFit := c.inhibitFit; s.ignorePrep := c.ignorePrep;
  1824. s.fixDropouts := c.fixDropouts; s.scanType := c.scanType
  1825. END SaveState;
  1826. (** restore static part of graphic state (e.g. before executing a glyph program) **)
  1827. PROCEDURE RestoreState* (VAR c: Context; VAR s: State);
  1828. BEGIN
  1829. c.cvtCutIn := s.cvtCutIn;
  1830. c.swCutIn := s.swCutIn; c.swVal := s.swVal;
  1831. c.minDist := s.minDist;
  1832. c.deltaBase := s.deltaBase; c.deltaShift := s.deltaShift;
  1833. c.autoFlip := s.autoFlip;
  1834. c.inhibitFit := s.inhibitFit; c.ignorePrep := s.ignorePrep;
  1835. c.fixDropouts := s.fixDropouts; c.scanType := s.scanType
  1836. END RestoreState;
  1837. (** execute program **)
  1838. PROCEDURE Execute* (VAR c: Context; code: Code; len: LONGINT; z0, z1: Zone);
  1839. BEGIN
  1840. c.code := code; c.codeLen := len; c.pc := 0; c.tos := -1; c.ctos := -1;
  1841. c.zone[0] := z0; c.zone[1] := z1;
  1842. c.free.x := 4000H; c.free.y := 0;
  1843. c.proj := c.free; c.proj2 := c.free;
  1844. c.gep0 := 1; c.gep1 := 1; c.gep2 := 1;
  1845. c.zp0 := c.zone[c.gep0]; c.zp1 := c.zone[c.gep1]; c.zp2 := c.zone[c.gep2];
  1846. c.rp0 := 0; c.rp1 := 0; c.rp2 := 0;
  1847. c.period := 40H; c.phase := 0; c.threshold := 20H;
  1848. c.loop := 1;
  1849. c.ratio := 0;
  1850. IF Notify # NIL THEN Notify(c, NotifyData) END;
  1851. WHILE c.pc < c.codeLen DO
  1852. Builtin[ORD(c.code[c.pc])](c) (* call primitive for current instruction *)
  1853. END;
  1854. IF Notify # NIL THEN Notify(c, NotifyData) END
  1855. END Execute;
  1856. (** install notify procedure for debug events **)
  1857. PROCEDURE InstallNotifier* (notify: Notifier; data: NotifierData);
  1858. BEGIN
  1859. Notify := notify; NotifyData := data
  1860. END InstallNotifier;
  1861. BEGIN
  1862. InitBuiltins;
  1863. Zero64[0] := 0X; Zero64[1] := 0X; Zero64[2] := 0X; Zero64[3] := 0X;
  1864. Zero64[4] := 0X; Zero64[5] := 0X; Zero64[6] := 0X; Zero64[7] := 0X;
  1865. NewZone(EmptyZone, 0, 0);
  1866. Notify := NIL; NotifyData := NIL
  1867. END OpenTypeInt.