kfonts.ob07 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. (*
  2. Copyright 2016, 2018 Anton Krotov
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. *)
  14. MODULE kfonts;
  15. IMPORT sys := SYSTEM, File, KOSAPI;
  16. CONST
  17. MIN_FONT_SIZE = 8;
  18. MAX_FONT_SIZE = 46;
  19. bold *= 1;
  20. italic *= 2;
  21. underline *= 4;
  22. strike_through *= 8;
  23. smoothing *= 16;
  24. bpp32 *= 32;
  25. TYPE
  26. Glyph = RECORD
  27. base: INTEGER;
  28. xsize, ysize: INTEGER;
  29. width: INTEGER
  30. END;
  31. TFont_desc = RECORD
  32. data, size, font, char_size, width, height, font_size, mem, mempos: INTEGER;
  33. glyphs: ARRAY 4, 256 OF Glyph
  34. END;
  35. TFont* = POINTER TO TFont_desc;
  36. PROCEDURE [stdcall] zeromem(size, adr: INTEGER);
  37. BEGIN
  38. sys.CODE(057H, 08BH, 07DH, 00CH, 08BH, 04DH, 008H, 033H, 0C0H, 09CH, 0FCH, 0F3H, 0ABH, 09DH, 05FH)
  39. END zeromem;
  40. PROCEDURE pset(buf, x, y, color: INTEGER; bpp32: BOOLEAN);
  41. VAR xsize, ysize: INTEGER;
  42. BEGIN
  43. sys.GET(buf, xsize);
  44. sys.GET(buf + 4, ysize);
  45. INC(buf, 8);
  46. IF (0 <= x) & (x < xsize) & (0 <= y) & (y < ysize) THEN
  47. IF bpp32 THEN
  48. sys.PUT(buf + 4 * (xsize * y + x), color)
  49. ELSE
  50. sys.MOVE(sys.ADR(color), buf + 3 * (xsize * y + x), 3)
  51. END
  52. END
  53. END pset;
  54. PROCEDURE pget(buf, x, y: INTEGER; bpp32: BOOLEAN): INTEGER;
  55. VAR xsize, ysize, color: INTEGER;
  56. BEGIN
  57. sys.GET(buf, xsize);
  58. sys.GET(buf + 4, ysize);
  59. INC(buf, 8);
  60. IF (0 <= x) & (x < xsize) & (0 <= y) & (y < ysize) THEN
  61. IF bpp32 THEN
  62. sys.GET(buf + 4 * (xsize * y + x), color)
  63. ELSE
  64. sys.MOVE(buf + 3 * (xsize * y + x), sys.ADR(color), 3)
  65. END
  66. END
  67. RETURN color
  68. END pget;
  69. PROCEDURE getrgb(color: INTEGER; VAR r, g, b: INTEGER);
  70. BEGIN
  71. b := LSR(LSL(color, 24), 24);
  72. g := LSR(LSL(color, 16), 24);
  73. r := LSR(LSL(color, 8), 24);
  74. END getrgb;
  75. PROCEDURE rgb(r, g, b: INTEGER): INTEGER;
  76. RETURN b + LSL(g, 8) + LSL(r, 16)
  77. END rgb;
  78. PROCEDURE create_glyph(VAR Font: TFont_desc; VAR glyph: Glyph; xsize, ysize: INTEGER);
  79. BEGIN
  80. glyph.base := Font.mempos;
  81. glyph.xsize := xsize;
  82. glyph.ysize := ysize;
  83. Font.mempos := Font.mempos + xsize * ysize
  84. END create_glyph;
  85. PROCEDURE getpix(Font: TFont_desc; n, x, y, xsize: INTEGER): CHAR;
  86. VAR res: CHAR;
  87. BEGIN
  88. sys.GET(Font.mem + n + x + y * xsize, res)
  89. RETURN res
  90. END getpix;
  91. PROCEDURE setpix(VAR Font: TFont_desc; n, x, y, xsize: INTEGER; c: CHAR);
  92. BEGIN
  93. sys.PUT(Font.mem + n + x + y * xsize, c)
  94. END setpix;
  95. PROCEDURE smooth(VAR Font: TFont_desc; n, xsize, ysize: INTEGER);
  96. VAR x, y: INTEGER;
  97. BEGIN
  98. FOR y := 1 TO ysize - 1 DO
  99. FOR x := 1 TO xsize - 1 DO
  100. IF (getpix(Font, n, x, y, xsize) = 1X) & (getpix(Font, n, x - 1, y - 1, xsize) = 1X) &
  101. (getpix(Font, n, x - 1, y, xsize) = 0X) & (getpix(Font, n, x, y - 1, xsize) = 0X) THEN
  102. setpix(Font, n, x - 1, y, xsize, 2X);
  103. setpix(Font, n, x, y - 1, xsize, 2X)
  104. END;
  105. IF (getpix(Font, n, x, y, xsize) = 0X) & (getpix(Font, n, x - 1, y - 1, xsize) = 0X) &
  106. (getpix(Font, n, x - 1, y, xsize) = 1X) & (getpix(Font, n, x, y - 1, xsize) = 1X) THEN
  107. setpix(Font, n, x, y, xsize, 2X);
  108. setpix(Font, n, x - 1, y - 1, xsize, 2X)
  109. END
  110. END
  111. END
  112. END smooth;
  113. PROCEDURE _bold(VAR Font: TFont_desc; src, dst, src_xsize, dst_xsize, n: INTEGER);
  114. VAR i, j, k: INTEGER; pix: CHAR;
  115. BEGIN
  116. FOR i := 0 TO src_xsize - 1 DO
  117. FOR j := 0 TO Font.height - 1 DO
  118. pix := getpix(Font, src, i, j, src_xsize);
  119. IF pix = 1X THEN
  120. FOR k := 0 TO n DO
  121. setpix(Font, dst, i + k, j, dst_xsize, pix)
  122. END
  123. END
  124. END
  125. END
  126. END _bold;
  127. PROCEDURE make_glyph(VAR Font: TFont_desc; c: INTEGER);
  128. VAR ptr, i, j, max, x, y: INTEGER; s: SET; eoc: BOOLEAN;
  129. glyph: Glyph; pix: CHAR; bold_width: INTEGER;
  130. BEGIN
  131. create_glyph(Font, glyph, Font.width, Font.height);
  132. x := 0;
  133. y := 0;
  134. max := 0;
  135. ptr := Font.font + Font.char_size * c;
  136. eoc := FALSE;
  137. REPEAT
  138. sys.GET(ptr, s);
  139. INC(ptr, 4);
  140. FOR i := 0 TO 31 DO
  141. IF ~eoc THEN
  142. IF i IN s THEN
  143. setpix(Font, glyph.base, x, y, Font.width, 1X);
  144. IF x > max THEN
  145. max := x
  146. END
  147. ELSE
  148. setpix(Font, glyph.base, x, y, Font.width, 0X)
  149. END
  150. END;
  151. INC(x);
  152. IF x = Font.width THEN
  153. x := 0;
  154. INC(y);
  155. eoc := eoc OR (y = Font.height)
  156. END
  157. END
  158. UNTIL eoc;
  159. IF max = 0 THEN
  160. max := Font.width DIV 3
  161. END;
  162. glyph.width := max;
  163. smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
  164. Font.glyphs[0, c] := glyph;
  165. bold_width := 1;
  166. create_glyph(Font, glyph, Font.width + bold_width, Font.height);
  167. _bold(Font, Font.glyphs[0, c].base, glyph.base, Font.glyphs[0, c].xsize, glyph.xsize, bold_width);
  168. smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
  169. glyph.width := max + bold_width;
  170. Font.glyphs[1, c] := glyph;
  171. create_glyph(Font, glyph, Font.width + (Font.height - 1) DIV 3, Font.height);
  172. FOR i := 0 TO Font.glyphs[0, c].xsize - 1 DO
  173. FOR j := 0 TO Font.height - 1 DO
  174. pix := getpix(Font, Font.glyphs[0, c].base, i, j, Font.glyphs[0, c].xsize);
  175. IF pix = 1X THEN
  176. setpix(Font, glyph.base, i + (Font.height - 1 - j) DIV 3, j, glyph.xsize, pix)
  177. END
  178. END
  179. END;
  180. smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
  181. glyph.width := max;
  182. Font.glyphs[2, c] := glyph;
  183. create_glyph(Font, glyph, Font.width + (Font.height - 1) DIV 3 + bold_width, Font.height);
  184. _bold(Font, Font.glyphs[2, c].base, glyph.base, Font.glyphs[2, c].xsize, glyph.xsize, bold_width);
  185. smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
  186. glyph.width := max + bold_width;
  187. Font.glyphs[3, c] := glyph;
  188. END make_glyph;
  189. PROCEDURE OutChar(Font: TFont_desc; c: INTEGER; x, y: INTEGER; buf: INTEGER; bpp32, smoothing: BOOLEAN; color, style: INTEGER): INTEGER;
  190. VAR i, x0, y0, xsize, mem, xmax: INTEGER; r, g, b, r0, g0, b0: INTEGER; ch: CHAR; glyph: Glyph;
  191. BEGIN
  192. x0 := x;
  193. y0 := y;
  194. style := style MOD 4;
  195. glyph := Font.glyphs[style, c];
  196. xsize := glyph.xsize;
  197. xmax := x0 + xsize;
  198. mem := Font.mem + glyph.base;
  199. getrgb(color, r0, g0, b0);
  200. FOR i := mem TO mem + xsize * Font.height - 1 DO
  201. sys.GET(i, ch);
  202. IF ch = 1X THEN
  203. pset(buf, x, y, color, bpp32);
  204. ELSIF (ch = 2X) & smoothing THEN
  205. getrgb(pget(buf, x, y, bpp32), r, g, b);
  206. r := (r * 3 + r0) DIV 4;
  207. g := (g * 3 + g0) DIV 4;
  208. b := (b * 3 + b0) DIV 4;
  209. pset(buf, x, y, rgb(r, g, b), bpp32)
  210. END;
  211. INC(x);
  212. IF x = xmax THEN
  213. x := x0;
  214. INC(y)
  215. END
  216. END
  217. RETURN glyph.width
  218. END OutChar;
  219. PROCEDURE hline(buf, x, y, width, color: INTEGER; bpp32: BOOLEAN);
  220. VAR i: INTEGER;
  221. BEGIN
  222. FOR i := x TO x + width - 1 DO
  223. pset(buf, i, y, color, bpp32)
  224. END
  225. END hline;
  226. PROCEDURE TextWidth*(Font: TFont; str, length, params: INTEGER): INTEGER;
  227. VAR res: INTEGER; c: CHAR;
  228. BEGIN
  229. res := 0;
  230. params := params MOD 4;
  231. IF Font # NIL THEN
  232. sys.GET(str, c);
  233. WHILE (length > 0) OR (length = -1) & (c # 0X) DO
  234. INC(str);
  235. res := res + Font.glyphs[params, ORD(c)].width;
  236. IF length > 0 THEN
  237. DEC(length)
  238. END;
  239. IF length # 0 THEN
  240. sys.GET(str, c)
  241. END
  242. END
  243. END
  244. RETURN res
  245. END TextWidth;
  246. PROCEDURE TextHeight*(Font: TFont): INTEGER;
  247. VAR res: INTEGER;
  248. BEGIN
  249. IF Font # NIL THEN
  250. res := Font.height
  251. ELSE
  252. res := 0
  253. END
  254. RETURN res
  255. END TextHeight;
  256. PROCEDURE TextClipLeft(Font: TFont; str, length, params: INTEGER; VAR x: INTEGER): INTEGER;
  257. VAR x1: INTEGER; c: CHAR;
  258. BEGIN
  259. params := params MOD 4;
  260. sys.GET(str, c);
  261. WHILE (length > 0) OR (length = -1) & (c # 0X) DO
  262. INC(str);
  263. x1 := x;
  264. x := x + Font.glyphs[params, ORD(c)].width;
  265. IF x > 0 THEN
  266. length := 0;
  267. END;
  268. IF length > 0 THEN
  269. DEC(length)
  270. END;
  271. IF length # 0 THEN
  272. sys.GET(str, c)
  273. END
  274. END;
  275. x := x1
  276. RETURN str - 1
  277. END TextClipLeft;
  278. PROCEDURE TextOut*(Font: TFont; canvas, x, y, str, length, color, params: INTEGER);
  279. VAR width, xsize, ysize, str1, n: INTEGER; c: CHAR; bpp32, smoothing, underline, strike: BOOLEAN;
  280. BEGIN
  281. IF Font # NIL THEN
  282. sys.GET(canvas, xsize);
  283. sys.GET(canvas + 4, ysize);
  284. IF (y <= -TextHeight(Font)) OR (y >= ysize) THEN
  285. length := 0
  286. END;
  287. IF length # 0 THEN
  288. smoothing := 4 IN BITS(params);
  289. bpp32 := 5 IN BITS(params);
  290. underline := 2 IN BITS(params);
  291. strike := 3 IN BITS(params);
  292. str1 := TextClipLeft(Font, str, length, params, x);
  293. n := str1 - str;
  294. str := str1;
  295. IF length >= n THEN
  296. length := length - n
  297. END;
  298. sys.GET(str, c)
  299. END;
  300. WHILE (length > 0) OR (length = -1) & (c # 0X) DO
  301. INC(str);
  302. width := OutChar(Font^, ORD(c), x, y, canvas, bpp32, smoothing, color, params);
  303. IF strike THEN
  304. hline(canvas, x + ORD(1 IN BITS(params)) * ((Font.height DIV 2) DIV 3), y + Font.height DIV 2, width + 2, color, bpp32)
  305. END;
  306. IF underline THEN
  307. hline(canvas, x, y + Font.height - 1, width + 2, color, bpp32)
  308. END;
  309. x := x + width;
  310. IF x > xsize THEN
  311. length := 0
  312. END;
  313. IF length > 0 THEN
  314. DEC(length)
  315. END;
  316. IF length # 0 THEN
  317. sys.GET(str, c)
  318. END
  319. END
  320. END
  321. END TextOut;
  322. PROCEDURE SetSize*(_Font: TFont; font_size: INTEGER): BOOLEAN;
  323. VAR temp, offset, fsize, i, memsize, mem: INTEGER;
  324. c: CHAR; Font, Font2: TFont_desc;
  325. BEGIN
  326. offset := -1;
  327. IF (MIN_FONT_SIZE <= font_size) & (font_size <= MAX_FONT_SIZE) & (_Font # NIL) THEN
  328. Font := _Font^;
  329. Font2 := Font;
  330. temp := Font.data + (font_size - 8) * 4;
  331. IF (Font.data <= temp) & (temp <= Font.size + Font.data - 4) THEN
  332. sys.GET(temp, offset);
  333. IF offset # -1 THEN
  334. Font.font_size := font_size;
  335. INC(offset, 156);
  336. offset := offset + Font.data;
  337. IF (Font.data <= offset) & (offset <= Font.size + Font.data - 4) THEN
  338. sys.GET(offset, fsize);
  339. IF fsize > 256 + 6 THEN
  340. temp := offset + fsize - 1;
  341. IF (Font.data <= temp) & (temp <= Font.size + Font.data - 1) THEN
  342. sys.GET(temp, c);
  343. IF c # 0X THEN
  344. Font.height := ORD(c);
  345. DEC(temp);
  346. sys.GET(temp, c);
  347. IF c # 0X THEN
  348. Font.width := ORD(c);
  349. DEC(fsize, 6);
  350. Font.char_size := fsize DIV 256;
  351. IF fsize MOD 256 # 0 THEN
  352. INC(Font.char_size)
  353. END;
  354. IF Font.char_size > 0 THEN
  355. Font.font := offset + 4;
  356. Font.mempos := 0;
  357. memsize := (Font.width + 10) * Font.height * 1024;
  358. mem := Font.mem;
  359. Font.mem := KOSAPI.sysfunc3(68, 12, memsize);
  360. IF Font.mem # 0 THEN
  361. IF mem # 0 THEN
  362. mem := KOSAPI.sysfunc3(68, 13, mem)
  363. END;
  364. zeromem(memsize DIV 4, Font.mem);
  365. FOR i := 0 TO 255 DO
  366. make_glyph(Font, i)
  367. END
  368. ELSE
  369. offset := -1
  370. END
  371. ELSE
  372. offset := -1
  373. END
  374. ELSE
  375. offset := -1
  376. END
  377. ELSE
  378. offset := -1
  379. END
  380. ELSE
  381. offset := -1
  382. END
  383. ELSE
  384. offset := -1
  385. END
  386. ELSE
  387. offset := -1
  388. END
  389. END;
  390. ELSE
  391. offset := -1
  392. END;
  393. IF offset # -1 THEN
  394. _Font^ := Font
  395. ELSE
  396. _Font^ := Font2
  397. END
  398. END
  399. RETURN offset # -1
  400. END SetSize;
  401. PROCEDURE Enabled*(Font: TFont; font_size: INTEGER): BOOLEAN;
  402. VAR offset, temp: INTEGER;
  403. BEGIN
  404. offset := -1;
  405. IF (MIN_FONT_SIZE <= font_size) & (font_size <= MAX_FONT_SIZE) & (Font # NIL) THEN
  406. temp := Font.data + (font_size - 8) * 4;
  407. IF (Font.data <= temp) & (temp <= Font.size + Font.data - 4) THEN
  408. sys.GET(temp, offset)
  409. END
  410. END
  411. RETURN offset # -1
  412. END Enabled;
  413. PROCEDURE Destroy*(VAR Font: TFont);
  414. BEGIN
  415. IF Font # NIL THEN
  416. IF Font.mem # 0 THEN
  417. Font.mem := KOSAPI.sysfunc3(68, 13, Font.mem)
  418. END;
  419. IF Font.data # 0 THEN
  420. Font.data := KOSAPI.sysfunc3(68, 13, Font.data)
  421. END;
  422. DISPOSE(Font)
  423. END
  424. END Destroy;
  425. PROCEDURE LoadFont*(file_name: ARRAY OF CHAR): TFont;
  426. VAR Font: TFont; data, size, n: INTEGER;
  427. BEGIN
  428. data := File.Load(file_name, size);
  429. IF (data # 0) & (size > 156) THEN
  430. NEW(Font);
  431. Font.data := data;
  432. Font.size := size;
  433. Font.font_size := 0;
  434. n := MIN_FONT_SIZE;
  435. WHILE ~SetSize(Font, n) & (n <= MAX_FONT_SIZE) DO
  436. INC(n)
  437. END;
  438. IF Font.font_size = 0 THEN
  439. Destroy(Font)
  440. END
  441. ELSE
  442. IF data # 0 THEN
  443. data := KOSAPI.sysfunc3(68, 13, data)
  444. END;
  445. Font := NIL
  446. END
  447. RETURN Font
  448. END LoadFont;
  449. END kfonts.