OpenType.Mod 59 KB

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