OpenTypeInt.Mod 55 KB

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