OpenType.Mod 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600
  1. MODULE OpenType; (** AUTHOR "eos, PL"; PURPOSE "Bluebottle port of OpenType"; *)
  2. (**
  3. OpenType library (partial implementation; supports only TrueType so far)
  4. **)
  5. (*
  6. 24.05.2000 - introduced cvtLen to deal with fonts that have no CVT
  7. *)
  8. IMPORT
  9. OpenTypeInt, OpenTypeScan,
  10. KernelLog, Strings, Files;
  11. CONST
  12. SharpenContours = TRUE; (* switching off sharpening can result in visually hard to see lines in small chinese fonts *)
  13. CONST
  14. (** name ids **)
  15. Copyright* = 0; Family* = 1; Subfamily* = 2; UniqueID* = 3; FullName* = 4; Version* = 5;
  16. PSName* = 6; Trademark* = 7; Manufacturer* = 8; Designer* = 9; Description* = 10;
  17. VendorURL* = 11; DesignerURL* = 12;
  18. (** LoadGlyph modes **)
  19. Hinted* = 0; Width* = 1; Outline* = 2; Raster* = 3; Grey* = 4;
  20. DefaultCacheSize* = 8; (** maximal number of objects per cache **)
  21. NumTables = 32; (* maximal number of tables in font file *)
  22. CharMapSize = 254; (* number of unicode characters with equivalent Mac character *)
  23. X = OpenTypeInt.X; Y = OpenTypeInt.Y;
  24. Debug = FALSE;
  25. TYPE
  26. Fixed* = OpenTypeInt.Fixed;
  27. F26D6* = OpenTypeInt.F26D6;
  28. F2D14* = OpenTypeInt.F2D14;
  29. FUnit* = OpenTypeInt.FUnit;
  30. CacheObj = POINTER TO CacheObjDesc;
  31. CacheObjDesc = RECORD
  32. prev, next: CacheObj;
  33. stamp: LONGINT;
  34. END;
  35. (** object cache **)
  36. Cache* = RECORD
  37. entries, max: INTEGER; (* current and maximal number of entries *)
  38. sent: CacheObj; (* sentinel of cached object list *)
  39. END;
  40. (* OpenType table directory entry *)
  41. TableEntry = RECORD
  42. tag: LONGINT; (* table identifier *)
  43. checkSum: LONGINT; (* checksum over table *)
  44. offset, length: LONGINT; (* position and length of table within file *)
  45. END;
  46. (** header table **)
  47. FontHeader* = RECORD
  48. flags: INTEGER; (* only using bits 0..4 *)
  49. unitsPerEm*: INTEGER; (** in range 16..16384 **)
  50. xMin*, yMin*, xMax*, yMax*: FUnit; (** bounding box of all glyphs **)
  51. lowestRecPPEM*: INTEGER; (** smallest readable size in pixels **)
  52. indexToLocFormat: INTEGER; (* 'loca' index format *)
  53. END;
  54. (** horizontal header table **)
  55. HorHeader* = RECORD
  56. ascender*, descender*, lineGap*: FUnit; (** typographic ascent, descent and line gap **)
  57. advanceWidthMax*, minLeftSideBearing*, minRightSideBearing*, xMaxExtent*: FUnit; (** calculated over all glyphs **)
  58. numberOfHMetrics: LONGINT; (* number of horizontal metrics entries *)
  59. END;
  60. (* character map table *)
  61. CharMapSegment* = RECORD
  62. start*, end*, delta*, offset*: INTEGER;
  63. END;
  64. CharMapSegments* = POINTER TO ARRAY OF CharMapSegment;
  65. CharMapGlyphs* = POINTER TO ARRAY OF INTEGER;
  66. CharMap* = RECORD
  67. segCount*: INTEGER; (* number of segments *)
  68. seg*: CharMapSegments;
  69. glyph*: CharMapGlyphs;
  70. END;
  71. (** maximum profile table **)
  72. MaxProfile* = RECORD
  73. numGlyphs*: LONGINT; (** number of glyphs in font **)
  74. maxPoints, maxContours: INTEGER;
  75. maxCompositePoints, maxCompositeContours: INTEGER;
  76. maxZones, maxTwilightPoints: INTEGER;
  77. maxStorage: INTEGER;
  78. maxFunctionDefs, maxInstructionDefs: INTEGER;
  79. maxStackElements, maxSizeOfInstructions: INTEGER;
  80. END;
  81. (* horizontal metrics *)
  82. HorMetric = RECORD
  83. aw: INTEGER;
  84. lsb: INTEGER;
  85. END;
  86. HorMetrics = POINTER TO ARRAY OF HorMetric;
  87. (* linear threshold table *)
  88. LinearThresholds = POINTER TO ARRAY OF CHAR;
  89. (** OpenType font object **)
  90. Font* = POINTER TO FontDesc;
  91. FontDesc* = RECORD (CacheObjDesc)
  92. name*: ARRAY 64 OF CHAR; (** font name **)
  93. file*: Files.File; (** font file **)
  94. inst*: Cache; (** cached instances **)
  95. table: ARRAY NumTables OF TableEntry;
  96. numTables: INTEGER;
  97. head*: FontHeader;
  98. hhea*: HorHeader;
  99. cmap*: CharMap;
  100. maxp*: MaxProfile;
  101. hmtx: HorMetrics;
  102. LTSH: LinearThresholds;
  103. fontProg, cvtProg, glyphProg: OpenTypeInt.Code;
  104. func: OpenTypeInt.Functions;
  105. instr: OpenTypeInt.Instructions;
  106. store: OpenTypeInt.Store;
  107. cvt: OpenTypeInt.CVT;
  108. cvtLen: LONGINT;
  109. twilight: OpenTypeInt.Zone;
  110. END;
  111. (** transformation matrix **)
  112. Matrix* = ARRAY 4 OF Fixed;
  113. (** resolution specific font instance **)
  114. Instance* = POINTER TO InstanceDesc;
  115. InstanceDesc* = RECORD (CacheObjDesc)
  116. font*: Font; (** font that instance is derived from **)
  117. ptsize*: F26D6; (** point size **)
  118. xdpi*, ydpi*: INTEGER; (** device resolution in dots per inch **)
  119. xppm*, yppm*: F26D6; (** number of pixels per Em square **)
  120. mat*: Matrix; (** current transform matrix **)
  121. xmin*, ymin*, xmax*, ymax*: F26D6; (** union of all character bounding boxes **)
  122. useHints*, useGrey*: BOOLEAN; (** suggestions for glyphs loaded from this instance **)
  123. rotated, stretched: BOOLEAN; (* is matrix rotated or scaled? *)
  124. aw: POINTER TO ARRAY OF CHAR; (* advance width for each glyph *)
  125. func: OpenTypeInt.Functions;
  126. instr: OpenTypeInt.Instructions;
  127. store: OpenTypeInt.Store;
  128. cvt: OpenTypeInt.CVT;
  129. twilight: OpenTypeInt.Zone;
  130. state: OpenTypeInt.State;
  131. END;
  132. (** glyph structure **)
  133. Glyph* = POINTER TO GlyphDesc;
  134. GlyphDesc* = RECORD
  135. font*: Font; (** font that glyph is compatible with **)
  136. awx*, awy*: INTEGER; (** advance vector **)
  137. hbx*, hby*: INTEGER; (** horizontal bearing (vector from origin to lower left corner of bounding box) **)
  138. rw*, rh*: INTEGER; (** raster width and height **)
  139. xmin*, ymin*, xmax*, ymax*: F26D6; (** outline bounding box **)
  140. lppx, rppx: F26D6; (* phantom point coordinates *)
  141. outline, simple, comp: OpenTypeInt.Zone; (* glyph outline *)
  142. fixDropouts: BOOLEAN;
  143. scanType: INTEGER;
  144. store: OpenTypeInt.Store;
  145. cvt: OpenTypeInt.CVT;
  146. END;
  147. (** glyph outline enumeration **)
  148. OutlineData0* = RECORD END;
  149. OutlineData* = RECORD (OutlineData0)
  150. moveto*: PROCEDURE (x, y: F26D6; VAR data: OutlineData0);
  151. lineto*: PROCEDURE (x, y: F26D6; VAR data: OutlineData0);
  152. bezierto*: PROCEDURE (x, y: ARRAY OF F26D6; n: INTEGER; VAR data: OutlineData0);
  153. END;
  154. (** glyph raster enumeration **)
  155. RasterData0* = RECORD (OpenTypeScan.EnumData) END;
  156. RasterData* = RECORD (RasterData0)
  157. rect*: PROCEDURE (llx, lly, urx, ury, opacity: INTEGER; VAR data: RasterData0);
  158. END;
  159. (**--- Debug ---**)
  160. DebugLogArray = POINTER TO ARRAY OF Strings.String;
  161. DebugLog = OBJECT
  162. VAR log : DebugLogArray;
  163. logEntries : LONGINT;
  164. PROCEDURE &New*;
  165. BEGIN
  166. NEW(log, 16);
  167. logEntries := 0;
  168. END New;
  169. PROCEDURE Add(logEntry : ARRAY OF CHAR);
  170. VAR newLog : DebugLogArray; i : LONGINT;
  171. BEGIN
  172. INC(logEntries);
  173. IF logEntries >= LEN(log) THEN
  174. NEW(newLog, LEN(log)*2); i := 0;
  175. WHILE i < LEN(log) DO
  176. newLog[i] := log[i]; INC(i)
  177. END;
  178. log := newLog
  179. END;
  180. log[logEntries-1] := Strings.NewString(logEntry)
  181. END Add;
  182. PROCEDURE AddB(logEntry : ARRAY OF CHAR; logVal :BOOLEAN);
  183. VAR tString : ARRAY 32 OF CHAR; entry : ARRAY 256 OF CHAR;
  184. BEGIN
  185. COPY(logEntry, entry);
  186. Strings.BoolToStr(logVal, tString);
  187. Strings.Append(entry, tString);
  188. Add(entry)
  189. END AddB;
  190. PROCEDURE AddI(logEntry : ARRAY OF CHAR; logVal : LONGINT);
  191. VAR tString : ARRAY 32 OF CHAR; entry : ARRAY 256 OF CHAR;
  192. BEGIN
  193. COPY(logEntry, entry);
  194. Strings.IntToStr(logVal, tString);
  195. Strings.Append(entry, tString);
  196. Add(entry)
  197. END AddI;
  198. PROCEDURE Flush;
  199. VAR i : LONGINT;
  200. BEGIN
  201. i := 0;
  202. WHILE i < logEntries DO
  203. KernelLog.String(log[i]^); KernelLog.Ln; INC(i)
  204. END;
  205. logEntries := 0
  206. END Flush;
  207. END DebugLog;
  208. (* ------------------------------------- *)
  209. VAR
  210. FontCache*: Cache; (** cache for font objects **)
  211. CharToUnicode*: ARRAY 256 OF INTEGER; (** mapping from Oberon character codes to Unicodes **)
  212. Identity*: Matrix; (** matrix normally used for generating instances **)
  213. CacheStamp: LONGINT; (* next object stamp *)
  214. MacChar, UniChar: ARRAY 256 OF INTEGER; (* corresponding Mac and Unicode characters in ascending Unicode order *)
  215. Log : DebugLog;
  216. (**--- Object Caches ---**)
  217. (** initialize object cache **)
  218. PROCEDURE InitCache* (VAR cache: Cache);
  219. BEGIN
  220. NEW(cache.sent); cache.sent.next := cache.sent; cache.sent.prev := cache.sent;
  221. cache.sent.stamp := MAX(LONGINT);
  222. cache.entries := 0; cache.max := DefaultCacheSize
  223. END InitCache;
  224. (** set new maximal number of objects that are kept in a cache **)
  225. PROCEDURE SetCacheSize* (VAR cache: Cache; max: INTEGER);
  226. BEGIN
  227. cache.max := max;
  228. WHILE cache.entries > max DO
  229. cache.sent.next := cache.sent.next.next;
  230. DEC(cache.entries)
  231. END;
  232. cache.sent.next.prev := cache.sent
  233. END SetCacheSize;
  234. (*
  235. PROCEDURE Stamp (obj: CacheObj);
  236. BEGIN
  237. obj.next.prev := obj.prev; obj.prev.next := obj.next;
  238. obj.stamp := CacheStamp; INC(CacheStamp);
  239. WHILE obj.stamp > obj.next.stamp DO obj.next := obj.next.next END;
  240. obj.prev := obj.next.prev; obj.prev.next := obj; obj.next.prev := obj
  241. END Stamp;
  242. *)
  243. PROCEDURE Append (VAR cache: Cache; obj: CacheObj);
  244. BEGIN
  245. obj.stamp := CacheStamp; INC(CacheStamp);
  246. obj.prev := cache.sent.prev; obj.prev.next := obj;
  247. obj.next := cache.sent; obj.next.prev := obj;
  248. IF cache.entries = cache.max THEN
  249. cache.sent.next := cache.sent.next.next; cache.sent.next.prev := cache.sent
  250. ELSE
  251. INC(cache.entries)
  252. END
  253. END Append;
  254. (**--- Fonts ---**)
  255. (** return location of table within font file (returns whether table was found) **)
  256. PROCEDURE FindTable* (font: Font; name: ARRAY OF CHAR; VAR offset, length: LONGINT): BOOLEAN;
  257. VAR tag, lo, hi, m: LONGINT;
  258. BEGIN
  259. tag := ASH(ASH(ASH(ORD(name[0]), 8) + ORD(name[1]), 8) + ORD(name[2]), 8) + ORD(name[3]);
  260. lo := 0; hi := font.numTables;
  261. WHILE lo+1 < hi DO
  262. m := (lo + hi) DIV 2;
  263. IF font.table[m].tag <= tag THEN lo := m
  264. ELSE hi := m
  265. END
  266. END;
  267. offset := font.table[lo].offset; length := font.table[lo].length;
  268. RETURN font.table[lo].tag = tag
  269. END FindTable;
  270. (** read big endian 2 byte integer **)
  271. PROCEDURE ReadInt* (VAR r: Files.Rider; VAR i: INTEGER);
  272. VAR c: ARRAY 2 OF CHAR;
  273. BEGIN
  274. r.file.ReadBytes(r, c, 0, 2);
  275. i := 100H*ORD(c[0]) + ORD(c[1])
  276. END ReadInt;
  277. (** read big endian 4 byte integer **)
  278. PROCEDURE ReadLInt* (VAR r: Files.Rider; VAR l: LONGINT);
  279. VAR c: ARRAY 4 OF CHAR;
  280. BEGIN
  281. r.file.ReadBytes(r, c, 0, 4);
  282. l := ASH(ORD(c[0]), 24) + ASH(ORD(c[1]), 16) + ASH(ORD(c[2]), 8) + ORD(c[3])
  283. END ReadLInt;
  284. (** read big endian 2 byte integer **)
  285. PROCEDURE Read16U* (VAR r: Files.Rider; VAR i: LONGINT);
  286. VAR c: ARRAY 2 OF CHAR;
  287. BEGIN
  288. r.file.ReadBytes(r, c, 0, 2);
  289. i := 100H* LONG(ORD(c[0])) + LONG(ORD(c[1]))
  290. END Read16U;
  291. PROCEDURE LoadHeader (font: Font): BOOLEAN;
  292. VAR pos, len, version, magic: LONGINT; r: Files.Rider; gformat: INTEGER;
  293. BEGIN
  294. IF ~FindTable(font, "head", pos, len) THEN RETURN FALSE END;
  295. font.file.Set(r, pos); ReadLInt(r, version);
  296. IF version # 10000H THEN RETURN FALSE END;
  297. r.file.Set(r,pos+12); ReadLInt(r, magic);
  298. IF magic # 5F0F3CF5H THEN RETURN FALSE END;
  299. ReadInt(r, font.head.flags); ReadInt(r, font.head.unitsPerEm);
  300. font.file.Set(r, pos+36);
  301. ReadInt(r, font.head.xMin); ReadInt(r, font.head.yMin);
  302. ReadInt(r, font.head.xMax); ReadInt(r, font.head.yMax);
  303. font.file.Set(r, pos+46);
  304. ReadInt(r, font.head.lowestRecPPEM);
  305. font.file.Set(r, pos+50);
  306. ReadInt(r, font.head.indexToLocFormat);
  307. ReadInt(r, gformat);
  308. RETURN gformat = 0
  309. END LoadHeader;
  310. PROCEDURE LoadHorHeader (font: Font): BOOLEAN;
  311. VAR pos, len, version: LONGINT; r: Files.Rider; mformat: INTEGER;
  312. BEGIN
  313. IF ~FindTable(font, "hhea", pos, len) THEN RETURN FALSE END;
  314. font.file.Set(r, pos); ReadLInt(r, version);
  315. IF version # 10000H THEN RETURN FALSE END;
  316. ReadInt(r, font.hhea.ascender); ReadInt(r, font.hhea.descender); ReadInt(r, font.hhea.lineGap);
  317. IF Debug THEN KernelLog.String("Ascender: "); KernelLog.Int(font.hhea.ascender, 0); KernelLog.Ln END;
  318. IF Debug THEN KernelLog.String("Descender: "); KernelLog.Int(font.hhea.descender, 0); KernelLog.Ln END;
  319. IF Debug THEN KernelLog.String("LineGap: "); KernelLog.Int(font.hhea.lineGap, 0); KernelLog.Ln END;
  320. ReadInt(r, font.hhea.advanceWidthMax); ReadInt(r, font.hhea.minLeftSideBearing);
  321. IF Debug THEN KernelLog.String("AdvanceWidthMax: "); KernelLog.Int(font.hhea.advanceWidthMax, 0); KernelLog.Ln END;
  322. IF Debug THEN KernelLog.String("LeftSideBearing: "); KernelLog.Int(font.hhea.minLeftSideBearing, 0); KernelLog.Ln END;
  323. ReadInt(r, font.hhea.minRightSideBearing); ReadInt(r, font.hhea.xMaxExtent);
  324. IF Debug THEN KernelLog.String("RightSideBearing: "); KernelLog.Int(font.hhea.minRightSideBearing, 0); KernelLog.Ln END;
  325. IF Debug THEN KernelLog.String("xMaxExtent: "); KernelLog.Int(font.hhea.xMaxExtent, 0); KernelLog.Ln END;
  326. font.file.Set(r, pos+32); ReadInt(r, mformat);
  327. Read16U(r, font.hhea.numberOfHMetrics);
  328. IF Debug THEN KernelLog.String("Num of HMetrics: "); KernelLog.Int(font.hhea.numberOfHMetrics, 0); KernelLog.Ln END;
  329. RETURN mformat = 0
  330. END LoadHorHeader;
  331. PROCEDURE LoadCharMap (font: Font): BOOLEAN;
  332. VAR
  333. r: Files.Rider; pos, length, offset, s, p: LONGINT;
  334. version, tables, t, platform, encoding, format, n, len, segCountX2, pad, off: INTEGER;
  335. found: BOOLEAN; glyph: ARRAY 256 OF CHAR; uni: ARRAY CharMapSize OF INTEGER;
  336. BEGIN
  337. IF ~FindTable(font, "cmap", pos, length) THEN
  338. IF Debug THEN Log.Add("CMAP Table not found"); Log.Flush END;
  339. RETURN FALSE
  340. END;
  341. font.file.Set(r, pos); ReadInt(r, version);
  342. IF version # 0 THEN
  343. IF Debug THEN Log.AddI("Version is not 0: ", version); Log.Flush END;
  344. RETURN FALSE
  345. END;
  346. ReadInt(r, tables);
  347. IF Debug THEN Log.AddI("Number of CMAP tables: ", tables); END;
  348. found := FALSE;
  349. t := 0;
  350. WHILE t < tables DO
  351. r.file.Set(r, pos + 4 + 8*t);
  352. ReadInt(r, platform); ReadInt(r, encoding); ReadLInt(r, offset); INC(offset, pos);
  353. IF (platform = 3) & (encoding = 1) THEN (* found Microsoft Unicode encoding *)
  354. IF Debug THEN Log.Add("found platform ID 3 encoding 1") END;
  355. font.file.Set(r, offset); ReadInt(r, format);
  356. IF format # 4 THEN
  357. IF Debug THEN Log.AddI("format for platform 3:1 not supported: ", format) END;
  358. ELSE
  359. ReadInt(r, len); ReadInt(r, version); ReadInt(r, segCountX2);
  360. font.cmap.segCount := segCountX2 DIV 2;
  361. IF Debug THEN Log.AddI("SegCount: ", font.cmap.segCount) END;
  362. NEW(font.cmap.seg, font.cmap.segCount);
  363. font.file.Set(r, offset+14);
  364. n := 0; WHILE n < font.cmap.segCount DO ReadInt(r, font.cmap.seg[n].end); INC(n) END;
  365. ReadInt(r, pad);
  366. n := 0; WHILE n < font.cmap.segCount DO ReadInt(r, font.cmap.seg[n].start); INC(n) END;
  367. n := 0; WHILE n < font.cmap.segCount DO ReadInt(r, font.cmap.seg[n].delta); INC(n) END;
  368. n := 0;
  369. WHILE n < font.cmap.segCount DO
  370. ReadInt(r, off);
  371. IF off = 0 THEN font.cmap.seg[n].offset := -1
  372. ELSE font.cmap.seg[n].offset := off DIV 2 - (font.cmap.segCount - n)
  373. END;
  374. INC(n)
  375. END;
  376. len := SHORT(offset + len - r.file.Pos(r)) DIV 2;
  377. IF len > 0 THEN
  378. NEW(font.cmap.glyph, len);
  379. n := 0; WHILE n < len DO ReadInt(r, font.cmap.glyph[n]); INC(n) END;
  380. IF Debug THEN Log.AddI("Glyphs added: ", len) END
  381. ELSE
  382. font.cmap.glyph := NIL
  383. END;
  384. RETURN TRUE;
  385. END;
  386. ELSIF (platform = 1) & (encoding = 0) THEN
  387. IF Debug THEN Log.Add("found platform ID 1 encoding 0") END;
  388. font.file.Set(r, offset); ReadInt(r, format);
  389. IF format # 0 THEN
  390. IF Debug THEN Log.AddI("format for platform 1:0 not supported: ", format) END;
  391. ELSE
  392. ReadInt(r, len); ReadInt(r, version);
  393. r.file.ReadBytes(r, glyph, 0,256);
  394. FOR n := 0 TO CharMapSize-1 DO
  395. uni[n] := ORD(glyph[MacChar[n]]) (* character UniChar[n] now has glyph uni[n] *)
  396. END;
  397. p := 0; s := 0;
  398. FOR n := 0 TO CharMapSize-1 DO
  399. IF uni[n] # 0 THEN (* UniChar[n] is defined *)
  400. IF (n = 0) OR (uni[n-1] = 0) OR (UniChar[n-1] + 1 # UniChar[n]) THEN
  401. INC(s)
  402. END;
  403. INC(p)
  404. END
  405. END;
  406. font.cmap.segCount := SHORT(s);
  407. NEW(font.cmap.seg, s+1); (* add one for the sentinel segment *)
  408. NEW(font.cmap.glyph, p);
  409. s := 0; p := 0;
  410. FOR n := 0 TO CharMapSize-1 DO
  411. IF uni[n] # 0 THEN
  412. IF (n = 0) OR (uni[n-1] = 0) OR (UniChar[n-1] + 1 # UniChar[n]) THEN
  413. font.cmap.seg[s].start := UniChar[n];
  414. font.cmap.seg[s].delta := 0;
  415. font.cmap.seg[s].offset := SHORT(p)
  416. END;
  417. IF (n = CharMapSize-1) OR (UniChar[n+1] = 0) OR (UniChar[n+1] - 1 # UniChar[n]) THEN
  418. font.cmap.seg[s].end := UniChar[n];
  419. INC(s)
  420. END;
  421. font.cmap.glyph[p] := uni[n];
  422. INC(p)
  423. END
  424. END;
  425. font.cmap.seg[s].start := -1; (* = FFFF *)
  426. font.cmap.seg[s].end := -1; (* = FFFF *)
  427. font.cmap.seg[s].delta := 1;
  428. font.cmap.seg[s].offset := -1;
  429. found := TRUE
  430. END
  431. ELSE
  432. IF Debug THEN
  433. Log.AddI("Platform not supported: ", platform);
  434. Log.AddI("Encoding: ",encoding)
  435. END;
  436. END;
  437. INC(t)
  438. END;
  439. RETURN found
  440. END LoadCharMap;
  441. PROCEDURE LoadMaxProfile (font: Font): BOOLEAN;
  442. VAR pos, len, version: LONGINT; r: Files.Rider;
  443. BEGIN
  444. IF ~FindTable(font, "maxp", pos, len) THEN RETURN FALSE END;
  445. font.file.Set(r, pos); ReadLInt(r, version);
  446. IF version # 10000H THEN RETURN FALSE END; (* only TrueType supported so far *)
  447. Read16U(r, font.maxp.numGlyphs);
  448. IF Debug THEN KernelLog.String("Num of Glyphs: "); KernelLog.Int(font.maxp.numGlyphs, 0); KernelLog.Ln END;
  449. ReadInt(r, font.maxp.maxPoints); ReadInt(r, font.maxp.maxContours);
  450. IF Debug THEN KernelLog.String("Num of Points: "); KernelLog.Int(font.maxp.maxPoints, 0); KernelLog.Ln END;
  451. IF Debug THEN KernelLog.String("Num of Contours: "); KernelLog.Int(font.maxp.maxContours, 0); KernelLog.Ln END;
  452. ReadInt(r, font.maxp.maxCompositePoints); ReadInt(r, font.maxp.maxCompositeContours);
  453. IF Debug THEN KernelLog.String("Num of Comp Points: "); KernelLog.Int(font.maxp.maxCompositePoints, 0); KernelLog.Ln END;
  454. IF Debug THEN KernelLog.String("Num of Comp Countours: "); KernelLog.Int(font.maxp.maxCompositeContours, 0); KernelLog.Ln END;
  455. ReadInt(r, font.maxp.maxZones); ReadInt(r, font.maxp.maxTwilightPoints);
  456. IF Debug THEN KernelLog.String("Num of maxZones: "); KernelLog.Int(font.maxp.maxZones, 0); KernelLog.Ln END;
  457. IF Debug THEN KernelLog.String("Num of maxTwilight: "); KernelLog.Int(font.maxp.maxTwilightPoints, 0); KernelLog.Ln END;
  458. ReadInt(r, font.maxp.maxStorage); ReadInt(r, font.maxp.maxFunctionDefs);
  459. IF Debug THEN KernelLog.String("Num of maxStorage: "); KernelLog.Int(font.maxp.maxStorage, 0); KernelLog.Ln END;
  460. IF Debug THEN KernelLog.String("Num of maxFuncDefs: "); KernelLog.Int(font.maxp.maxFunctionDefs, 0); KernelLog.Ln END;
  461. IF font.maxp.maxFunctionDefs = 0 THEN font.maxp.maxFunctionDefs := 64 END; (* seems to be necessary *)
  462. ReadInt(r, font.maxp.maxInstructionDefs); ReadInt(r, font.maxp.maxStackElements);
  463. IF Debug THEN KernelLog.String("Num of InstructionDefs: "); KernelLog.Int(font.maxp.maxInstructionDefs, 0); KernelLog.Ln END;
  464. IF Debug THEN KernelLog.String("Num of maxStackElems: "); KernelLog.Int(font.maxp.maxStackElements, 0); KernelLog.Ln END;
  465. ReadInt(r, font.maxp.maxSizeOfInstructions);
  466. IF Debug THEN KernelLog.String("MaxSize of Instruction: "); KernelLog.Int(font.maxp.maxSizeOfInstructions, 0); KernelLog.Ln END;
  467. RETURN TRUE
  468. END LoadMaxProfile;
  469. PROCEDURE LoadHorMetrics (font: Font): BOOLEAN;
  470. VAR pos, len: LONGINT; r: Files.Rider; aw: INTEGER; n: LONGINT;
  471. BEGIN
  472. IF ~FindTable(font, "hmtx", pos, len) THEN RETURN FALSE END;
  473. NEW(font.hmtx, font.maxp.numGlyphs);
  474. font.file.Set(r, pos);
  475. n := 0;
  476. WHILE n < font.hhea.numberOfHMetrics DO
  477. ReadInt(r, font.hmtx[n].aw); ReadInt(r, font.hmtx[n].lsb);
  478. INC(n)
  479. END;
  480. aw := font.hmtx[n-1].aw;
  481. WHILE n < font.maxp.numGlyphs DO
  482. font.hmtx[n].aw := aw; ReadInt(r, font.hmtx[n].lsb);
  483. INC(n)
  484. END;
  485. RETURN TRUE
  486. END LoadHorMetrics;
  487. PROCEDURE LoadCVT (font: Font);
  488. VAR pos, len, n: LONGINT; r: Files.Rider; val: FUnit;
  489. BEGIN
  490. font.cvt := NIL; font.cvtLen := 0;
  491. IF FindTable(font, "cvt ", pos, len) THEN
  492. font.cvtLen := len DIV 2;
  493. OpenTypeInt.NewCVT(font.cvt, font.cvtLen);
  494. font.file.Set(r, pos);
  495. FOR n := 0 TO font.cvtLen-1 DO
  496. ReadInt(r, val); font.cvt[n] := val
  497. END
  498. END
  499. END LoadCVT;
  500. PROCEDURE LoadLinearThresholds (font: Font);
  501. VAR pos, len: LONGINT; r: Files.Rider; numGlyphs: LONGINT;
  502. BEGIN
  503. font.LTSH := NIL;
  504. IF FindTable(font, "LTSH", pos, len) THEN
  505. NEW(font.LTSH, font.maxp.numGlyphs);
  506. font.file.Set(r, pos+2);
  507. Read16U(r, numGlyphs);
  508. IF numGlyphs >= font.maxp.numGlyphs THEN
  509. r.file.ReadBytes(r, font.LTSH^, 0, font.maxp.numGlyphs)
  510. ELSE
  511. r.file.ReadBytes(r, font.LTSH^, 0, numGlyphs);
  512. WHILE numGlyphs < font.maxp.numGlyphs DO
  513. font.LTSH[numGlyphs] := 0FFX;
  514. INC(numGlyphs)
  515. END
  516. END
  517. END
  518. END LoadLinearThresholds;
  519. PROCEDURE LoadFont (font: Font): BOOLEAN;
  520. VAR r: Files.Rider; n: LONGINT; ok: BOOLEAN;
  521. lh, lhh, lcm, lmp, lhm : BOOLEAN;
  522. BEGIN
  523. (* load table directory *)
  524. font.file.Set(r, 4); ReadInt(r, font.numTables);
  525. IF font.numTables > NumTables THEN
  526. font.numTables := NumTables (* this is somewhat crude, but unlikely to ever happen *)
  527. END;
  528. font.file.Set(r, 12); n := 0;
  529. WHILE n < font.numTables DO
  530. ReadLInt(r, font.table[n].tag);
  531. ReadLInt(r, font.table[n].checkSum);
  532. ReadLInt(r, font.table[n].offset);
  533. ReadLInt(r, font.table[n].length);
  534. INC(n)
  535. END;
  536. (* load required tables *)
  537. IF Debug THEN
  538. Log.Add("-- LoadHeader: "); lh := LoadHeader(font); Log.AddB("status: ", lh);
  539. Log.Add("-- LoadHorHeader: "); lhh := LoadHorHeader(font); Log.AddB("status: ", lhh);
  540. Log.Add("-- LoadCharMap: "); lcm := LoadCharMap(font); Log.AddB("status: ", lcm);
  541. Log.Add("-- LoadMaxProfile: "); lmp := LoadMaxProfile(font); Log.AddB("status: ", lmp);
  542. Log.Add("-- LoadHorMetrics: "); lhm := LoadHorMetrics(font); Log.AddB("status: ", lhm);
  543. Log.Flush;
  544. ok := lh & lhh & lcm & lmp & lhm
  545. ELSE
  546. ok :=
  547. LoadHeader(font) &
  548. LoadHorHeader(font) &
  549. LoadCharMap(font) &
  550. LoadMaxProfile(font) &
  551. LoadHorMetrics(font);
  552. END;
  553. IF ok THEN
  554. (* load optional structures *)
  555. IF Debug THEN KernelLog.String("LoadCVT"); KernelLog.Ln END;
  556. LoadCVT(font);
  557. IF Debug THEN KernelLog.String("LoadLinearThresholds"); KernelLog.Ln END;
  558. LoadLinearThresholds(font);
  559. (* allocate structures *)
  560. IF Debug THEN KernelLog.String("NewCode: "); KernelLog.Int(font.maxp.maxSizeOfInstructions, 0); KernelLog.Ln END;
  561. OpenTypeInt.NewCode(font.glyphProg, font.maxp.maxSizeOfInstructions);
  562. IF Debug THEN KernelLog.String("NewStack: "); KernelLog.Int(font.maxp.maxStackElements, 0); KernelLog.Ln END;
  563. IF Debug THEN KernelLog.String("NewFunctions: "); KernelLog.Int(font.maxp.maxFunctionDefs, 0); KernelLog.Ln END;
  564. OpenTypeInt.NewFunctions(font.func, font.maxp.maxFunctionDefs);
  565. IF Debug THEN KernelLog.String("NewInstructions: "); KernelLog.Int(font.maxp.maxInstructionDefs, 0); KernelLog.Ln END;
  566. OpenTypeInt.NewInstructions(font.instr, font.maxp.maxInstructionDefs);
  567. IF Debug THEN KernelLog.String("NewStore: "); KernelLog.Int(font.maxp.maxStorage, 0); KernelLog.Ln END;
  568. OpenTypeInt.NewStore(font.store, font.maxp.maxStorage);
  569. IF Debug THEN KernelLog.String("NewZone: "); KernelLog.Int(font.maxp.maxTwilightPoints, 0); KernelLog.Ln END;
  570. OpenTypeInt.NewZone(font.twilight, 1, font.maxp.maxTwilightPoints);
  571. IF Debug THEN KernelLog.String("-- done"); KernelLog.Ln END;
  572. ok := font.maxp.maxStackElements <= OpenTypeInt.StackSize;
  573. END;
  574. RETURN ok
  575. END LoadFont;
  576. PROCEDURE ExecFontProg (font: Font);
  577. VAR pos, len: LONGINT; r: Files.Rider; context: OpenTypeInt.Context;
  578. BEGIN
  579. IF FindTable(font, "fpgm", pos, len) THEN
  580. IF Debug THEN KernelLog.String("fpgm execution started"); KernelLog.Ln END;
  581. OpenTypeInt.NewCode(font.fontProg, len);
  582. font.file.Set(r, pos);
  583. r.file.ReadBytes(r, font.fontProg^, 0,len);
  584. OpenTypeInt.SetStructures(context, font.func, font.instr, font.store, font.cvt);
  585. OpenTypeInt.SetResolution(context, 10*40H, (10*40H+36) DIV 72, (10*40H+36) DIV 72, font.head.unitsPerEm, FALSE, FALSE);
  586. OpenTypeInt.InitState(context);
  587. OpenTypeInt.Execute(context, font.fontProg, len, OpenTypeInt.EmptyZone, OpenTypeInt.EmptyZone);
  588. IF Debug THEN KernelLog.String("fpgm execution ended"); KernelLog.Ln END;
  589. END
  590. END ExecFontProg;
  591. (** open a OpenType font file; file name extension and path may be omitted; returns NIL if not found **)
  592. PROCEDURE Open* (name: ARRAY OF CHAR): Font;
  593. VAR fname, temp, ext: Files.FileName; obj: CacheObj; file: Files.File; r: Files.Rider; version: LONGINT; font: Font;
  594. BEGIN
  595. NEW(Log);
  596. COPY(name, fname);
  597. Strings.GetExtension(name, temp, ext);
  598. IF ext[0] = 0X THEN
  599. Strings.Append(fname, ".TTF")
  600. ELSE
  601. name[Strings.Length(name) - Strings.Length(ext) - 1] := 0X
  602. END;
  603. (* find font in cache *)
  604. obj := FontCache.sent.next;
  605. WHILE obj # FontCache.sent DO
  606. IF obj(Font).name = name THEN
  607. RETURN obj(Font)
  608. END;
  609. obj := obj.next
  610. END;
  611. (* try to open font file *)
  612. file := Files.Old(fname);
  613. IF (file = NIL) & (ext[0] = 0X) THEN (* try extension '.OTF' if none was specified *)
  614. COPY(name, fname); Strings.Append(fname, ".OTF");
  615. file := Files.Old(fname)
  616. END;
  617. IF file # NIL THEN
  618. file.Set(r, 0); ReadLInt(r, version);
  619. IF version = 10000H THEN (* 'OTTO' (including CFF outlines) not supported *)
  620. NEW(font); COPY(name, font.name); font.file := file;
  621. IF LoadFont(font) THEN
  622. Append(FontCache, font);
  623. InitCache(font.inst);
  624. ExecFontProg(font);
  625. RETURN font
  626. ELSE
  627. IF Debug THEN Log.Add("## loading error") END
  628. END
  629. ELSE
  630. IF Debug THEN Log.Add("## wrong version") END
  631. END
  632. END;
  633. IF Debug THEN Log.Flush END;
  634. RETURN NIL (* failed to load font *)
  635. END Open;
  636. (** get entry from name table; whenever possible, a string in English is returned **)
  637. PROCEDURE GetName* (font: Font; id: INTEGER; VAR name: ARRAY OF CHAR);
  638. VAR
  639. pos, len, off: LONGINT;
  640. r: Files.Rider;
  641. unicode: BOOLEAN;
  642. n, offset, platform, encoding, language, nameID, l, o: INTEGER;
  643. dummy: CHAR;
  644. BEGIN
  645. name[0] := 0X;
  646. IF FindTable(font, "name", pos, len) THEN
  647. off := -1; len := 0; unicode := FALSE;
  648. font.file.Set(r, pos+2); ReadInt(r, n); ReadInt(r, offset);
  649. WHILE n > 0 DO
  650. ReadInt(r, platform); ReadInt(r, encoding); ReadInt(r, language); ReadInt(r, nameID);
  651. ReadInt(r, l); ReadInt(r, o);
  652. IF nameID = id THEN
  653. off := o; len := l;
  654. IF (platform = 3) & (encoding = 1) & (language MOD 100H = 9) THEN
  655. n := 1; unicode := TRUE
  656. ELSIF (platform = 1) & (encoding = 0) & (language = 0) THEN
  657. n := 1
  658. END
  659. END;
  660. DEC(n)
  661. END;
  662. IF off >= 0 THEN
  663. font.file.Set(r, pos + offset + off);
  664. l := 0;
  665. WHILE len > 0 DO
  666. IF unicode THEN
  667. r.file.Read(r, dummy); DEC(len) (* skip high byte *)
  668. END;
  669. r.file.Read(r, name[l]); INC(l); DEC(len)
  670. END;
  671. name[l] := 0X
  672. END
  673. END
  674. END GetName;
  675. (** map Unicode character code to glyph number **)
  676. PROCEDURE UnicodeToGlyph* (font: Font; code: LONGINT): LONGINT;
  677. VAR lo, hi, m, start, end, delta, offset, idx: LONGINT;
  678. BEGIN
  679. lo := 0; hi := font.cmap.segCount;
  680. WHILE lo+1 < hi DO
  681. m := (lo + hi) DIV 2;
  682. IF LONG(font.cmap.seg[m].start) MOD 10000H <= code THEN lo := m
  683. ELSE hi := m
  684. END
  685. END;
  686. start := LONG(font.cmap.seg[lo].start) MOD 10000H;
  687. end := LONG(font.cmap.seg[lo].end) MOD 10000H;
  688. IF (start <= code) & (code <= end) THEN
  689. delta := font.cmap.seg[lo].delta; offset := font.cmap.seg[lo].offset;
  690. IF offset < 0 THEN
  691. RETURN (code + delta) MOD 10000H
  692. ELSE
  693. idx := font.cmap.glyph[code - start + offset];
  694. IF idx = 0 THEN
  695. RETURN 0
  696. ELSE
  697. RETURN (idx + delta) MOD 10000H
  698. END
  699. END
  700. ELSE
  701. RETURN 0
  702. END
  703. END UnicodeToGlyph;
  704. (**--- Instances ---**)
  705. PROCEDURE CalcPPEm (font: Font; ptsize: F26D6; xdpi, ydpi: INTEGER; VAR xppm, yppm: F26D6);
  706. BEGIN
  707. xppm := OpenTypeInt.MulDiv(ptsize, xdpi, 72);
  708. yppm := OpenTypeInt.MulDiv(ptsize, ydpi, 72);
  709. IF ODD(font.head.flags DIV 8) THEN (* round ppem to integer *)
  710. xppm := (xppm + 20H) DIV 40H * 40H;
  711. yppm := (yppm + 20H) DIV 40H * 40H
  712. END
  713. END CalcPPEm;
  714. (** get an instance for an opened font (an instance has fixed point size and resolution) **)
  715. PROCEDURE GetInstance* (font: Font; ptsize: F26D6; xdpi, ydpi: INTEGER; mat: Matrix; VAR inst: Instance);
  716. VAR
  717. xppm, yppm, ppm, lo, hi, xmin, xmax, ymin, ymax: F26D6; obj: CacheObj; i, pos, len, size: LONGINT;
  718. context: OpenTypeInt.Context; r: Files.Rider; version, n, maxPPM, flags: INTEGER; ch: CHAR;
  719. BEGIN
  720. CalcPPEm(font, ptsize, xdpi, ydpi, xppm, yppm);
  721. obj := font.inst.sent;
  722. WHILE obj # font.inst.sent DO
  723. inst := obj(Instance);
  724. IF (inst.xppm = xppm) & (inst.yppm = yppm) &
  725. (~ODD(font.head.flags DIV 4) OR (inst.ptsize = ptsize)) &
  726. (inst.mat[0] = mat[0]) & (inst.mat[1] = mat[1]) & (inst.mat[2] = mat[2]) & (inst.mat[3] = mat[3])
  727. THEN
  728. RETURN
  729. END;
  730. obj := obj.next
  731. END;
  732. NEW(inst); inst.font := font;
  733. inst.ptsize := ptsize;
  734. inst.xdpi := xdpi; inst.ydpi := ydpi;
  735. inst.xppm := xppm; inst.yppm := yppm;
  736. IF xppm >= yppm THEN ppm := xppm ELSE ppm := yppm END;
  737. inst.mat[0] := mat[0]; inst.mat[1] := mat[1];
  738. inst.mat[2] := mat[2]; inst.mat[3] := mat[3];
  739. inst.rotated := (mat[1] # 0) OR (mat[2] # 0);
  740. inst.stretched := (mat[0] # 10000H) OR (mat[3] # 10000H);
  741. Append(font.inst, inst);
  742. OpenTypeInt.NewFunctions(inst.func, font.maxp.maxFunctionDefs);
  743. OpenTypeInt.NewInstructions(inst.instr, font.maxp.maxInstructionDefs);
  744. OpenTypeInt.NewStore(inst.store, font.maxp.maxStorage);
  745. OpenTypeInt.NewCVT(inst.cvt, font.cvtLen);
  746. OpenTypeInt.NewZone(inst.twilight, 1, font.maxp.maxTwilightPoints);
  747. FOR i := 0 TO font.maxp.maxFunctionDefs-1 DO inst.func[i] := font.func[i] END;
  748. FOR i := 0 TO font.maxp.maxInstructionDefs-1 DO inst.instr[i] := font.instr[i] END;
  749. FOR i := 0 TO font.maxp.maxStorage-1 DO inst.store[i] := font.store[i] END;
  750. FOR i := 0 TO font.cvtLen-1 DO
  751. inst.cvt[i] := OpenTypeInt.MulDiv(font.cvt[i], ppm, font.head.unitsPerEm)
  752. END;
  753. OpenTypeInt.InitState(context);
  754. IF FindTable(font, "prep", pos, len) THEN (* load and execute cvt program *)
  755. IF Debug THEN KernelLog.String("Processing prep table"); KernelLog.Ln END;
  756. IF font.cvtProg = NIL THEN
  757. OpenTypeInt.NewCode(font.cvtProg, len);
  758. font.file.Set(r, pos);
  759. r.file.ReadBytes(r, font.cvtProg^, 0,len)
  760. END;
  761. OpenTypeInt.SetStructures(context, inst.func, inst.instr, inst.store, inst.cvt);
  762. OpenTypeInt.SetResolution(context, ptsize, xppm, yppm, font.head.unitsPerEm, inst.rotated, inst.stretched);
  763. OpenTypeInt.Execute(context, font.cvtProg, len, inst.twilight, OpenTypeInt.EmptyZone)
  764. END;
  765. OpenTypeInt.SaveState(context, inst.state);
  766. inst.xmin := OpenTypeInt.MulDiv(font.head.xMin, ppm, font.head.unitsPerEm);
  767. inst.ymin := OpenTypeInt.MulDiv(font.head.yMin, ppm, font.head.unitsPerEm);
  768. inst.xmax := OpenTypeInt.MulDiv(font.head.xMax, ppm, font.head.unitsPerEm);
  769. inst.ymax := OpenTypeInt.MulDiv(font.head.yMax, ppm, font.head.unitsPerEm);
  770. IF inst.rotated OR inst.stretched THEN
  771. lo := OpenTypeInt.MulShift(inst.xmin, mat[0], -16); hi := OpenTypeInt.MulShift(inst.xmax, mat[0], -16);
  772. IF lo <= hi THEN xmin := lo; xmax := hi ELSE xmin := hi; xmax := lo END;
  773. lo := OpenTypeInt.MulShift(inst.ymin, mat[2], -16); hi := OpenTypeInt.MulShift(inst.ymax, mat[2], -16);
  774. IF lo <= hi THEN xmin := xmin + lo; xmax := xmax + hi ELSE xmin := xmin + hi; xmax := xmax + lo END;
  775. lo := OpenTypeInt.MulShift(inst.xmin, mat[1], -16); hi := OpenTypeInt.MulShift(inst.xmax, mat[1], -16);
  776. IF lo <= hi THEN ymin := lo; ymax := hi ELSE ymin := hi; ymax := lo END;
  777. lo := OpenTypeInt.MulShift(inst.ymin, mat[3], -16); hi := OpenTypeInt.MulShift(inst.ymax, mat[3], -16);
  778. IF lo <= hi THEN ymin := ymin + lo; ymax := ymax + hi ELSE ymin := ymin + hi; ymax := ymax + lo END;
  779. inst.xmin := xmin; inst.ymin := ymin; inst.xmax := xmax; inst.ymax := ymax
  780. END;
  781. inst.useHints := TRUE; inst.useGrey := FALSE;
  782. IF FindTable(font, "gasp", pos, len) THEN (* get suggestion for hinting and grayscale usage *)
  783. IF Debug THEN KernelLog.String("Processing gasp table"); KernelLog.Ln END;
  784. font.file.Set(r, pos);
  785. ReadInt(r, version);
  786. IF version = 0 THEN
  787. ReadInt(r, n);
  788. REPEAT
  789. ReadInt(r, maxPPM); ReadInt(r, flags)
  790. UNTIL (yppm <= 40H*maxPPM) OR r.eof;
  791. inst.useHints := ODD(flags);
  792. inst.useGrey := ODD(flags DIV 2)
  793. END
  794. END;
  795. inst.aw := NIL;
  796. IF FindTable(font, "hdmx", pos, len) THEN (* get horizontal device metrics *)
  797. IF Debug THEN KernelLog.String("Processing hdmx table"); KernelLog.Ln END;
  798. font.file.Set(r, pos+2);
  799. ReadInt(r, n); ReadLInt(r, size);
  800. REPEAT
  801. r.file.Read(r, ch);
  802. IF ORD(ch) = yppm DIV 40H THEN
  803. r.file.Read(r, ch);
  804. NEW(inst.aw, font.maxp.numGlyphs);
  805. r.file.ReadBytes(r, inst.aw^, 0, font.maxp.numGlyphs);
  806. n := 0
  807. ELSE
  808. font.file.Set(r, font.file.Pos(r) - 1 + size);
  809. DEC(n)
  810. END
  811. UNTIL n = 0
  812. END;
  813. IF Debug THEN KernelLog.String("## finished"); KernelLog.Ln END
  814. END GetInstance;
  815. (**--- Glyphs ---**)
  816. (** initialize glyph structure to be compatible with given font **)
  817. PROCEDURE InitGlyph* (glyph: Glyph; font: Font);
  818. BEGIN
  819. glyph.font := font;
  820. IF Debug THEN KernelLog.String("max Contours: "); KernelLog.Int(font.maxp.maxContours, 0); KernelLog.String(" NewZone Simple: "); KernelLog.Int(font.maxp.maxPoints+2, 0); KernelLog.Ln END;
  821. OpenTypeInt.NewZone(glyph.simple, font.maxp.maxContours, font.maxp.maxPoints+2);
  822. IF Debug THEN KernelLog.String("max CompContours: ");KernelLog.Int(font.maxp.maxCompositeContours, 0); KernelLog.String(" NewZone Comp: "); KernelLog.Int(font.maxp.maxCompositePoints+2, 0); KernelLog.Ln END;
  823. OpenTypeInt.NewZone(glyph.comp, font.maxp.maxCompositeContours, font.maxp.maxCompositePoints+2);
  824. IF Debug THEN KernelLog.String("NewStore: "); KernelLog.Int(font.maxp.maxStorage, 0); KernelLog.Ln END;
  825. OpenTypeInt.NewStore(glyph.store, font.maxp.maxStorage);
  826. IF Debug THEN KernelLog.String("NewCVT: "); KernelLog.Int(font.cvtLen, 0); KernelLog.Ln END;
  827. OpenTypeInt.NewCVT(glyph.cvt, font.cvtLen)
  828. END InitGlyph;
  829. PROCEDURE LoadSimpleOutline (VAR r: Files.Rider; glyph: Glyph; inst: Instance; num: LONGINT; contours: INTEGER; hinted, rotated, stretched: BOOLEAN);
  830. VAR
  831. font: Font; zone: OpenTypeInt.Zone; pt: OpenTypeInt.Points; points, instrLen, xmin, ymin, xmax, ymax, i, j, val: INTEGER;
  832. flag: SHORTINT; byte: CHAR; x, y, aw, lsb: FUnit; dx: F26D6; context: OpenTypeInt.Context;
  833. BEGIN
  834. font := glyph.font; zone := glyph.simple; pt := zone.pt;
  835. zone.contours := 0; points := 0; instrLen := 0;
  836. IF contours > 0 THEN
  837. ReadInt(r, xmin); ReadInt(r, ymin);
  838. ReadInt(r, xmax); ReadInt(r, ymax);
  839. (* load contour end points *)
  840. zone.contours := contours; zone.first[0] := 0;
  841. FOR i := 1 TO contours DO
  842. ReadInt(r, j); zone.first[i] := j+1
  843. END;
  844. points := zone.first[contours];
  845. (* load glyph instructions *)
  846. ReadInt(r, instrLen);
  847. IF instrLen > 0 THEN
  848. IF hinted THEN
  849. IF instrLen > LEN(font.glyphProg^) THEN
  850. IF Debug THEN KernelLog.String("Wrong Instruction Prog Size: "); KernelLog.Int(instrLen, 0); KernelLog.String(" Array size: "); KernelLog.Int(LEN(font.glyphProg^), 0); KernelLog.Ln END;
  851. hinted := FALSE;
  852. font.file.Set(r, r.file.Pos(r) + instrLen)
  853. ELSE
  854. r.file.ReadBytes(r, font.glyphProg^, 0, instrLen)
  855. END
  856. ELSE font.file.Set(r, r.file.Pos(r) + instrLen)
  857. END
  858. END;
  859. (* load flags (small hack: store flags in pt[i].cur[0]) *)
  860. i := 0;
  861. WHILE i < points DO
  862. Files.ReadSInt(r, flag); pt[i].cur[0] := flag;
  863. IF ODD(flag DIV 8) THEN (* repeat flag set *)
  864. r.file.Read(r, byte); j := ORD(byte);
  865. WHILE j > 0 DO
  866. INC(i); pt[i].cur[0] := flag; DEC(j)
  867. END
  868. END;
  869. INC(i)
  870. END;
  871. (* load x-coordinates *)
  872. x := 0;
  873. FOR i := 0 TO points-1 DO
  874. flag := SHORT(SHORT(pt[i].cur[0]));
  875. IF ODD(flag DIV 2) THEN (* x is short *)
  876. r.file.Read(r, byte);
  877. IF ODD(flag DIV 10H) THEN INC(x, ORD(byte)) (* short x-value is positive *)
  878. ELSE DEC(x, ORD(byte)) (* short x-value is negative *)
  879. END
  880. ELSIF ~ODD(flag DIV 10H) THEN (* x has previous value *)
  881. ReadInt(r, val); INC(x, val)
  882. END;
  883. pt[i].org[X] := OpenTypeInt.MulDiv(x, inst.xppm, font.head.unitsPerEm)
  884. END;
  885. (* load y-coordinates *)
  886. y := 0;
  887. FOR i := 0 TO points-1 DO
  888. flag := SHORT(SHORT(pt[i].cur[0]));
  889. IF ODD(flag DIV 4) THEN (* y is short *)
  890. r.file.Read(r, byte);
  891. IF ODD(flag DIV 20H) THEN INC(y, ORD(byte)) (* short y-value is positive *)
  892. ELSE DEC(y, ORD(byte)) (* short y-value is negative *)
  893. END
  894. ELSIF ~ODD(flag DIV 20H) THEN (* y has previous value *)
  895. ReadInt(r, val); INC(y, val)
  896. END;
  897. pt[i].org[Y] := OpenTypeInt.MulDiv(y, inst.yppm, font.head.unitsPerEm)
  898. END;
  899. FOR i := 0 TO points-1 DO
  900. pt[i].onCurve := ODD(pt[i].cur[0])
  901. END
  902. END;
  903. (* add phantom points *)
  904. aw := font.hmtx[num].aw; lsb := font.hmtx[num].lsb;
  905. IF ODD(font.head.flags DIV 2) THEN
  906. pt[points].org[X] := 0;
  907. pt[points+1].org[X] := OpenTypeInt.MulDiv(aw, inst.xppm, font.head.unitsPerEm)
  908. ELSE
  909. pt[points].org[X] := OpenTypeInt.MulDiv(xmin - lsb, inst.xppm, font.head.unitsPerEm);
  910. pt[points+1].org[X] := pt[points].org[X] + OpenTypeInt.MulDiv(aw, inst.xppm, font.head.unitsPerEm)
  911. END;
  912. pt[points].org[Y] := 0; pt[points].onCurve := FALSE;
  913. pt[points+1].org[Y] := 0; pt[points+1].onCurve := FALSE;
  914. IF hinted THEN (* round phantom points to grid and shift whole outline *)
  915. dx := 20H - (pt[points].org[X] + 20H) MOD 40H;
  916. IF dx # 0 THEN
  917. FOR i := 0 TO points+1 DO
  918. INC(pt[i].org[X], dx)
  919. END
  920. END;
  921. pt[points+1].org[X] := (pt[points+1].org[X] + 20H) DIV 40H * 40H
  922. END;
  923. FOR i := 0 TO points+1 DO
  924. pt[i].cur := pt[i].org;
  925. pt[i].touched[0] := FALSE; pt[i].touched[1] := FALSE
  926. END;
  927. IF hinted & (instrLen > 0) THEN (* execute instructions *)
  928. OpenTypeInt.RestoreState(context, inst.state);
  929. IF context.ignorePrep THEN (* use default state and cvt *)
  930. OpenTypeInt.InitState(context)
  931. END;
  932. FOR i := 0 TO font.maxp.maxStorage-1 DO glyph.store[i] := inst.store[i] END;
  933. FOR i := 0 TO SHORT(font.cvtLen-1) DO glyph.cvt[i] := inst.cvt[i] END;
  934. FOR i := 0 TO font.maxp.maxTwilightPoints-1 DO font.twilight.pt[i] := inst.twilight.pt[i] END;
  935. OpenTypeInt.SetStructures(context, inst.func, inst.instr, glyph.store, glyph.cvt);
  936. OpenTypeInt.SetResolution(context, inst.ptsize, inst.xppm, inst.yppm, font.head.unitsPerEm, rotated, stretched);
  937. OpenTypeInt.Execute(context, font.glyphProg, instrLen, font.twilight, zone);
  938. glyph.fixDropouts := context.fixDropouts;
  939. glyph.scanType := context.scanType
  940. END;
  941. glyph.lppx := pt[points].cur[X]; glyph.rppx := pt[points+1].cur[X]
  942. END LoadSimpleOutline;
  943. PROCEDURE LoadOutline (glyph: Glyph; inst: Instance; num: LONGINT; hinted, rotated, stretched: BOOLEAN);
  944. VAR
  945. font: Font; pos, len, beg, end, idx: LONGINT; r: Files.Rider;
  946. int, contours, flags, arg1, arg2, firstc, firstp, i, lastc, lastp, instrLen, points: INTEGER; comp: OpenTypeInt.Zone;
  947. aw, lsb, xmin, ymin, xmax, ymax: FUnit; lppx, rppx, dx, dy: F26D6; m00, m01, m10, m11: F2D14;
  948. scaled, rot: BOOLEAN; context: OpenTypeInt.Context;
  949. BEGIN
  950. font := glyph.font;
  951. IF FindTable(font, "loca", pos, len) THEN
  952. IF font.head.indexToLocFormat = 0 THEN (* short offsets *)
  953. font.file.Set(r, pos + 2*num);
  954. ReadInt(r, int); beg := 2*(LONG(int) MOD 10000H);
  955. ReadInt(r, int); end := 2*(LONG(int) MOD 10000H)
  956. ELSE (* long offsets *)
  957. font.file.Set(r, pos + 4*num);
  958. ReadLInt(r, beg);
  959. ReadLInt(r, end);
  960. END;
  961. glyph.lppx := 0;
  962. IF beg >= end THEN (* character without contour *)
  963. LoadSimpleOutline(r, glyph, inst, num, 0, hinted, rotated, stretched)
  964. ELSIF FindTable(font, "glyf", pos, len) THEN
  965. font.file.Set(r, pos + beg);
  966. ReadInt(r, contours);
  967. IF Debug THEN KernelLog.String(" Contours read: "); KernelLog.Int(contours, 0); KernelLog.Ln END;
  968. IF contours > 0 THEN (* simple glyph *)
  969. LoadSimpleOutline(r, glyph, inst, num, contours, hinted, rotated, stretched)
  970. ELSE (* composite glyph *)
  971. IF Debug THEN KernelLog.String("--------------- Composite Glyph ----------------"); KernelLog.Ln END;
  972. comp := glyph.comp; glyph.outline := comp;
  973. aw := font.hmtx[num].aw; lsb := font.hmtx[num].lsb;
  974. ReadInt(r, xmin); ReadInt(r, ymin);
  975. ReadInt(r, xmax); ReadInt(r, ymax);
  976. lppx := OpenTypeInt.MulDiv(xmin - lsb, inst.xppm, font.head.unitsPerEm);
  977. rppx := lppx + OpenTypeInt.MulDiv(aw, inst.xppm, font.head.unitsPerEm);
  978. REPEAT
  979. ReadInt(r, flags); Read16U(r, idx);
  980. IF ODD(flags) THEN (* args are words *)
  981. ReadInt(r, arg1); ReadInt(r, arg2)
  982. ELSE
  983. ReadInt(r, arg1); arg2 := arg1 MOD 100H; arg1 := arg1 DIV 100H MOD 100H
  984. END;
  985. (* load transformation (if any) *)
  986. IF ODD(flags DIV 8) THEN (* we_have_a_scale *)
  987. ReadInt(r, m00); m01 := 0;
  988. m10 := 0; m11 := m00;
  989. scaled := TRUE; rot := FALSE
  990. ELSIF ODD(flags DIV 40H) THEN (* we_have_an_x_and_y_scale *)
  991. ReadInt(r, m00); m01 := 0;
  992. m10 := 0; ReadInt(r, m11);
  993. scaled := TRUE; rot := FALSE
  994. ELSIF ODD(flags DIV 80H) THEN (* we_have_a_two_by_two *)
  995. ReadInt(r, m00); ReadInt(r, m01);
  996. ReadInt(r, m10); ReadInt(r, m11);
  997. scaled := TRUE; rot := TRUE
  998. ELSE
  999. m00 := 4000H; m01 := 0; m10 := 0; m11 := 4000H;
  1000. scaled := FALSE; rot := FALSE
  1001. END;
  1002. (* recursively load component *)
  1003. firstc := comp.contours; firstp := comp.first[firstc];
  1004. LoadOutline(glyph, inst, idx, hinted, rotated OR rot, stretched OR scaled);
  1005. IF comp.contours = firstc THEN (* loaded simple outline => copy to composite zone *)
  1006. FOR i := 0 TO glyph.simple.first[glyph.simple.contours] DO
  1007. comp.pt[firstp + i] := glyph.simple.pt[i]
  1008. END;
  1009. FOR i := 1 TO glyph.simple.contours DO
  1010. comp.first[firstc + i] := firstp + glyph.simple.first[i]
  1011. END;
  1012. INC(comp.contours, glyph.simple.contours)
  1013. END;
  1014. lastc := comp.contours-1; lastp := comp.first[comp.contours]-1;
  1015. IF scaled THEN (* apply transformation *)
  1016. FOR i := firstp TO lastp DO
  1017. dx := comp.pt[i].cur[X]; dy := comp.pt[i].cur[Y];
  1018. comp.pt[i].cur[X] := OpenTypeInt.MulShift(dx, m00, -14) + OpenTypeInt.MulShift(dy, m10, -14);
  1019. comp.pt[i].cur[Y] := OpenTypeInt.MulShift(dx, m01, -14) + OpenTypeInt.MulShift(dy, m11, -14)
  1020. END;
  1021. glyph.lppx := OpenTypeInt.MulShift(glyph.lppx, m00, -14);
  1022. glyph.rppx := OpenTypeInt.MulShift(glyph.rppx, m00, -14)
  1023. END;
  1024. IF ODD(flags DIV 200H) THEN (* use_my_metrics *)
  1025. lppx := glyph.lppx; rppx := glyph.rppx (* won't work very well with rotated subglyphs *)
  1026. END;
  1027. (* compute translation vector and shift new glyph *)
  1028. IF ODD(flags DIV 2) THEN (* args_arg_xy_values *)
  1029. dx := OpenTypeInt.MulDiv(arg1, inst.xppm, font.head.unitsPerEm);
  1030. dy := OpenTypeInt.MulDiv(arg2, inst.yppm, font.head.unitsPerEm);
  1031. IF ODD(flags DIV 4) THEN (* round_xy_to_grid *)
  1032. dx := (dx + 20H) DIV 40H * 40H;
  1033. dy := (dy + 20H) DIV 40H * 40H
  1034. END
  1035. ELSE
  1036. dx := comp.pt[arg2].cur[X] - comp.pt[arg1].cur[X];
  1037. dy := comp.pt[arg2].cur[Y] - comp.pt[arg2].cur[Y]
  1038. END;
  1039. IF (dx # 0) OR (dy # 0) THEN
  1040. FOR i := firstp TO lastp DO
  1041. INC(comp.pt[i].cur[X], dx);
  1042. INC(comp.pt[i].cur[Y], dy)
  1043. END
  1044. END
  1045. UNTIL ~ODD(flags DIV 20H);
  1046. (* load instructions *)
  1047. IF ODD(flags DIV 100H) THEN (* we_have_instr *)
  1048. ReadInt(r, instrLen);
  1049. IF hinted THEN r.file.ReadBytes(r, font.glyphProg^, 0, instrLen)
  1050. ELSE font.file.Set(r, r.file.Pos(r) + instrLen)
  1051. END
  1052. ELSE
  1053. instrLen := 0
  1054. END;
  1055. (* add phantom points *)
  1056. points := comp.first[comp.contours];
  1057. IF hinted THEN comp.pt[points].cur[X] := (lppx + 20H) DIV 40H * 40H
  1058. ELSE comp.pt[points].cur[X] := lppx
  1059. END;
  1060. comp.pt[points].cur[Y] := 0; comp.pt[points].onCurve := FALSE;
  1061. INC(points);
  1062. IF hinted THEN comp.pt[points].cur[X] := (rppx + 20H) DIV 40H * 40H
  1063. ELSE comp.pt[points].cur[X] := rppx
  1064. END;
  1065. comp.pt[points].cur[Y] := 0; comp.pt[points].onCurve := FALSE;
  1066. INC(points);
  1067. FOR i := 0 TO points-1 DO
  1068. comp.pt[i].org := comp.pt[i].cur; comp.pt[i].touched[X] := FALSE; comp.pt[i].touched[Y] := FALSE
  1069. END;
  1070. IF hinted & (instrLen > 0) THEN (* execute instructions *)
  1071. OpenTypeInt.RestoreState(context, inst.state);
  1072. IF context.ignorePrep THEN (* use default state and cvt *)
  1073. OpenTypeInt.InitState(context)
  1074. END;
  1075. FOR i := 0 TO font.maxp.maxStorage-1 DO glyph.store[i] := inst.store[i] END;
  1076. FOR i := 0 TO SHORT(font.cvtLen-1) DO glyph.cvt[i] := inst.cvt[i] END;
  1077. FOR i := 0 TO font.maxp.maxTwilightPoints-1 DO font.twilight.pt[i] := inst.twilight.pt[i] END;
  1078. OpenTypeInt.SetStructures(context, inst.func, inst.instr, glyph.store, glyph.cvt);
  1079. OpenTypeInt.SetResolution(context, inst.ptsize, inst.xppm, inst.yppm, font.head.unitsPerEm, rotated, stretched);
  1080. OpenTypeInt.Execute(context, font.glyphProg, instrLen, font.twilight, comp);
  1081. glyph.fixDropouts := TRUE OR context.fixDropouts;
  1082. glyph.scanType := context.scanType
  1083. END;
  1084. glyph.lppx := comp.pt[points-2].cur[X];
  1085. glyph.rppx := comp.pt[points-1].cur[X]
  1086. END
  1087. END;
  1088. (* translate glyph so that left phantom point is at origin *)
  1089. IF glyph.lppx # 0 THEN
  1090. FOR i := 0 TO glyph.outline.first[glyph.outline.contours]+1 DO
  1091. DEC(glyph.outline.pt[i].cur[X], glyph.lppx)
  1092. END;
  1093. DEC(glyph.rppx, glyph.lppx); glyph.lppx := 0
  1094. END
  1095. END
  1096. END LoadOutline;
  1097. (** load glyph structure with appropriately scaled outline **)
  1098. PROCEDURE LoadGlyph* (inst: Instance; glyph: Glyph; VAR ras: OpenTypeScan.Rasterizer; num: LONGINT; mode: SET);
  1099. VAR
  1100. font: Font; aw, xmin, ymin, xmax, ymax: F26D6; n: INTEGER;
  1101. cur: OpenTypeInt.Coord; rules: SET;
  1102. BEGIN
  1103. ASSERT(inst.font = glyph.font, 100);
  1104. ASSERT((0 <= num) & (num < glyph.font.maxp.numGlyphs), 101);
  1105. font := glyph.font;
  1106. (* try to get metrics if neither outline nor raster is requested *)
  1107. IF mode * {Hinted, Width} = mode THEN
  1108. IF (Hinted IN mode) & (inst.aw # NIL) THEN
  1109. aw := 40H*ORD(inst.aw[num])
  1110. ELSE
  1111. aw := OpenTypeInt.MulDiv(font.hmtx[num].aw, inst.xppm, LONG(font.head.unitsPerEm))
  1112. END;
  1113. IF inst.rotated OR inst.stretched THEN
  1114. glyph.awx := SHORT(OpenTypeInt.MulShift(aw, inst.mat[0], -22));
  1115. glyph.awy := SHORT(OpenTypeInt.MulShift(aw, inst.mat[1], -22))
  1116. ELSE
  1117. glyph.awx := SHORT((aw + 20H) DIV 40H); glyph.awy := 0
  1118. END;
  1119. IF (mode = {Width}) OR (* unhinted width requested *)
  1120. ~ODD(font.head.flags DIV 10H) OR (* width scales linearly *)
  1121. (font.LTSH # NIL) & (40H*ORD(font.LTSH[num]) <= inst.yppm) OR (* in linear range *)
  1122. (inst.aw # NIL) (* hinted width available *)
  1123. THEN
  1124. RETURN
  1125. END
  1126. END;
  1127. (* load glyph outline *)
  1128. glyph.comp.contours := 0; glyph.comp.first[0] := 0; glyph.outline := glyph.simple;
  1129. LoadOutline(glyph, inst, num, Hinted IN mode, inst.rotated, inst.stretched);
  1130. (* transform outline if necessary *)
  1131. IF (mode * {Outline, Raster} # {}) & (inst.rotated OR inst.stretched) THEN
  1132. FOR n := 0 TO glyph.outline.first[glyph.outline.contours]-1 DO
  1133. cur := glyph.outline.pt[n].cur;
  1134. glyph.outline.pt[n].cur[X] := OpenTypeInt.MulShift(cur[X], inst.mat[0], -16) + OpenTypeInt.MulShift(cur[Y], inst.mat[2], -16);
  1135. glyph.outline.pt[n].cur[Y] := OpenTypeInt.MulShift(cur[X], inst.mat[1], -16) + OpenTypeInt.MulShift(cur[Y], inst.mat[3], -16)
  1136. END
  1137. END;
  1138. (* compute bounding box *)
  1139. IF mode * {Width, Raster} # {} THEN
  1140. xmin := MAX(F26D6); ymin := MAX(F26D6); xmax := MIN(F26D6); ymax := MIN(F26D6);
  1141. FOR n := 0 TO glyph.outline.first[glyph.outline.contours]-1 DO
  1142. cur := glyph.outline.pt[n].cur;
  1143. IF cur[X] < xmin THEN xmin := cur[X] END;
  1144. IF cur[X] > xmax THEN xmax := cur[X] END;
  1145. IF cur[Y] < ymin THEN ymin := cur[Y] END;
  1146. IF cur[Y] > ymax THEN ymax := cur[Y] END
  1147. END;
  1148. IF Hinted IN mode THEN (* round to grid *)
  1149. DEC(xmin, xmin MOD 40H); DEC(ymin, ymin MOD 40H);
  1150. INC(xmax, (-xmax) MOD 40H); INC(ymax, (-ymax) MOD 40H)
  1151. END;
  1152. glyph.xmin := xmin; glyph.ymin := ymin;
  1153. glyph.xmax := xmax; glyph.ymax := ymax
  1154. END;
  1155. IF Width IN mode THEN
  1156. IF (Hinted IN mode) & (inst.aw # NIL) THEN
  1157. aw := 40H*ORD(inst.aw[num])
  1158. ELSE
  1159. aw := glyph.rppx (* glyph.lppx = 0 *)
  1160. END;
  1161. IF inst.rotated OR inst.stretched THEN
  1162. glyph.awx := SHORT(OpenTypeInt.MulShift(aw, inst.mat[0], -22));
  1163. glyph.awy := SHORT(OpenTypeInt.MulShift(aw, inst.mat[1], -22))
  1164. ELSE
  1165. glyph.awx := SHORT((aw + 20H) DIV 40H); glyph.awy := 0
  1166. END
  1167. END;
  1168. IF Raster IN mode THEN
  1169. rules := {};
  1170. IF ~(Grey IN mode) THEN
  1171. INCL(rules, OpenTypeScan.Round)
  1172. END;
  1173. IF glyph.fixDropouts THEN
  1174. IF glyph.scanType IN {0, 1, 4, 5} THEN INCL(rules, OpenTypeScan.Dropouts) END;
  1175. IF glyph.scanType IN {1, 5} THEN INCL(rules, OpenTypeScan.Stubs) END;
  1176. IF glyph.scanType IN {4, 5} THEN INCL(rules, OpenTypeScan.Smart) END
  1177. END;
  1178. INCL(rules, OpenTypeScan.Dropouts);
  1179. OpenTypeScan.Convert(glyph.outline, rules, ras);
  1180. glyph.hbx := SHORT(ras.xmin DIV 40H);
  1181. glyph.hby := SHORT(ras.ymin DIV 40H);
  1182. glyph.rw := ras.width; glyph.rh := ras.height
  1183. END
  1184. END LoadGlyph;
  1185. (** enumerate glyph outline **)
  1186. PROCEDURE EnumOutline* (glyph: Glyph; VAR data: OutlineData);
  1187. VAR pt: OpenTypeInt.Points; cont, beg, points, i, j, k, l: INTEGER; x, y: F26D6; xx, yy: ARRAY 2 OF F26D6;
  1188. BEGIN
  1189. pt := glyph.outline.pt;
  1190. cont := 0;
  1191. WHILE cont < glyph.outline.contours DO
  1192. beg := glyph.outline.first[cont]; points := glyph.outline.first[cont+1] - beg;
  1193. i := 0; WHILE (i < points) & ~pt[beg + i].onCurve DO INC(i) END;
  1194. IF i < points THEN
  1195. j := i; k := beg + j;
  1196. x := pt[k].cur[X]; y := pt[k].cur[Y];
  1197. data.moveto(x, y, data);
  1198. REPEAT
  1199. j := (j+1) MOD points; k := beg + j;
  1200. IF pt[k].onCurve THEN
  1201. x := pt[k].cur[X]; y := pt[k].cur[Y];
  1202. data.lineto(x, y, data)
  1203. ELSE
  1204. xx[0] := pt[k].cur[X]; yy[0] := pt[k].cur[Y];
  1205. l := beg + (j+1) MOD points;
  1206. IF pt[l].onCurve THEN
  1207. k := l; j := k - beg;
  1208. xx[1] := pt[k].cur[X]; yy[1] := pt[k].cur[Y]
  1209. ELSE
  1210. xx[1] := (xx[0] + pt[l].cur[X]) DIV 2; yy[1] := (yy[0] + pt[l].cur[Y]) DIV 2
  1211. END;
  1212. data.bezierto(xx, yy, 2, data);
  1213. x := xx[1]; y := yy[1]
  1214. END
  1215. UNTIL j = i
  1216. END;
  1217. INC(cont)
  1218. END
  1219. END EnumOutline;
  1220. PROCEDURE SharpenC(VAR x0,x1,a0,a1: INTEGER);
  1221. BEGIN
  1222. IF x0=x1 THEN
  1223. a0 := 0; a1 := 0; INC(x1)
  1224. ELSIF ((x1-x0) = 1) & (a0 # 0) THEN
  1225. IF 40H-a0 > a1 THEN
  1226. a0 := 0;
  1227. (*a1 := 0;*)
  1228. (*DEC(a0,a1); a1 := 0;*)
  1229. ELSE
  1230. (*a0 := 0; *) a1 := 0; (* INC(x0); *) INC(x1);
  1231. (*INC(a1, 40H-a0); a0 := 3FH;*)
  1232. END;
  1233. END;
  1234. END SharpenC;
  1235. PROCEDURE EnumRow (row: INTEGER; beg, end: F26D6; VAR data: OpenTypeScan.EnumData);
  1236. VAR x0, a0, x1, a1: INTEGER;
  1237. BEGIN
  1238. WITH data: RasterData DO
  1239. x0 := SHORT(beg DIV 40H); a0 := SHORT(beg MOD 40H);
  1240. x1 := SHORT(end DIV 40H); a1 := SHORT(end MOD 40H);
  1241. IF SharpenContours THEN SharpenC(x0,x1,a0,a1) END;
  1242. IF x0 < x1 THEN
  1243. IF a0 # 0 THEN
  1244. data.rect(x0, row, x0+1, row+1, 4*(40H-a0), data);
  1245. INC(x0)
  1246. END;
  1247. IF x0 < x1 THEN
  1248. data.rect(x0, row, x1, row+1, 255, data)
  1249. END;
  1250. IF a1 # 0 THEN
  1251. data.rect(x1, row, x1+1, row+1, 4*a1, data)
  1252. END
  1253. ELSIF a0 < a1 THEN
  1254. data.rect(x0, row, x0+1, row+1, 4*(a1 - a0), data)
  1255. END
  1256. END
  1257. END EnumRow;
  1258. PROCEDURE EnumCol (col: INTEGER; beg, end: F26D6; VAR data: OpenTypeScan.EnumData);
  1259. VAR y0, a0, y1, a1: INTEGER;
  1260. BEGIN
  1261. WITH data: RasterData DO
  1262. y0 := SHORT(beg DIV 40H); a0 := SHORT(beg MOD 40H);
  1263. y1 := SHORT(end DIV 40H); a1 := SHORT(end MOD 40H);
  1264. IF SharpenContours THEN SharpenC(y0,y1,a0,a1) END;
  1265. IF y0 < y1 THEN
  1266. IF a0 # 0 THEN
  1267. data.rect(col, y0, col+1, y0+1, 4*(40H-a0), data);
  1268. INC(y0)
  1269. END;
  1270. IF y0 < y1 THEN
  1271. data.rect(col, y0, col+1, y1, 255, data)
  1272. END;
  1273. IF a1 # 0 THEN
  1274. data.rect(col, y1, col+1, y1+1, 4*a1, data)
  1275. END
  1276. ELSIF a0 < a1 THEN
  1277. data.rect(col, y0, col+1, y0+1, 4*(a1 - a0) , data)
  1278. END
  1279. END
  1280. END EnumCol;
  1281. (** enumerate non-transparent pixels of glyph raster image **)
  1282. PROCEDURE EnumRaster* (VAR ras: OpenTypeScan.Rasterizer; VAR data: RasterData);
  1283. BEGIN
  1284. OpenTypeScan.EnumerateRows(ras, EnumRow, data);
  1285. OpenTypeScan.EnumerateColumns(ras, EnumCol, data)
  1286. END EnumRaster;
  1287. (*--- Initialization ---*)
  1288. PROCEDURE InitCharMaps;
  1289. VAR i: INTEGER; l: LONGINT;
  1290. BEGIN
  1291. FOR i := 0 TO 126 DO
  1292. UniChar[i] := i; MacChar[i] := i
  1293. END;
  1294. UniChar[127] := 0A0H; MacChar[127] := 0CAH;
  1295. UniChar[128] := 0A1H; MacChar[128] := 0C1H;
  1296. UniChar[129] := 0A2H; MacChar[129] := 0A2H;
  1297. UniChar[130] := 0A3H; MacChar[130] := 0A3H;
  1298. UniChar[131] := 0A4H; MacChar[131] := 0DBH;
  1299. UniChar[132] := 0A5H; MacChar[132] := 0B4H;
  1300. UniChar[133] := 0A7H; MacChar[133] := 0A4H;
  1301. UniChar[134] := 0A8H; MacChar[134] := 0ACH;
  1302. UniChar[135] := 0A9H; MacChar[135] := 0A9H;
  1303. UniChar[136] := 0AAH; MacChar[136] := 0BBH;
  1304. UniChar[137] := 0ABH; MacChar[137] := 0C7H;
  1305. UniChar[138] := 0ACH; MacChar[138] := 0C2H;
  1306. UniChar[139] := 0AEH; MacChar[139] := 0A8H;
  1307. UniChar[140] := 0AFH; MacChar[140] := 0F8H;
  1308. UniChar[141] := 0B0H; MacChar[141] := 0A1H;
  1309. UniChar[142] := 0B1H; MacChar[142] := 0B1H;
  1310. UniChar[143] := 0B4H; MacChar[143] := 0ABH;
  1311. UniChar[144] := 0B5H; MacChar[144] := 0B5H;
  1312. UniChar[145] := 0B6H; MacChar[145] := 0A6H;
  1313. UniChar[146] := 0B8H; MacChar[146] := 0FCH;
  1314. UniChar[147] := 0BAH; MacChar[147] := 0BCH;
  1315. UniChar[148] := 0BBH; MacChar[148] := 0C8H;
  1316. UniChar[149] := 0BFH; MacChar[149] := 0C0H;
  1317. UniChar[150] := 0C0H; MacChar[150] := 0CBH;
  1318. UniChar[151] := 0C1H; MacChar[151] := 0E7H;
  1319. UniChar[152] := 0C2H; MacChar[152] := 0E5H;
  1320. UniChar[153] := 0C3H; MacChar[153] := 0CCH;
  1321. UniChar[154] := 0C4H; MacChar[154] := 80H;
  1322. UniChar[155] := 0C5H; MacChar[155] := 81H;
  1323. UniChar[156] := 0C6H; MacChar[156] := 0AEH;
  1324. UniChar[157] := 0C7H; MacChar[157] := 82H;
  1325. UniChar[158] := 0C8H; MacChar[158] := 0E9H;
  1326. UniChar[159] := 0C9H; MacChar[159] := 83H;
  1327. UniChar[160] := 0CAH; MacChar[160] := 0E6H;
  1328. UniChar[161] := 0CBH; MacChar[161] := 0E8H;
  1329. UniChar[162] := 0CCH; MacChar[162] := 0EDH;
  1330. UniChar[163] := 0CDH; MacChar[163] := 0EAH;
  1331. UniChar[164] := 0CEH; MacChar[164] := 0EBH;
  1332. UniChar[165] := 0CFH; MacChar[165] := 0ECH;
  1333. UniChar[166] := 0D1H; MacChar[166] := 84H;
  1334. UniChar[167] := 0D2H; MacChar[167] := 0F1H;
  1335. UniChar[168] := 0D3H; MacChar[168] := 0EEH;
  1336. UniChar[169] := 0D4H; MacChar[169] := 0EFH;
  1337. UniChar[170] := 0D5H; MacChar[170] := 0CDH;
  1338. UniChar[171] := 0D6H; MacChar[171] := 85H;
  1339. UniChar[172] := 0D8H; MacChar[172] := 0AFH;
  1340. UniChar[173] := 0D9H; MacChar[173] := 0F4H;
  1341. UniChar[174] := 0DAH; MacChar[174] := 0F2H;
  1342. UniChar[175] := 0DBH; MacChar[175] := 0F3H;
  1343. UniChar[176] := 0DCH; MacChar[176] := 86H;
  1344. UniChar[177] := 0DFH; MacChar[177] := 0A7H;
  1345. UniChar[178] := 0E0H; MacChar[178] := 88H;
  1346. UniChar[179] := 0E1H; MacChar[179] := 87H;
  1347. UniChar[180] := 0E2H; MacChar[180] := 89H;
  1348. UniChar[181] := 0E3H; MacChar[181] := 8BH;
  1349. UniChar[182] := 0E4H; MacChar[182] := 8AH;
  1350. UniChar[183] := 0E5H; MacChar[183] := 8CH;
  1351. UniChar[184] := 0E6H; MacChar[184] := 0BEH;
  1352. UniChar[185] := 0E7H; MacChar[185] := 8DH;
  1353. UniChar[186] := 0E8H; MacChar[186] := 8FH;
  1354. UniChar[187] := 0E9H; MacChar[187] := 8EH;
  1355. UniChar[188] := 0EAH; MacChar[188] := 90H;
  1356. UniChar[189] := 0EBH; MacChar[189] := 91H;
  1357. UniChar[190] := 0ECH; MacChar[190] := 93H;
  1358. UniChar[191] := 0EDH; MacChar[191] := 92H;
  1359. UniChar[192] := 0EEH; MacChar[192] := 94H;
  1360. UniChar[193] := 0EFH; MacChar[193] := 95H;
  1361. UniChar[194] := 0F1H; MacChar[194] := 96H;
  1362. UniChar[195] := 0F2H; MacChar[195] := 98H;
  1363. UniChar[196] := 0F3H; MacChar[196] := 97H;
  1364. UniChar[197] := 0F4H; MacChar[197] := 99H;
  1365. UniChar[198] := 0F5H; MacChar[198] := 9BH;
  1366. UniChar[199] := 0F6H; MacChar[199] := 9AH;
  1367. UniChar[200] := 0F7H; MacChar[200] := 0D6H;
  1368. UniChar[201] := 0F8H; MacChar[201] := 0BFH;
  1369. UniChar[202] := 0F9H; MacChar[202] := 9DH;
  1370. UniChar[203] := 0FAH; MacChar[203] := 9CH;
  1371. UniChar[204] := 0FBH; MacChar[204] := 9EH;
  1372. UniChar[205] := 0FCH; MacChar[205] := 9FH;
  1373. UniChar[206] := 0FFH; MacChar[206] := 0D8H;
  1374. UniChar[207] := 131H; MacChar[207] := 0F5H;
  1375. UniChar[208] := 152H; MacChar[208] := 0CEH;
  1376. UniChar[209] := 153H; MacChar[209] := 0CFH;
  1377. UniChar[210] := 178H; MacChar[210] := 0D9H;
  1378. UniChar[211] := 192H; MacChar[211] := 0C4H;
  1379. UniChar[212] := 2C6H; MacChar[212] := 0F6H;
  1380. UniChar[213] := 2C7H; MacChar[213] := 0FFH;
  1381. UniChar[214] := 2D6H; MacChar[214] := 0F7H;
  1382. UniChar[215] := 2D8H; MacChar[215] := 0F9H;
  1383. UniChar[216] := 2D9H; MacChar[216] := 0FAH;
  1384. UniChar[217] := 2DAH; MacChar[217] := 0FBH;
  1385. UniChar[218] := 2DBH; MacChar[218] := 0FEH;
  1386. UniChar[219] := 2DDH; MacChar[219] := 0FDH;
  1387. UniChar[220] := 3C0H; MacChar[220] := 0B9H;
  1388. UniChar[221] := 2013H; MacChar[221] := 0D0H;
  1389. UniChar[222] := 2014H; MacChar[222] := 0D1H;
  1390. UniChar[223] := 2018H; MacChar[223] := 0D4H;
  1391. UniChar[224] := 2019H; MacChar[224] := 0D5H;
  1392. UniChar[225] := 201AH; MacChar[225] := 0E2H;
  1393. UniChar[226] := 201CH; MacChar[226] := 0D2H;
  1394. UniChar[227] := 201DH; MacChar[227] := 0D3H;
  1395. UniChar[228] := 201EH; MacChar[228] := 0E3H;
  1396. UniChar[229] := 2020H; MacChar[229] := 0A0H;
  1397. UniChar[230] := 2021H; MacChar[230] := 0E0H;
  1398. UniChar[231] := 2022H; MacChar[231] := 0A5H;
  1399. UniChar[232] := 2026H; MacChar[232] := 0C9H;
  1400. UniChar[233] := 2030H; MacChar[233] := 0E4H;
  1401. UniChar[234] := 2039H; MacChar[234] := 0DCH;
  1402. UniChar[235] := 203AH; MacChar[235] := 0DDH;
  1403. UniChar[236] := 2122H; MacChar[236] := 0AAH;
  1404. UniChar[237] := 2126H; MacChar[237] := 0BDH;
  1405. UniChar[238] := 2202H; MacChar[238] := 0B6H;
  1406. UniChar[239] := 2206H; MacChar[239] := 0C6H;
  1407. UniChar[240] := 220FH; MacChar[240] := 0B8H;
  1408. UniChar[241] := 2211H; MacChar[241] := 0B7H;
  1409. UniChar[242] := 2215H; MacChar[242] := 0DAH;
  1410. UniChar[243] := 2219H; MacChar[243] := 0E1H;
  1411. UniChar[244] := 221AH; MacChar[244] := 0C3H;
  1412. UniChar[245] := 221EH; MacChar[245] := 0B0H;
  1413. UniChar[246] := 222BH; MacChar[246] := 0BAH;
  1414. UniChar[247] := 2248H; MacChar[247] := 0C5H;
  1415. UniChar[248] := 2260H; MacChar[248] := 0ADH;
  1416. UniChar[249] := 2264H; MacChar[249] := 0B2H;
  1417. UniChar[250] := 2265H; MacChar[250] := 0B3H;
  1418. UniChar[251] := 25CAH; MacChar[251] := 0D7H;
  1419. l := 0F001H; UniChar[252] := SHORT(l); MacChar[252] := 0DEH;
  1420. l := 0F002H; UniChar[253] := SHORT(l); MacChar[253] := 0DFH;
  1421. FOR i := 0 TO 126 DO CharToUnicode[i] := i END;
  1422. CharToUnicode[127] := 0;
  1423. CharToUnicode[128] := 0C4H;
  1424. CharToUnicode[129] := 0D6H;
  1425. CharToUnicode[130] := 0DCH;
  1426. CharToUnicode[131] := 0E4H;
  1427. CharToUnicode[132] := 0F6H;
  1428. CharToUnicode[133] := 0FCH;
  1429. CharToUnicode[134] := 0E2H;
  1430. CharToUnicode[135] := 0EAH;
  1431. CharToUnicode[136] := 0EEH;
  1432. CharToUnicode[137] := 0F4H;
  1433. CharToUnicode[138] := 0FBH;
  1434. CharToUnicode[139] := 0E0H;
  1435. CharToUnicode[140] := 0E8H;
  1436. CharToUnicode[141] := 0ECH;
  1437. CharToUnicode[142] := 0F2H;
  1438. CharToUnicode[143] := 0F9H;
  1439. CharToUnicode[144] := 0E9H;
  1440. CharToUnicode[145] := 0EBH;
  1441. CharToUnicode[146] := 0EFH;
  1442. CharToUnicode[147] := 0E7H;
  1443. CharToUnicode[148] := 0E1H;
  1444. CharToUnicode[149] := 0F1H;
  1445. CharToUnicode[150] := 0DFH;
  1446. CharToUnicode[151] := 0A3H;
  1447. CharToUnicode[152] := 0B6H;
  1448. CharToUnicode[153] := 0C7H;
  1449. CharToUnicode[154] := 2030H;
  1450. CharToUnicode[155] := 2013H;
  1451. FOR i := 156 TO 170 DO CharToUnicode[i] := 0 END;
  1452. CharToUnicode[171] := 0DFH;
  1453. FOR i := 172 TO 255 DO CharToUnicode[i] := 0 END;
  1454. END InitCharMaps;
  1455. BEGIN
  1456. KernelLog.String("OpenType 0.45 BBPort /3.12.2004 eos, pl"); KernelLog.Ln;
  1457. InitCharMaps;
  1458. InitCache(FontCache);
  1459. Identity[0] := 10000H; Identity[1] := 0;
  1460. Identity[2] := 0; Identity[3] := 10000H
  1461. END OpenType.