File: render.c

package info (click to toggle)
netrik 1.16.1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,288 kB
  • sloc: ansic: 6,657; sh: 994; makefile: 120
file content (322 lines) | stat: -rw-r--r-- 11,153 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/*
   netrik -- The ANTRIK Internet Viewer
   Copyright (C) Olaf D. Buddenhagen AKA antrik, et al (see AUTHORS)
   Published under the GNU GPL; see LICENSE for details.
*/

/*
 * render.c -- generates screen output from the item tree and page map.
 *
 * (C) 2001, 2002 antrik
 *
 * There are functions to dump the whole page to stdout line by line and to
 * render a specified region of the page to a specified (curses) screen region.
 *
 * There is also a debug function which dumps the item tree including the text
 * in the text items, including text attributes, but without the correct layout
 * like dump().
 */

#include <ncursesw/curses.h>
#include <stdlib.h>
#include <ncursesw/term.h>
#include <string.h>

#include "cfg.h"
#include "colors.h"
#include "items.h"
#include "layout.h"
#include "render.h"
#include "screen.h"

#define MIN(a,b) ((a)<(b)?(a):(b))

#ifdef DEBUG
/* dump structure tree;
 * dumps all items in item tree and their strings with correct attributes;
 * also prints positions of items on page */
void dump_items(item_tree)
struct Item	*item_tree;    /* top of item tree to dump */
{
   struct Item	*cur_item;    /* currently dumped item */
   struct Item	*new_item;    /* current item for depth calculations */

   char	*item_name[]={
      "TEXT",
      "BOX",
      "FORM",
      "BLANK",
      "BLOCK_ANCHOR",
      "INLINE_ANCHOR"
   };
   
   /* for all items (starting from top) */
   cur_item=item_tree;
   do {    /* until back at top */

      /* draw tree */
      for(new_item=cur_item; new_item!=item_tree; new_item=new_item->parent)    /* ascend till top */
	 printf("|");
      printf("-");

      /* print item type */
      printf("%s", item_name[cur_item->type]);
      if(cur_item->type==ITEM_BLOCK_ANCHOR) {    /* virtual block -> list children */
	 struct Item	*item;

	 printf(" { ");
	 for(item=cur_item->data.block_anchor->virtual_child; item!=cur_item; item=item->list_next)
	    printf("%s ", item_name[item->type]);
	 printf("}");
      }

      if(cur_item->center)
	 printf(" (center)");

      printf(" (%d,%d - %d,%d)\n", cur_item->x_start, cur_item->y_start, cur_item->x_end, cur_item->y_end);    /* print page position */

      if(cur_item->type==ITEM_TEXT) {    /* text item -> output string */
	 int	cur_div;    /* div currently printed */

	 int	div_start;    /* starting position in string of currend div */
	 int	div_end;    /* starting position in string of next div */

	 for(cur_div=0, div_start=0; cur_div<cur_item->data.string->div_count; ++cur_div) {    /* complete string (all divisions) */
	    div_end=cur_item->data.string->div[cur_div].end;

	    set_color_raw(cur_item->data.string->div[cur_div].color);

	    /* output current div's text */
	    printf("%.*s", div_end-div_start, &cur_item->data.string->text[div_start]);

	    reset_color_raw();

	    div_start=div_end;
	 }    /* for all div's */
	 printf("\n");

	 if(cur_item->data.string->link_count) {
	    int	link;

	    set_color_raw(((COLOR_BLACK|8)<<4)+color_map[TM_LINK]); printf("Links:");
	    reset_color_raw(); printf("\n");

	    for(link=0; link<cur_item->data.string->link_count; ++link)
	       printf("   %d,%d-%d,%d\n", cur_item->data.string->link[link].x_start, cur_item->data.string->link[link].y_start, cur_item->data.string->link[link].x_end, cur_item->data.string->link[link].y_end);    /* print page position */
	 }

      }    /* if text item */

      fflush(stdout);    /* pagers behave funny on segfault... */

      /* next item */
      if(cur_item->first_child==NULL) {    /* no children -> go to next item */
	 while(cur_item->next==NULL)    /* if last item at this depth: ascend before going to next item */
	    cur_item=cur_item->parent;
	 cur_item=cur_item->next;
      } else    /* has children -> descend */
	 cur_item=cur_item->first_child;
   } while(cur_item!=item_tree);    /* for all items (until back at top) */

   printf("\n");
}
#endif

/* dump whole page to screen (stdout) with correct layout */
void dump(layout)
struct Layout_data	*layout;
{
   const struct Item		*item_tree=layout->item_tree;    /* top of item tree of page */
   const struct Item_list	*page_map=layout->page_map;    /* space usage map */

   int		line;    /* line number in page */

   for(line=0; line<item_tree->y_end; ++line) {    /* all lines in page */
      int	item_num;    /* item in current line */

      if(cfg.force_colors) {
         set_color_raw(7);    /* force white on black */
         printf("\n");    /* begin new line after setting background (otherwise the new background isn't applied to the whole line!) */
      }

      for(item_num=0; item_num<page_map[line].count; ++item_num) {    /* all items in line (NOTE: this function presently won't really work if there is actually more than one item in a line!) */
	 const struct Item	*item=page_map[line].item[item_num];    /* current text item */
	 const struct String	*string=item->data.string;    /* current string */

	 const int		text_start=line_start(item, line);    /* starting position of line inside string */
	 const int		text_end=line_end(item, line);    /* ending position of line inside string */
	 const int		x_start=line_pos(item, line);    /* starting column of line on page */

	 int	cur_div;    /* div currently printed */

	 int	div_start;    /* starting position in string of currend div */
	 int	div_end;    /* starting position in string of next div */

	 int	cursor_col;

	 /* set cursor col */
	 for(cursor_col=0; cursor_col<x_start; ++cursor_col)
	    putchar(' ');

	 /* seek div containing beginning of line */
	 for(cur_div=0; (div_end=string->div[cur_div].end)<=text_start; ++cur_div);

	 /* print line */
	 for(div_start=text_start; div_start<text_end; ++cur_div) {    /* all divs containing parts of line */
	    div_end=MIN(string->div[cur_div].end, text_end);    /* div containing end of line is truncated */

	    set_color_raw(string->div[cur_div].color);

	    /* output current div's text */
	    {
	       char	output_string[div_end-div_start+1];
	       char	*src, *dst;

	       /* copy printed string part, replacing &nbsp; chars */
	       for(src=&string->text[div_start], dst=output_string; src < &string->text[div_end]; ++src, ++dst) {
		  if(*src != '\xa0')
		     *dst=*src;
		  else
		     *dst=' ';
	       }
	       *dst=0;

	       printf("%s", output_string);
	    }

	    reset_color_raw();

	    div_start=div_end;    /* next div starts where current one ends */
	 }    /* next div */

	 if((unsigned)string->text[text_end]>' ') {    /* printable character follows end of line => word broken -> display continuation mark */
	    set_color_raw(color_map[TM_SYS]);
	    printf("\\");
	    reset_color_raw();
	 }

      }    /* next item in line */

      if(!cfg.force_colors)    /* end line (if force_color, a linewrap is done *before* printing the line content!) */
         printf("\n");

#ifdef DEBUG
      fflush(stdout);    /* pagers behave funny on segfault... */
#endif
   }    /* next line */

   if(cfg.force_colors)    /* need to end last line (no line breaks are noramlly issued *after* printing a line if force_colors!) */
      printf("\n");

}

/* render specified region of page and output to (curses) screen at specified position */
void render(layout, page_x, page_y, screen_x, screen_y, width, height, overpaint)
struct Layout_data	*layout;
int			page_x, page_y;    /* starting position of rendered region inside page */
int			screen_x, screen_y;    /* starting position on screen */
int			width, height;    /* size of region */
int			overpaint;    /* clean the screen area before rendering */
{
   const struct Item		*item_tree=layout->item_tree;    /* top of item tree of page */
   const struct Item_list	*page_map=layout->page_map;    /* space usage map */

   int		line;    /* line number in page */

   if(page_y+height>item_tree->y_end)    /* try to render lines after the page end -> truncate area */
      height=item_tree->y_end-page_y;

   /* clear area */
   if(overpaint) {
      int	clr_line;
      char	clr_string[width+1];

      memset(clr_string, ' ', width);
      set_color(color_map[TM_NORMAL]);
      for(clr_line=screen_y; clr_line<screen_y+height; ++clr_line)    /* all lines in area */
	 mvprintw(clr_line, screen_x, "%.*s", width, clr_string);    /* overprint with empty string */
   }
	 
   for(line=page_y; line<page_y+height; ++line) {    /* all lines in area */
      int	item_num;    /* item in current line */


      for(item_num=0; item_num<page_map[line].count; ++item_num) {    /* all items in line */
	 const struct Item	*item=page_map[line].item[item_num];    /* current text item */
	 const struct String	*string=item->data.string;    /* current string */

	 int	text_start;    /* position inside string of first char of rendered line part */
	 int	text_end;    /* position after last char */

	 int	x_start;    /* starting position of current line relative to rendered area */
	 int	x_end;    /* position after line end */

	 int	div_start;    /* starting position in string of currend div */
	 int	div_end;    /* starting position in string of next div */
	 int	cur_div;    /* div currently printed */

	 /* first assume whole line will be rendered */
	 text_start=line_start(item, line);
	 text_end=line_end(item, line);

	 /* calc starting column of line relative to start of rendered area */
	 x_start=line_pos(item, line) - page_x;
	 if(x_start<0) {    /* line starts before beginning of rendered area -> truncate */
	    text_start-=x_start;
	    x_start=0;
	 }

	 /* calc ending column */
	 x_end=x_start + (text_end-text_start);
	 if(x_end>width) {    /* line ends after end of rendered area */
	    text_end-=x_end-width;
	    x_end=width;
	 }

	 /* print line */
	 move(screen_y+(line-page_y), screen_x+x_start);    /* set cursor to beginning of line */

	 if(text_end>text_start) {    /* anything to print (some part of line is inside area) */
	    /* seek div containing beginning of line */
	    for(cur_div=0; (div_end=string->div[cur_div].end)<=text_start; ++cur_div);

	    /* output divs */
	    for(div_start=text_start; div_start<text_end; ++cur_div) {    /* all divs containing parts of this line */
	       div_end=string->div[cur_div].end;

	       if(div_end>text_end)    /* div exceeds line end -> truncate */
		  div_end=text_end;

	       set_color(string->div[cur_div].color);

	       /* output current div's text */
	       {
		  char	output_string[div_end-div_start+1];
		  char	*src, *dst;

		  /* copy printed string part, replacing &nbsp; chars */
		  for(src=&string->text[div_start], dst=output_string; src < &string->text[div_end]; ++src, ++dst) {
		     if(*src != '\xa0')
			*dst=*src;
		     else
			*dst=' ';
		  }
		  *dst=0;

		  printw("%s", output_string);
	       }

	       div_start=div_end;    /* next div starts where current one ends */
	    }    /* next div */
	 }

	 if(x_end>=0 && x_end<width && (unsigned)string->text[text_end]>' ') {    /* end of line inside area, and normal character follows => word broken -> display continuation mark */
	    set_color(color_map[TM_SYS]);
	    addch('\\');
	 }

      }    /* next item in line */

   }    /* next line */

}