Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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