Merge branch 'master' of https://git.maemo.org/projects/erwise
[erwise] / Xl / XlFormatText.c
1 /*
2  * XlFormatText.c --
3  *
4  * Author: Teemu Rantanen <tvr@cs.hut.fi>
5  * Copyright (c) 1992 Teemu Rantanen
6  *                    All rights reserved
7  *
8  * Created: Tue Mar  3 02:54:45 1992 tvr
9  * Last modified: Tue May 12 04:26:29 1992 tvr
10  *
11  */
12
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <limits.h>
16
17 #include "HTAnchor.h"
18 #include "HTStyle.h"
19 #include "../HText/HText.h"
20
21 #include "XlFormatText.h"
22
23 int xl_calc_position();
24 int xl_character_width();
25
26 #define MAX(a, b) ((a) > (b) ? (a) : (b))
27
28 /*
29  * Set up how to format text (current left and right margins)
30  */
31 void xl_set_margins(p, left, right, c_l, c_r, x, y, low_y, m)
32 HTextObject_t *p;
33 int left, right;
34 int *c_l, *c_r;
35 int *x, *y;
36 int low_y;
37 int m;
38 {
39     int i;
40
41     switch (m) {
42     case MARGIN_START_STYLE:
43         i = xl_object_mode(p);
44
45         *c_l = xl_calc_position(p, I_LEFT, left, right);
46
47         *x = xl_calc_position(p, I_LEFT | I_FIRST, left, right);
48
49         if (i & STYLE_RAW) {
50             *c_r = INT_MAX;
51         } else {
52
53             if (i & STYLE_CHANGE_REGION_ON_TAB) {
54
55                 *c_r = xl_calc_position(p, I_MIDDLE_L, left, right);
56
57             } else {
58
59                 *c_r = xl_calc_position(p, I_RIGHT, left, right);
60
61             }
62         }
63         break;
64
65     case MARGIN_HANDLE_P_OBJECT:
66         if (xl_object_mode(p) & STYLE_CHANGE_REGION_ON_TAB) {
67
68             *c_l = xl_calc_position(p, I_MIDDLE_R, left, right);
69             *c_r = xl_calc_position(p, I_RIGHT, left, right);
70             *y = low_y;
71             *x = xl_calc_position(p, I_MIDDLE_R | I_FIRST, left, right);
72
73         } else {
74
75             *x += 60;           /* :-) */
76
77 #ifdef XL_DEBUG
78             printf("xl_set_margins(): normal tab ... barf\n");
79 #endif
80         }
81         break;
82
83 #ifdef XL_DEBUG
84     default:
85         printf("xl_set_margins: illegal mode\n");
86 #endif
87     }
88 }
89
90
91 /*
92  * Check how many objects belongs to this line.
93  */
94 int xl_check_objects(pp, x_corner, y, right)
95 HTextObject_t **pp;
96 int *x_corner;
97 int y;
98 int right;
99 {
100     HTextObject_t *p, *p_old;
101
102     int x;
103
104     int r = 0;
105
106     p = *pp;
107
108     p_old = NULL;
109
110     x = *x_corner;
111
112     while (!r) {
113         /*
114          * Region ends ?
115          */
116         if (!p || (p->paragraph)) {
117             r |= FORMAT_REGION_ENDS;
118         }
119         /*
120          * End of text
121          */
122         if (!p) {
123             break;
124         }
125         /*
126          * New style?
127          */
128         if (p_old && (p_old->style != p->style)) {
129             r |= FORMAT_NEW_STYLE;
130             r |= FORMAT_REGION_ENDS;
131         }
132         /*
133          * Text full ?
134          */
135         if ((x + p->width) >= right) {
136             r |= FORMAT_NEXT_OBJECT_TOO_LONG;
137         }
138         /*
139          * Setup object
140          */
141         p->x = x;
142         p->y = y;
143
144         x += p->width + xl_wordgap(p);
145
146
147         if (!r) {
148             p_old = p;
149
150             p = p->next;
151         }
152     }
153
154     /*
155      * Return pointer to where to go on.
156      */
157     if (p_old) {
158         *pp = p;
159     }
160     *x_corner = x;
161
162     return r;
163 }
164
165 /*
166  * Set new x-koordinate if line of objects is not 'leftified'
167  * Set new y coordinate above all objects.
168  */
169 void xl_modify_objects(p_start, p_end, right, mode)
170 HTextObject_t *p_start;
171 HTextObject_t *p_end;
172 int right;
173 int mode;
174 {
175     HTextObject_t *p = p_start;
176     HTextObject_t *p_last;
177
178     int offset;
179
180     /*
181      * Set last object
182      */
183
184     if (p_start == p_end) {
185
186 #ifdef XL_DEBUG
187         if (!p_start->paragraph) {
188             printf("zero object ?\n");
189         }
190 #endif
191         p_last = p_start;
192
193     } else if (p_end) {
194
195         p_last = p_end->prev;
196
197     } else {
198
199         for (p_last = p; p_last->next; p_last = p_last->next);
200
201     }
202
203     switch (xl_object_style(p_start)) {
204     case STYLE_LEFTIFY:
205         /*
206          * Do nothing.
207          */
208         break;
209
210     case STYLE_CENTER:
211
212         offset = (right - (p_last->x + p_last->width)) / 2;
213
214         for (p; p != p_end; p = p->next) {
215             p->x += offset;
216         }
217         break;
218
219 #ifdef XL_DEBUG
220     default:
221         printf("Style not supported yet\n");
222 #endif
223     }
224 #if 0
225     *newy = p_start->y + xl_lineheightandgap(p_start, p_end);
226 #endif
227 }
228
229
230 /*
231  *  width is a request which can be denied (in case of ftp-text for
232  *  example)
233  *  Maximum width used on the page is returned. Everything else on the screen
234  *  is formatted using given width.
235  */
236 int XlFormatText(leftmargin, width, topmargin, vwidth, vheight, htext)
237 int leftmargin, width;
238 int topmargin;
239 int *vwidth, *vheight;
240 HText_t *htext;
241 {
242     int stepped_y;
243
244     int max_right_position = leftmargin;
245
246     /*
247      * Current x,y coordinates.
248      */
249     int x, y;
250
251     /*
252      * When there are many regions next to other, store starting
253      * upper and lower levels
254      */
255     int low_y = 0;
256     int high_y = 0;
257
258     /*
259      * current format region
260      */
261     int current_left;
262     int current_right;
263
264     /*
265      * Point out line
266      */
267     HTextObject_t *p = htext->first;
268
269     HTextObject_t *p_start = 0;
270
271     /*
272      * Should check ascend (if there is any text)
273      */
274     if (p) {
275
276         low_y = high_y = y = topmargin;
277
278         xl_set_margins(p, leftmargin, leftmargin + width,
279                        &current_left, &current_right,
280                        &x, &y, low_y, MARGIN_START_STYLE);
281     }
282     /*
283      * Loop through text
284      */
285     while (p) {
286         int mode;
287
288         int high_y_old;
289
290         stepped_y = 0;
291
292         high_y_old = y;
293
294         /*
295          * What objects are on this line ?
296          */
297         p_start = p;
298
299         mode = xl_check_objects(&p, &x, y, current_right);
300
301         /*
302          * Check for zero objects. This prevents endless loop and makes
303          * sure this object will be modified
304          */
305         if ((p == p_start) && p && !p->paragraph &&
306             (mode & FORMAT_NEXT_OBJECT_TOO_LONG)) {
307             mode |= FORMAT_ONLY_OBJECT_TOO_LONG;
308             p = p->next;
309         }
310         /*
311          * Update object positions if needs justifying etc
312          */
313         xl_modify_objects(p_start, p, current_right, mode);
314
315         /*
316          * Check maximum object x position
317          */
318
319         if (p && p->prev &&
320             ((p->prev->x + p->prev->width) > max_right_position)) {
321             max_right_position = p->prev->x + p->prev->width;
322         }
323         if (xl_object_mode(p_start) & STYLE_RAW) {
324             /*
325              * Raw style HTextObject paragraphs
326              */
327
328             if (p && p_start->paragraph) {
329                 p = p->next;
330
331             }
332             switch (p_start->paragraph) {
333             case HTEXT_NEWLINE:
334                 /*
335                  * New line
336                  */
337                 x = current_left;
338
339                 y += xl_linespace(p_start, p);
340
341                 low_y = high_y = MAX(y, high_y);
342                 break;
343
344             case HTEXT_TAB:
345                 /*
346                  * Tabulator
347                  */
348 #if 0
349                 {
350                     int i = 0;
351                     HTextObject_t *pp;
352
353                     for (pp = p_start; pp != p; pp = pp->next) {
354                         switch (pp->paragraph) {
355                         case 0:
356                             i += pp->length;
357                             break;
358
359                         case HTEXT_TAB:
360                             i = 0;
361                         }
362                     }
363
364                     i = 8 - (i % 8);
365
366                     x += xl_character_width(p_start) * i;
367                 }
368 #endif
369                 {
370                     int i;
371                     int cl = xl_character_width(p_start);
372
373                     i = ((x - leftmargin) % (cl * 8));
374
375                     x += (cl * 8) - i;
376                 }
377
378                 break;
379             }
380         } else {
381             /*
382              * Hypertext style
383              */
384
385             /*
386              * Wrap
387              */
388             if (mode & FORMAT_NEXT_OBJECT_TOO_LONG) {
389                 x = current_left;
390                 y += xl_linespace(p_start, p);
391
392                 high_y = MAX(y, high_y);
393
394                 if (mode & FORMAT_ONLY_OBJECT_TOO_LONG) {
395                     low_y = high_y;
396                 }
397                 stepped_y++;
398             }
399             /*
400              * Check paragraph objects
401              */
402             if (p_start->paragraph) {
403                 switch (p_start->paragraph) {
404                 case HTEXT_NEWLINE:
405
406                     x = current_left;
407                     if (!stepped_y) {
408                         y += xl_linespace(p_start, p);
409
410                         stepped_y++;
411
412                         high_y = MAX(y, high_y);
413                     }
414                     high_y = y;
415
416 #ifdef XL_DEBUG
417                     printf("XlFormatText(): there should not be newlines in htext\n");
418 #endif
419                     break;
420
421                 case HTEXT_PARAGRAPH:
422
423                     if (!stepped_y) {
424                         y += xl_linespace(p_start, p);
425                         y += xl_paragraphspace(p_start, p);
426
427                         stepped_y++;
428                     }
429                     low_y = high_y = y;
430
431                     xl_set_margins(p, leftmargin, leftmargin + width,
432                                    &current_left, &current_right,
433                                    &x, &y, low_y, MARGIN_START_STYLE);
434                     break;
435
436                 case HTEXT_TAB:
437
438                     xl_set_margins(p, leftmargin, leftmargin + width,
439                                    &current_left, &current_right, &x, &y,
440                                    low_y, MARGIN_HANDLE_P_OBJECT);
441                     break;
442
443                 case HTEXT_CONTINUE:
444                     printf("format: dont understand continued objects here\n");
445                     exit(1);
446                     break;
447
448                 }
449
450                 p = p->next;
451
452             }
453         }
454
455         /*
456          * Make sure paragraph endings happen
457          */
458         if (p && (p->style != p_start->style)) {
459             mode |= FORMAT_NEW_STYLE;
460         }
461         /*
462          * Check for new style
463          */
464         if (mode & FORMAT_NEW_STYLE) {
465             /*
466              * Make sure one and only line is advanced always
467              */
468             if (y < high_y) {
469                 if (!stepped_y) {
470                     high_y += xl_linespace(p_start, p);
471                 }
472                 high_y += xl_stylespace(p_start, p);
473
474                 y = low_y = high_y;
475
476                 stepped_y++;
477             } else {
478                 if (high_y_old == high_y) {
479                     high_y += xl_linespace(p_start, p);
480                 }
481                 if (p) {
482                     high_y += xl_stylespace_before(p, p);
483                 }
484                 high_y += xl_stylespace(p_start, p);
485
486                 y = low_y = high_y;
487
488                 stepped_y++;
489             }
490
491             xl_set_margins(p, leftmargin, leftmargin + width,
492                            &current_left, &current_right,
493                            &x, &y, low_y, MARGIN_START_STYLE);
494         }
495     }
496
497 #if 0
498     /*
499      * Check region ending
500      */
501     /* tab sivulle tai tab sivulleyl|s depending on object and so on */
502     /* p = p->next */
503     /* set regions with margin_handle_p_object */
504     /* check where to start (y, x). x = regionstart or tab */
505
506     if ((mode & FORMAT_REGION_ENDS) && p) {
507         int i;
508
509         i = p->paragraph;
510
511         switch (i) {
512         case HTEXT_PARAGRAPH:
513             high_y += xl_lineheightandgap(p_start, p);
514
515             y = low_y = high_y;
516
517             xl_set_margins(p, leftmargin, leftmargin + width,
518                            &current_left, &current_right,
519                            &x, &y, low_y, MARGIN_START_STYLE);
520             break;
521
522         case HTEXT_NEWLINE:
523             /*high_y += xl_lineheightandgap(p_start, p);*/
524             y = low_y = high_y;
525             x = current_left;
526
527             break;
528
529         case HTEXT_TAB:
530             xl_set_margins(p, leftmargin, leftmargin + width,
531                            &current_left, &current_right, &x, &y, low_y,
532                            MARGIN_HANDLE_P_OBJECT);
533             break;
534
535         case HTEXT_CONTINUE:
536             printf("format: dont understand continued objects here\n");
537             exit(1);
538             break;
539
540         }
541
542         if (i) {
543             p = p->next;
544         }
545     }
546     /*
547      * Check New style
548      */
549     if (mode & FORMAT_NEW_STYLE) {
550         high_y = low_y = y;
551
552         xl_set_margins(p, leftmargin, leftmargin + width,
553                        &current_left, &current_right,
554                        &x, &y, low_y, MARGIN_START_STYLE);
555     }
556 #endif
557
558     /*
559      * Give width and height to caller
560      */
561
562     if (!stepped_y) {
563         if (p_start)
564             y += xl_linespace(p_start, p);
565         else
566             y = 1;
567     }
568     *vwidth = MAX(max_right_position, width);
569
570     *vheight = y;
571
572     return 0;
573 }