Subversion Repositories Kolibri OS

Rev

Rev 9896 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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