Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
9896 akron1 1
(*
9898 akron1 2
    Copyright 2018-2020, 2023 Anton Krotov
9896 akron1 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 .
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.