Subversion Repositories Kolibri OS

Rev

Rev 6613 | 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, File, KOSAPI;
  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] zeromem(size, adr: INTEGER);
  53. BEGIN
  54.   sys.CODE("578B7D0C8B4D0833C09CFCF3AB9D5F")
  55. END zeromem;
  56.  
  57. PROCEDURE pset(buf, x, y, color: INTEGER; bpp32: BOOLEAN);
  58. VAR xsize, ysize: INTEGER;
  59. BEGIN
  60.   sys.GET(buf, xsize);
  61.   sys.GET(buf + 4, ysize);
  62.   INC(buf, 8);
  63.   IF (0 <= x) & (x < xsize) & (0 <= y) & (y < ysize) THEN
  64.     IF bpp32 THEN
  65.       sys.PUT(buf + 4 * (xsize * y + x), color)
  66.     ELSE
  67.       sys.MOVE(sys.ADR(color), buf + 3 * (xsize * y + x), 3)
  68.     END
  69.   END
  70. END pset;
  71.  
  72. PROCEDURE pget(buf, x, y: INTEGER; bpp32: BOOLEAN): INTEGER;
  73. VAR xsize, ysize, color: INTEGER;
  74. BEGIN
  75.   sys.GET(buf, xsize);
  76.   sys.GET(buf + 4, ysize);
  77.   INC(buf, 8);
  78.   IF (0 <= x) & (x < xsize) & (0 <= y) & (y < ysize) THEN
  79.     IF bpp32 THEN
  80.       sys.GET(buf + 4 * (xsize * y + x), color)
  81.     ELSE
  82.       sys.MOVE(buf + 3 * (xsize * y + x), sys.ADR(color), 3)
  83.     END
  84.   END
  85.   RETURN color
  86. END pget;
  87.  
  88. PROCEDURE getrgb(color: INTEGER; VAR r, g, b: INTEGER);
  89. BEGIN
  90.   b := LSR(LSL(color, 24), 24);
  91.   g := LSR(LSL(color, 16), 24);
  92.   r := LSR(LSL(color,  8), 24);
  93. END getrgb;
  94.  
  95. PROCEDURE rgb(r, g, b: INTEGER): INTEGER;
  96.   RETURN b + LSL(g, 8) + LSL(r, 16)
  97. END rgb;
  98.  
  99. PROCEDURE create_glyph(VAR Font: TFont_desc; VAR glyph: Glyph; xsize, ysize: INTEGER);
  100. VAR res: INTEGER;
  101. BEGIN
  102.   glyph.base := Font.mempos;
  103.   glyph.xsize := xsize;
  104.   glyph.ysize := ysize;
  105.   Font.mempos := Font.mempos + xsize * ysize
  106. END create_glyph;
  107.  
  108. PROCEDURE getpix(Font: TFont_desc; n, x, y, xsize: INTEGER): CHAR;
  109. VAR res: CHAR;
  110. BEGIN
  111.   sys.GET(Font.mem + n + x + y * xsize, res)
  112.   RETURN res
  113. END getpix;
  114.  
  115. PROCEDURE setpix(VAR Font: TFont_desc; n, x, y, xsize: INTEGER; c: CHAR);
  116. BEGIN
  117.   sys.PUT(Font.mem + n + x + y * xsize, c)
  118. END setpix;
  119.  
  120. PROCEDURE smooth(VAR Font: TFont_desc; n, xsize, ysize: INTEGER);
  121. VAR x, y: INTEGER;
  122. BEGIN
  123.   FOR y := 1 TO ysize - 1 DO
  124.     FOR x := 1 TO xsize - 1 DO
  125.       IF (getpix(Font, n, x, y, xsize) = 1X) & (getpix(Font, n, x - 1, y - 1, xsize) = 1X) &
  126.          (getpix(Font, n, x - 1, y, xsize) = 0X) & (getpix(Font, n, x, y - 1, xsize) = 0X) THEN
  127.         setpix(Font, n, x - 1, y, xsize, 2X);
  128.         setpix(Font, n, x, y - 1, xsize, 2X)
  129.       END;
  130.       IF (getpix(Font, n, x, y, xsize) = 0X) & (getpix(Font, n, x - 1, y - 1, xsize) = 0X) &
  131.          (getpix(Font, n, x - 1, y, xsize) = 1X) & (getpix(Font, n, x, y - 1, xsize) = 1X) THEN
  132.         setpix(Font, n, x, y, xsize, 2X);
  133.         setpix(Font, n, x - 1, y - 1, xsize, 2X)
  134.       END
  135.     END
  136.   END
  137. END smooth;
  138.  
  139. PROCEDURE _bold(VAR Font: TFont_desc; src, dst, src_xsize, dst_xsize, n: INTEGER);
  140. VAR i, j, k: INTEGER; pix: CHAR;
  141. BEGIN
  142.   FOR i := 0 TO src_xsize - 1 DO
  143.     FOR j := 0 TO Font.height - 1 DO
  144.       pix := getpix(Font, src, i, j, src_xsize);
  145.       IF pix = 1X THEN
  146.         FOR k := 0 TO n DO
  147.           setpix(Font, dst, i + k, j, dst_xsize, pix)
  148.         END
  149.       END
  150.     END
  151.   END
  152. END _bold;
  153.  
  154. PROCEDURE make_glyph(VAR Font: TFont_desc; c: INTEGER);
  155. VAR ptr, i, j, max, x, y: INTEGER; s: SET; eoc: BOOLEAN;
  156.     glyph: Glyph; pix: CHAR; bold_width: INTEGER;
  157. BEGIN
  158.   create_glyph(Font, glyph, Font.width, Font.height);
  159.   x := 0;
  160.   y := 0;
  161.   max := 0;
  162.   ptr := Font.font + Font.char_size * c;
  163.   eoc := FALSE;
  164.   REPEAT
  165.     sys.GET(ptr, s);
  166.     INC(ptr, 4);
  167.     FOR i := 0 TO 31 DO
  168.       IF ~eoc THEN
  169.         IF i IN s THEN
  170.           setpix(Font, glyph.base, x, y, Font.width, 1X);
  171.           IF x > max THEN
  172.             max := x
  173.           END
  174.         ELSE
  175.           setpix(Font, glyph.base, x, y, Font.width, 0X)
  176.         END
  177.       END;
  178.       INC(x);
  179.       IF x = Font.width THEN
  180.         x := 0;
  181.         INC(y);
  182.         eoc := eoc OR (y = Font.height)
  183.       END
  184.     END
  185.   UNTIL eoc;
  186.   IF max = 0 THEN
  187.     max := Font.width DIV 3
  188.   END;
  189.  
  190.   glyph.width := max;
  191.   smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
  192.   Font.glyphs[0, c] := glyph;
  193.  
  194.   bold_width := 1;
  195.  
  196.   create_glyph(Font, glyph, Font.width + bold_width, Font.height);
  197.   _bold(Font, Font.glyphs[0, c].base, glyph.base, Font.glyphs[0, c].xsize, glyph.xsize, bold_width);
  198.   smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
  199.   glyph.width := max + bold_width;
  200.   Font.glyphs[1, c] := glyph;
  201.  
  202.   create_glyph(Font, glyph, Font.width + (Font.height - 1) DIV 3, Font.height);
  203.   FOR i := 0 TO Font.glyphs[0, c].xsize - 1 DO
  204.     FOR j := 0 TO Font.height - 1 DO
  205.       pix := getpix(Font, Font.glyphs[0, c].base, i, j, Font.glyphs[0, c].xsize);
  206.       IF pix = 1X THEN
  207.         setpix(Font, glyph.base, i + (Font.height - 1 - j) DIV 3, j, glyph.xsize, pix)
  208.       END
  209.     END
  210.   END;
  211.   smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
  212.   glyph.width := max;
  213.   Font.glyphs[2, c] := glyph;
  214.  
  215.   create_glyph(Font, glyph, Font.width + (Font.height - 1) DIV 3 + bold_width, Font.height);
  216.   _bold(Font, Font.glyphs[2, c].base, glyph.base, Font.glyphs[2, c].xsize, glyph.xsize, bold_width);
  217.   smooth(Font, glyph.base, glyph.xsize, glyph.ysize);
  218.   glyph.width := max + bold_width;
  219.   Font.glyphs[3, c] := glyph;
  220.  
  221. END make_glyph;
  222.  
  223. PROCEDURE OutChar(Font: TFont_desc; c: INTEGER; x, y: INTEGER; buf: INTEGER; bpp32, smoothing: BOOLEAN; color, style: INTEGER): INTEGER;
  224. VAR i, x0, y0, xsize, mem, xmax: INTEGER; r, g, b, r0, g0, b0: INTEGER; ch: CHAR; glyph: Glyph;
  225. BEGIN
  226.   x0 := x;
  227.   y0 := y;
  228.   style := style MOD 4;
  229.   glyph := Font.glyphs[style, c];
  230.   xsize := glyph.xsize;
  231.   xmax := x0 + xsize;
  232.   mem := Font.mem + glyph.base;
  233.   getrgb(color, r0, g0, b0);
  234.   FOR i := mem TO mem + xsize * Font.height - 1 DO
  235.     sys.GET(i, ch);
  236.     IF ch = 1X THEN
  237.       pset(buf, x, y, color, bpp32);
  238.     ELSIF (ch = 2X) & smoothing THEN
  239.       getrgb(pget(buf, x, y, bpp32), r, g, b);
  240.       r := (r * 3 + r0) DIV 4;
  241.       g := (g * 3 + g0) DIV 4;
  242.       b := (b * 3 + b0) DIV 4;
  243.       pset(buf, x, y, rgb(r, g, b), bpp32)
  244.     END;
  245.     INC(x);
  246.     IF x = xmax THEN
  247.       x := x0;
  248.       INC(y)
  249.     END
  250.   END
  251.   RETURN glyph.width
  252. END OutChar;
  253.  
  254. PROCEDURE hline(buf, x, y, width, color: INTEGER; bpp32: BOOLEAN);
  255. VAR i: INTEGER;
  256. BEGIN
  257.   FOR i := x TO x + width - 1 DO
  258.     pset(buf, i, y, color, bpp32)
  259.   END
  260. END hline;
  261.  
  262. PROCEDURE TextWidth*(Font: TFont; str, length, params: INTEGER): INTEGER;
  263. VAR res: INTEGER; c: CHAR;
  264. BEGIN
  265.   res := 0;
  266.   params := params MOD 4;
  267.   IF Font # NIL THEN
  268.     sys.GET(str, c);
  269.     WHILE (length > 0) OR (length = -1) & (c # 0X) DO
  270.       INC(str);
  271.       res := res + Font.glyphs[params, ORD(c)].width;
  272.       IF length > 0 THEN
  273.         DEC(length)
  274.       END;
  275.       IF length # 0 THEN
  276.         sys.GET(str, c)
  277.       END
  278.     END
  279.   END
  280.   RETURN res
  281. END TextWidth;
  282.  
  283. PROCEDURE TextHeight*(Font: TFont): INTEGER;
  284. VAR res: INTEGER;
  285. BEGIN
  286.   IF Font # NIL THEN
  287.     res := Font.height
  288.   ELSE
  289.     res := 0
  290.   END
  291.   RETURN res
  292. END TextHeight;
  293.  
  294. PROCEDURE TextClipLeft(Font: TFont; str, length, params: INTEGER; VAR x: INTEGER): INTEGER;
  295. VAR x1: INTEGER; c: CHAR;
  296. BEGIN
  297.   params := params MOD 4;
  298.   sys.GET(str, c);
  299.   WHILE (length > 0) OR (length = -1) & (c # 0X) DO
  300.     INC(str);
  301.     x1 := x;
  302.     x := x + Font.glyphs[params, ORD(c)].width;
  303.     IF x > 0 THEN
  304.       length := 0;
  305.     END;
  306.     IF length > 0 THEN
  307.       DEC(length)
  308.     END;
  309.     IF length # 0 THEN
  310.       sys.GET(str, c)
  311.     END
  312.   END;
  313.   x := x1
  314.   RETURN str - 1
  315. END TextClipLeft;
  316.  
  317. PROCEDURE TextOut*(Font: TFont; canvas, x, y, str, length, color, params: INTEGER);
  318. VAR width, xsize, ysize, str1, n: INTEGER; c: CHAR; bpp32, smoothing, underline, strike: BOOLEAN;
  319. BEGIN
  320.   IF Font # NIL THEN
  321.     sys.GET(canvas,     xsize);
  322.     sys.GET(canvas + 4, ysize);
  323.     IF (y <= -TextHeight(Font)) OR (y >= ysize) THEN
  324.       length := 0
  325.     END;
  326.     IF length # 0 THEN
  327.       smoothing := 4 IN BITS(params);
  328.       bpp32 := 5 IN BITS(params);
  329.       underline := 2 IN BITS(params);
  330.       strike := 3 IN BITS(params);
  331.       str1 := TextClipLeft(Font, str, length, params, x);
  332.       n := str1 - str;
  333.       str := str1;
  334.       IF length >= n THEN
  335.         length := length - n
  336.       END;
  337.       sys.GET(str, c)
  338.     END;
  339.     WHILE (length > 0) OR (length = -1) & (c # 0X) DO
  340.       INC(str);
  341.       width := OutChar(Font^, ORD(c), x, y, canvas, bpp32, smoothing, color, params);
  342.       IF strike THEN
  343.         hline(canvas, x + ORD(1 IN BITS(params)) * ((Font.height DIV 2) DIV 3), y + Font.height DIV 2, width + 2, color, bpp32)
  344.       END;
  345.       IF underline THEN
  346.         hline(canvas, x, y + Font.height - 1, width + 2, color, bpp32)
  347.       END;
  348.       x := x + width;
  349.       IF x > xsize THEN
  350.         length := 0
  351.       END;
  352.       IF length > 0 THEN
  353.         DEC(length)
  354.       END;
  355.       IF length # 0 THEN
  356.         sys.GET(str, c)
  357.       END
  358.     END
  359.   END
  360. END TextOut;
  361.  
  362. PROCEDURE SetSize*(_Font: TFont; font_size: INTEGER): BOOLEAN;
  363. VAR temp, offset, fsize, i, memsize, mem: INTEGER;
  364.     c: CHAR; Font, Font2: TFont_desc;
  365. BEGIN
  366.   offset := -1;
  367.   IF (MIN_FONT_SIZE <= font_size) & (font_size <= MAX_FONT_SIZE) & (_Font # NIL) THEN
  368.     Font := _Font^;
  369.     Font2 := Font;
  370.     temp := Font.data + (font_size - 8) * 4;
  371.     IF (Font.data <= temp) & (temp <= Font.size + Font.data - 4) THEN
  372.       sys.GET(temp, offset);
  373.       IF offset # -1 THEN
  374.         Font.font_size := font_size;
  375.         INC(offset, 156);
  376.         offset := offset + Font.data;
  377.         IF (Font.data <= offset) & (offset <= Font.size + Font.data - 4) THEN
  378.           sys.GET(offset, fsize);
  379.           IF fsize > 256 + 6 THEN
  380.             temp := offset + fsize - 1;
  381.             IF (Font.data <= temp) & (temp <= Font.size + Font.data - 1) THEN
  382.               sys.GET(temp, c);
  383.               IF c # 0X THEN
  384.                 Font.height := ORD(c);
  385.                 DEC(temp);
  386.                 sys.GET(temp, c);
  387.                 IF c # 0X THEN
  388.                   Font.width := ORD(c);
  389.                   DEC(fsize, 6);
  390.                   Font.char_size := fsize DIV 256;
  391.                   IF fsize MOD 256 # 0 THEN
  392.                     INC(Font.char_size)
  393.                   END;
  394.                   IF Font.char_size > 0 THEN
  395.                     Font.font := offset + 4;
  396.                     Font.mempos := 0;
  397.                     memsize := (Font.width + 10) * Font.height * 1024;
  398.                     mem := Font.mem;
  399.                     Font.mem := KOSAPI.sysfunc3(68, 12, memsize);
  400.                     IF Font.mem # 0 THEN
  401.                       IF mem # 0 THEN
  402.                         mem := KOSAPI.sysfunc3(68, 13, mem)
  403.                       END;
  404.                       zeromem(memsize DIV 4, Font.mem);
  405.                       FOR i := 0 TO 255 DO
  406.                         make_glyph(Font, i)
  407.                       END
  408.                     ELSE
  409.                       offset := -1
  410.                     END
  411.                   ELSE
  412.                     offset := -1
  413.                   END
  414.                 ELSE
  415.                   offset := -1
  416.                 END
  417.               ELSE
  418.                 offset := -1
  419.               END
  420.             ELSE
  421.               offset := -1
  422.             END
  423.           ELSE
  424.             offset := -1
  425.           END
  426.         ELSE
  427.           offset := -1
  428.         END
  429.       END;
  430.     ELSE
  431.       offset := -1
  432.     END;
  433.     IF offset # -1 THEN
  434.       _Font^ := Font
  435.     ELSE
  436.       _Font^ := Font2
  437.     END
  438.   END
  439.   RETURN offset # -1
  440. END SetSize;
  441.  
  442. PROCEDURE Enabled*(Font: TFont; font_size: INTEGER): BOOLEAN;
  443. VAR offset, temp: INTEGER;
  444. BEGIN
  445.   offset := -1;
  446.   IF (MIN_FONT_SIZE <= font_size) & (font_size <= MAX_FONT_SIZE) & (Font # NIL) THEN
  447.     temp := Font.data + (font_size - 8) * 4;
  448.     IF (Font.data <= temp) & (temp <= Font.size + Font.data - 4) THEN
  449.       sys.GET(temp, offset)
  450.     END
  451.   END
  452.   RETURN offset # -1
  453. END Enabled;
  454.  
  455. PROCEDURE Destroy*(VAR Font: TFont);
  456. BEGIN
  457.   IF Font # NIL THEN
  458.     IF Font.mem # 0 THEN
  459.       Font.mem := KOSAPI.sysfunc3(68, 13, Font.mem)
  460.     END;
  461.     IF Font.data # 0 THEN
  462.       Font.data := KOSAPI.sysfunc3(68, 13, Font.data)
  463.     END;
  464.     DISPOSE(Font)
  465.   END
  466. END Destroy;
  467.  
  468. PROCEDURE LoadFont*(file_name: ARRAY OF CHAR): TFont;
  469. VAR Font: TFont; data, size, n: INTEGER;
  470. BEGIN
  471.   data := File.Load(file_name, size);
  472.   IF (data # 0) & (size > 156) THEN
  473.     NEW(Font);
  474.     Font.data := data;
  475.     Font.size := size;
  476.     Font.font_size := 0;
  477.     n := MIN_FONT_SIZE;
  478.     WHILE ~SetSize(Font, n) & (n <= MAX_FONT_SIZE) DO
  479.       INC(n)
  480.     END;
  481.     IF Font.font_size = 0 THEN
  482.       Destroy(Font)
  483.     END
  484.   ELSE
  485.     IF data # 0 THEN
  486.       data := KOSAPI.sysfunc3(68, 13, data)
  487.     END;
  488.     Font := NIL
  489.   END
  490.   RETURN Font
  491. END LoadFont;
  492.  
  493. END kfonts.