Subversion Repositories Kolibri OS

Rev

Rev 6613 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6613 leency 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 .
16
*)
17
 
18
MODULE kfonts;
19
 
6647 akron1 20
IMPORT sys := SYSTEM, File, KOSAPI;
6613 leency 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;
6647 akron1 233
  getrgb(color, r0, g0, b0);
6613 leency 234
  FOR i := mem TO mem + xsize * Font.height - 1 DO
235
    sys.GET(i, ch);
236
    IF ch = 1X THEN
6647 akron1 237
      pset(buf, x, y, color, bpp32);
6613 leency 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;
6647 akron1 275
      IF length # 0 THEN
276
	sys.GET(str, c)
277
      END
6613 leency 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
 
6647 akron1 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
 
6613 leency 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;
6647 akron1 399
		    Font.mem := KOSAPI.sysfunc3(68, 12, memsize);
6613 leency 400
		    IF Font.mem # 0 THEN
401
		      IF mem # 0 THEN
6647 akron1 402
			mem := KOSAPI.sysfunc3(68, 13, mem)
6613 leency 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
6647 akron1 459
      Font.mem := KOSAPI.sysfunc3(68, 13, Font.mem)
6613 leency 460
    END;
461
    IF Font.data # 0 THEN
6647 akron1 462
      Font.data := KOSAPI.sysfunc3(68, 13, Font.data)
6613 leency 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
6647 akron1 471
  data := File.Load(file_name, size);
6613 leency 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
6647 akron1 486
      data := KOSAPI.sysfunc3(68, 13, data)
6613 leency 487
    END;
488
    Font := NIL
489
  END
490
  RETURN Font
491
END LoadFont;
492
 
493
END kfonts.