| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- (*
- Copyright 2016, 2018 Anton Krotov
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- *)
- MODULE kfonts;
- IMPORT sys := SYSTEM, File, KOSAPI;
- CONST
- MIN_FONT_SIZE = 8;
- MAX_FONT_SIZE = 46;
- bold *= 1;
- italic *= 2;
- underline *= 4;
- strike_through *= 8;
- smoothing *= 16;
- bpp32 *= 32;
- TYPE
- Glyph = RECORD
- base: INTEGER;
- xsize, ysize: INTEGER;
- width: INTEGER
- END;
- TFont_desc = RECORD
- data, size, font, char_size, width, height, font_size, mem, mempos: INTEGER;
- glyphs: ARRAY 4, 256 OF Glyph
- END;
- TFont* = POINTER TO TFont_desc;
- PROCEDURE [stdcall] zeromem(size, adr: INTEGER);
- BEGIN
- sys.CODE(057H, 08BH, 07DH, 00CH, 08BH, 04DH, 008H, 033H, 0C0H, 09CH, 0FCH, 0F3H, 0ABH, 09DH, 05FH)
- END zeromem;
- PROCEDURE pset(buf, x, y, color: INTEGER; bpp32: BOOLEAN);
- VAR xsize, ysize: INTEGER;
- BEGIN
- sys.GET(buf, xsize);
- sys.GET(buf + 4, ysize);
- INC(buf, 8);
- IF (0 <= x) & (x < xsize) & (0 <= y) & (y < ysize) THEN
- IF bpp32 THEN
- sys.PUT(buf + 4 * (xsize * y + x), color)
- ELSE
- sys.MOVE(sys.ADR(color), buf + 3 * (xsize * y + x), 3)
- END
- END
- END pset;
- PROCEDURE pget(buf, x, y: INTEGER; bpp32: BOOLEAN): INTEGER;
- VAR xsize, ysize, color: INTEGER;
- BEGIN
- sys.GET(buf, xsize);
- sys.GET(buf + 4, ysize);
- INC(buf, 8);
- IF (0 <= x) & (x < xsize) & (0 <= y) & (y < ysize) THEN
- IF bpp32 THEN
- sys.GET(buf + 4 * (xsize * y + x), color)
- ELSE
- sys.MOVE(buf + 3 * (xsize * y + x), sys.ADR(color), 3)
- END
- END
- RETURN color
- END pget;
- PROCEDURE getrgb(color: INTEGER; VAR r, g, b: INTEGER);
- BEGIN
- b := LSR(LSL(color, 24), 24);
- g := LSR(LSL(color, 16), 24);
- r := LSR(LSL(color, 8), 24);
- END getrgb;
- PROCEDURE rgb(r, g, b: INTEGER): INTEGER;
- RETURN b + LSL(g, 8) + LSL(r, 16)
- END rgb;
- PROCEDURE create_glyph(VAR Font: TFont_desc; VAR glyph: Glyph; xsize, ysize: INTEGER);
- BEGIN
- glyph.base := Font.mempos;
- glyph.xsize := xsize;
- glyph.ysize := ysize;
- Font.mempos := Font.mempos + xsize * ysize
- END create_glyph;
- PROCEDURE getpix(Font: TFont_desc; n, x, y, xsize: INTEGER): CHAR;
- VAR res: CHAR;
- BEGIN
- sys.GET(Font.mem + n + x + y * xsize, res)
- RETURN res
- END getpix;
- PROCEDURE setpix(VAR Font: TFont_desc; n, x, y, xsize: INTEGER; c: CHAR);
- BEGIN
- sys.PUT(Font.mem + n + x + y * xsize, c)
- END setpix;
- PROCEDURE smooth(VAR Font: TFont_desc; n, xsize, ysize: INTEGER);
- VAR x, y: INTEGER;
- BEGIN
- FOR y := 1 TO ysize - 1 DO
- FOR x := 1 TO xsize - 1 DO
- IF (getpix(Font, n, x, y, xsize) = 1X) & (getpix(Font, n, x - 1, y - 1, xsize) = 1X) &
- (getpix(Font, n, x - 1, y, xsize) = 0X) & (getpix(Font, n, x, y - 1, xsize) = 0X) THEN
- setpix(Font, n, x - 1, y, xsize, 2X);
- setpix(Font, n, x, y - 1, xsize, 2X)
- END;
- IF (getpix(Font, n, x, y, xsize) = 0X) & (getpix(Font, n, x - 1, y - 1, xsize) = 0X) &
- (getpix(Font, n, x - 1, y, xsize) = 1X) & (getpix(Font, n, x, y - 1, xsize) = 1X) THEN
- setpix(Font, n, x, y, xsize, 2X);
- setpix(Font, n, x - 1, y - 1, xsize, 2X)
- END
- END
- END
- END smooth;
- PROCEDURE _bold(VAR Font: TFont_desc; src, dst, src_xsize, dst_xsize, n: INTEGER);
- VAR i, j, k: INTEGER; pix: CHAR;
- BEGIN
- FOR i := 0 TO src_xsize - 1 DO
- FOR j := 0 TO Font.height - 1 DO
- pix := getpix(Font, src, i, j, src_xsize);
- IF pix = 1X THEN
- FOR k := 0 TO n DO
- setpix(Font, dst, i + k, j, dst_xsize, pix)
- END
- END
- END
- END
- END _bold;
- PROCEDURE make_glyph(VAR Font: TFont_desc; c: INTEGER);
- VAR ptr, i, j, max, x, y: INTEGER; s: SET; eoc: BOOLEAN;
- glyph: Glyph; pix: CHAR; bold_width: INTEGER;
- BEGIN
- create_glyph(Font, glyph, Font.width, Font.height);
- x := 0;
- y := 0;
- max := 0;
- ptr := Font.font + Font.char_size * c;
- eoc := FALSE;
- REPEAT
- sys.GET(ptr, s);
- INC(ptr, 4);
- FOR i := 0 TO 31 DO
- IF ~eoc THEN
- IF i IN s THEN
- setpix(Font, glyph.base, x, y, Font.width, 1X);
- IF x > max THEN
- max := x
- END
- ELSE
- setpix(Font, glyph.base, x, y, Font.width, 0X)
- END
- END;
- INC(x);
- IF x = Font.width THEN
- x := 0;
- INC(y);
- eoc := eoc OR (y = Font.height)
- END
- END
- UNTIL eoc;
- IF max = 0 THEN
- max := Font.width DIV 3
- END;
- glyph.width := max;
- smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
- Font.glyphs[0, c] := glyph;
- bold_width := 1;
- create_glyph(Font, glyph, Font.width + bold_width, Font.height);
- _bold(Font, Font.glyphs[0, c].base, glyph.base, Font.glyphs[0, c].xsize, glyph.xsize, bold_width);
- smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
- glyph.width := max + bold_width;
- Font.glyphs[1, c] := glyph;
- create_glyph(Font, glyph, Font.width + (Font.height - 1) DIV 3, Font.height);
- FOR i := 0 TO Font.glyphs[0, c].xsize - 1 DO
- FOR j := 0 TO Font.height - 1 DO
- pix := getpix(Font, Font.glyphs[0, c].base, i, j, Font.glyphs[0, c].xsize);
- IF pix = 1X THEN
- setpix(Font, glyph.base, i + (Font.height - 1 - j) DIV 3, j, glyph.xsize, pix)
- END
- END
- END;
- smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
- glyph.width := max;
- Font.glyphs[2, c] := glyph;
- create_glyph(Font, glyph, Font.width + (Font.height - 1) DIV 3 + bold_width, Font.height);
- _bold(Font, Font.glyphs[2, c].base, glyph.base, Font.glyphs[2, c].xsize, glyph.xsize, bold_width);
- smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
- glyph.width := max + bold_width;
- Font.glyphs[3, c] := glyph;
- END make_glyph;
- PROCEDURE OutChar(Font: TFont_desc; c: INTEGER; x, y: INTEGER; buf: INTEGER; bpp32, smoothing: BOOLEAN; color, style: INTEGER): INTEGER;
- VAR i, x0, y0, xsize, mem, xmax: INTEGER; r, g, b, r0, g0, b0: INTEGER; ch: CHAR; glyph: Glyph;
- BEGIN
- x0 := x;
- y0 := y;
- style := style MOD 4;
- glyph := Font.glyphs[style, c];
- xsize := glyph.xsize;
- xmax := x0 + xsize;
- mem := Font.mem + glyph.base;
- getrgb(color, r0, g0, b0);
- FOR i := mem TO mem + xsize * Font.height - 1 DO
- sys.GET(i, ch);
- IF ch = 1X THEN
- pset(buf, x, y, color, bpp32);
- ELSIF (ch = 2X) & smoothing THEN
- getrgb(pget(buf, x, y, bpp32), r, g, b);
- r := (r * 3 + r0) DIV 4;
- g := (g * 3 + g0) DIV 4;
- b := (b * 3 + b0) DIV 4;
- pset(buf, x, y, rgb(r, g, b), bpp32)
- END;
- INC(x);
- IF x = xmax THEN
- x := x0;
- INC(y)
- END
- END
- RETURN glyph.width
- END OutChar;
- PROCEDURE hline(buf, x, y, width, color: INTEGER; bpp32: BOOLEAN);
- VAR i: INTEGER;
- BEGIN
- FOR i := x TO x + width - 1 DO
- pset(buf, i, y, color, bpp32)
- END
- END hline;
- PROCEDURE TextWidth*(Font: TFont; str, length, params: INTEGER): INTEGER;
- VAR res: INTEGER; c: CHAR;
- BEGIN
- res := 0;
- params := params MOD 4;
- IF Font # NIL THEN
- sys.GET(str, c);
- WHILE (length > 0) OR (length = -1) & (c # 0X) DO
- INC(str);
- res := res + Font.glyphs[params, ORD(c)].width;
- IF length > 0 THEN
- DEC(length)
- END;
- IF length # 0 THEN
- sys.GET(str, c)
- END
- END
- END
- RETURN res
- END TextWidth;
- PROCEDURE TextHeight*(Font: TFont): INTEGER;
- VAR res: INTEGER;
- BEGIN
- IF Font # NIL THEN
- res := Font.height
- ELSE
- res := 0
- END
- RETURN res
- END TextHeight;
- PROCEDURE TextClipLeft(Font: TFont; str, length, params: INTEGER; VAR x: INTEGER): INTEGER;
- VAR x1: INTEGER; c: CHAR;
- BEGIN
- params := params MOD 4;
- sys.GET(str, c);
- WHILE (length > 0) OR (length = -1) & (c # 0X) DO
- INC(str);
- x1 := x;
- x := x + Font.glyphs[params, ORD(c)].width;
- IF x > 0 THEN
- length := 0;
- END;
- IF length > 0 THEN
- DEC(length)
- END;
- IF length # 0 THEN
- sys.GET(str, c)
- END
- END;
- x := x1
- RETURN str - 1
- END TextClipLeft;
- PROCEDURE TextOut*(Font: TFont; canvas, x, y, str, length, color, params: INTEGER);
- VAR width, xsize, ysize, str1, n: INTEGER; c: CHAR; bpp32, smoothing, underline, strike: BOOLEAN;
- BEGIN
- IF Font # NIL THEN
- sys.GET(canvas, xsize);
- sys.GET(canvas + 4, ysize);
- IF (y <= -TextHeight(Font)) OR (y >= ysize) THEN
- length := 0
- END;
- IF length # 0 THEN
- smoothing := 4 IN BITS(params);
- bpp32 := 5 IN BITS(params);
- underline := 2 IN BITS(params);
- strike := 3 IN BITS(params);
- str1 := TextClipLeft(Font, str, length, params, x);
- n := str1 - str;
- str := str1;
- IF length >= n THEN
- length := length - n
- END;
- sys.GET(str, c)
- END;
- WHILE (length > 0) OR (length = -1) & (c # 0X) DO
- INC(str);
- width := OutChar(Font^, ORD(c), x, y, canvas, bpp32, smoothing, color, params);
- IF strike THEN
- hline(canvas, x + ORD(1 IN BITS(params)) * ((Font.height DIV 2) DIV 3), y + Font.height DIV 2, width + 2, color, bpp32)
- END;
- IF underline THEN
- hline(canvas, x, y + Font.height - 1, width + 2, color, bpp32)
- END;
- x := x + width;
- IF x > xsize THEN
- length := 0
- END;
- IF length > 0 THEN
- DEC(length)
- END;
- IF length # 0 THEN
- sys.GET(str, c)
- END
- END
- END
- END TextOut;
- PROCEDURE SetSize*(_Font: TFont; font_size: INTEGER): BOOLEAN;
- VAR temp, offset, fsize, i, memsize, mem: INTEGER;
- c: CHAR; Font, Font2: TFont_desc;
- BEGIN
- offset := -1;
- IF (MIN_FONT_SIZE <= font_size) & (font_size <= MAX_FONT_SIZE) & (_Font # NIL) THEN
- Font := _Font^;
- Font2 := Font;
- temp := Font.data + (font_size - 8) * 4;
- IF (Font.data <= temp) & (temp <= Font.size + Font.data - 4) THEN
- sys.GET(temp, offset);
- IF offset # -1 THEN
- Font.font_size := font_size;
- INC(offset, 156);
- offset := offset + Font.data;
- IF (Font.data <= offset) & (offset <= Font.size + Font.data - 4) THEN
- sys.GET(offset, fsize);
- IF fsize > 256 + 6 THEN
- temp := offset + fsize - 1;
- IF (Font.data <= temp) & (temp <= Font.size + Font.data - 1) THEN
- sys.GET(temp, c);
- IF c # 0X THEN
- Font.height := ORD(c);
- DEC(temp);
- sys.GET(temp, c);
- IF c # 0X THEN
- Font.width := ORD(c);
- DEC(fsize, 6);
- Font.char_size := fsize DIV 256;
- IF fsize MOD 256 # 0 THEN
- INC(Font.char_size)
- END;
- IF Font.char_size > 0 THEN
- Font.font := offset + 4;
- Font.mempos := 0;
- memsize := (Font.width + 10) * Font.height * 1024;
- mem := Font.mem;
- Font.mem := KOSAPI.sysfunc3(68, 12, memsize);
- IF Font.mem # 0 THEN
- IF mem # 0 THEN
- mem := KOSAPI.sysfunc3(68, 13, mem)
- END;
- zeromem(memsize DIV 4, Font.mem);
- FOR i := 0 TO 255 DO
- make_glyph(Font, i)
- END
- ELSE
- offset := -1
- END
- ELSE
- offset := -1
- END
- ELSE
- offset := -1
- END
- ELSE
- offset := -1
- END
- ELSE
- offset := -1
- END
- ELSE
- offset := -1
- END
- ELSE
- offset := -1
- END
- END;
- ELSE
- offset := -1
- END;
- IF offset # -1 THEN
- _Font^ := Font
- ELSE
- _Font^ := Font2
- END
- END
- RETURN offset # -1
- END SetSize;
- PROCEDURE Enabled*(Font: TFont; font_size: INTEGER): BOOLEAN;
- VAR offset, temp: INTEGER;
- BEGIN
- offset := -1;
- IF (MIN_FONT_SIZE <= font_size) & (font_size <= MAX_FONT_SIZE) & (Font # NIL) THEN
- temp := Font.data + (font_size - 8) * 4;
- IF (Font.data <= temp) & (temp <= Font.size + Font.data - 4) THEN
- sys.GET(temp, offset)
- END
- END
- RETURN offset # -1
- END Enabled;
- PROCEDURE Destroy*(VAR Font: TFont);
- BEGIN
- IF Font # NIL THEN
- IF Font.mem # 0 THEN
- Font.mem := KOSAPI.sysfunc3(68, 13, Font.mem)
- END;
- IF Font.data # 0 THEN
- Font.data := KOSAPI.sysfunc3(68, 13, Font.data)
- END;
- DISPOSE(Font)
- END
- END Destroy;
- PROCEDURE LoadFont*(file_name: ARRAY OF CHAR): TFont;
- VAR Font: TFont; data, size, n: INTEGER;
- BEGIN
- data := File.Load(file_name, size);
- IF (data # 0) & (size > 156) THEN
- NEW(Font);
- Font.data := data;
- Font.size := size;
- Font.font_size := 0;
- n := MIN_FONT_SIZE;
- WHILE ~SetSize(Font, n) & (n <= MAX_FONT_SIZE) DO
- INC(n)
- END;
- IF Font.font_size = 0 THEN
- Destroy(Font)
- END
- ELSE
- IF data # 0 THEN
- data := KOSAPI.sysfunc3(68, 13, data)
- END;
- Font := NIL
- END
- RETURN Font
- END LoadFont;
- END kfonts.
|