dtcalc: change from obsoleted MAXFLOAT to FLT_MAX from std C
[oweals/cde.git] / cde / lib / DtHelp / Canvas.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: Canvas.c /main/40 1999/10/14 13:17:22 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:        Canvas.c
28  **
29  **   Project:     Cde Help System
30  **
31  **   Description: UI independent layer for the help system.  These
32  **                routines manage the information within a 'canvas'.
33  **                The 'canvas' routines call UI dependent code to
34  **                render the information.
35  **
36  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
37  **
38  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
39  **  (c) Copyright 1993, 1994 International Business Machines Corp.
40  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
41  **  (c) Copyright 1993, 1994 Novell, Inc.
42  ****************************************************************************
43  ************************************<+>*************************************/
44
45 /*
46  * system includes
47  */
48 #include <stdlib.h>
49 #include <string.h>
50
51 /*
52  * Canvas Engine includes
53  */
54 #include "CanvasP.h"
55 #include "CanvasSegP.h"
56
57 /*
58  * private includes
59  */
60 #include "CanvasI.h"
61 #include "CvStringI.h"
62 #include "LinkMgrI.h"
63 #include "LayoutUtilI.h"
64 #include "SelectionI.h"
65 #include "VirtFuncsI.h"
66
67 #ifdef NLS16
68 #endif
69
70 /********    Private Function Declarations    ********/
71 static _DtCvUnit        DrawText(
72                                 _DtCanvasStruct *canvas,
73                                 _DtCvDspLine    *line,
74                                 int              txt_line,
75                                 _DtCvFlags       old_flag,
76                                 _DtCvFlags       new_flag );
77 /********    End Private Function Declarations    ********/
78
79 /*****************************************************************************
80  *              Private Variables
81  *****************************************************************************/
82 static  _DtCanvasStruct DefaultCanvas =
83   {
84         0,              /* int error;                  */
85         0,              /* int txt_cnt;                */
86         0,              /* int txt_max;                */
87         0,              /* int line_cnt;               */
88         0,              /* int line_max;               */
89         0,              /* int mark_cnt;               */
90         0,              /* int mark_max;               */
91         0,              /* int trav_cnt;               */
92         0,              /* int trav_max;               */
93         0,              /* int cur_trav;               */
94         0,              /* search_cnt */
95         0,              /* search_max */
96         0,              /* brk_cnt                     */
97         0,              /* brk_max                     */
98         1,              /* short mb_length;            */
99         0,              /* _DtCvUnit max_x;            */
100         0,              /* _DtCvUnit max_y;            */
101         _DtCvIGNORE_BOUNDARY,   /* _DtCvValue   constraint; */
102         _DtCvFALSE,     /* _DtCvValue   trav_on;            */
103         NULL,           /* _DtCvPointer    client_data;     */
104           {             /* CanvasMetrics metrics;           */
105             0,                  /* _DtCvUnit width;         */
106             0,                  /* _DtCvUnit height;        */
107             0,                  /* _DtCvUnit top_margin;    */
108             0,                  /* _DtCvUnit line_height;   */
109             0,                  /* _DtCvUnit horiz_pad_hint;   */
110           },
111           {             /* _DtCvSpaceMetrics link_info; */
112             0,                  /* _DtCvUnit space_before; */
113             0,                  /* _DtCvUnit space_after;  */
114             0,                  /* _DtCvUnit space_above;  */
115             0,                  /* _DtCvUnit space_below;  */
116           },
117           {             /* _DtCvSpaceMetrics traversal_info; */
118             0,                  /* _DtCvUnit space_before; */
119             0,                  /* _DtCvUnit space_after;  */
120             0,                  /* _DtCvUnit space_above;  */
121             0,                  /* _DtCvUnit space_below;  */
122           },
123           {             /* _DtCvLocale locale; */
124             _DtCvModeWrapNone,  /* _DtCvModeType  line_wrap_mode;    */
125             NULL,               /* const wchar_t *cant_begin_chars;  */
126             NULL,               /* const wchar_t *cant_end_chars;    */
127           },
128         NULL,           /* _DtCvSegment      *element_lst;   */
129         NULL,           /* _DtCvDspLine       *txt_lst;       */
130         NULL,           /* _DtCvLineSeg  *line_lst;       */
131         NULL,           /* _DtCvTraversalInfo *trav_lst;      */
132         NULL,           /* _DtCvLinkDb        link_data; */
133           {             /* CESelection select_start; */
134                 -1,             /* _DtCvUnit x;           */
135                 -1,             /* _DtCvUnit y;           */
136                 -1,             /* int  line_idx;    */
137                 -1,             /* int  char_idx;    */
138           },
139           {             /* CESelection select_end; */
140                 -1,             /* _DtCvUnit x;           */
141                 -1,             /* _DtCvUnit y;           */
142                 -1,             /* int  line_idx;    */
143                 -1,             /* int  char_idx;    */
144           },
145         NULL,           /* _DtCvMarkData        *marks; */
146         NULL,           /* searchs */
147         NULL,           /* pg_breaks */
148         { NULL },       /* _DtCvVirtualInfo      virt_functions; */
149   };
150
151 /*****************************************************************************
152  *              Private Functions
153  *****************************************************************************/
154 /*****************************************************************************
155  * Function: RenderSubSet
156  *
157  * Returns:     nothing
158  * Purpose:     Render the items next to an item of text.
159  *
160  *****************************************************************************/
161 static  void
162 RenderSubSet (
163     _DtCanvasStruct     *canvas,
164     _DtCvDspLine        *lines,
165     int                  cnt,
166     _DtCvUnit            y1,
167     _DtCvUnit            y2,
168     _DtCvUnit           *last_y)
169 {
170     int         i;
171     _DtCvUnit   minY;
172     _DtCvUnit   maxY;
173
174     /*
175      * Loop through the list looking for the item(s) next to the text.
176      */
177     for (i = 0; NULL != lines && i < cnt; lines++, i++)
178       {
179         /*
180          * get the minimum and maximum y of the next line
181          */
182         minY = lines->baseline - lines->ascent;
183         maxY = lines->baseline + lines->descent;
184
185         /*
186          * has this line been reviewed yet?
187          * is this line on the 'page'?
188          * Does it hang off the 'page' (and if so is it allowed)?
189          */
190         if (_DtCvIsNotProcessed(*lines) && maxY >= y1 && maxY <= y2)
191           {
192             (void) DrawText (canvas, lines, i, 0, 0);
193
194             /*
195              * indicate that this line has been rendered.
196              */
197             _DtCvSetProcessed(*lines);
198
199             /*
200              * is this the maximum that we've rendered?
201              */
202             if (*last_y < maxY)
203                 *last_y = maxY;
204
205             /*
206              * now render anything next to this!
207              */
208             RenderSubSet(canvas, canvas->txt_lst, cnt, minY, y2, last_y);
209           }
210       }
211 }
212
213 /*****************************************************************************
214  * Function: CheckAround
215  *
216  * Returns:     _DtCvSTATUS_NONE        if no other text is to the side of
217  *                                      this text.
218  *              _DtCvFALSE              if other text is to the side, but the
219  *                                      maximum y position is not violated.
220  *              _DtCvTRUE               if other text is to the side and the
221  *                                      maximum y position is violated.
222  * Purpose:  Find if another line of text intrudes upon this line.
223  *
224  *****************************************************************************/
225 static  _DtCvStatus
226 CheckAround (
227     _DtCvDspLine        *lines,
228     int                  cnt,
229     int                  idx,
230     _DtCvUnit            y2)
231 {
232     int         i    = 0;
233     _DtCvUnit   topY = lines[idx].baseline - lines[idx].ascent;
234     _DtCvUnit   botY = lines[idx].baseline + lines[idx].descent;
235     _DtCvUnit   minY;
236     _DtCvUnit   maxY;
237     _DtCvStatus result = _DtCvSTATUS_NONE;
238
239     /*
240      * set the processed flag so that we don't test something that's
241      * already tested.
242      */
243     _DtCvSetProcessed(lines[idx]);
244
245     /*
246      * go through looking for unprocessed lines to test.
247      */
248     while (i < cnt && _DtCvTRUE != result)
249       {
250         if (_DtCvIsNotProcessed(lines[i]))
251           {
252             /*
253              * calculate the minimum and maximum y positions for the line.
254              */
255             minY = lines[i].baseline - lines[i].ascent;
256             maxY = lines[i].baseline + lines[i].descent;
257
258             /*
259              * Does this line infringe vertically on the test line?
260              */
261             if (maxY > topY && minY < botY &&
262                 _DtCvTRUE == _DtCvCheckInfringement(topY, botY, minY, maxY))
263               {
264                 /*
265                  * indicate that it is not clear to the side.
266                  */
267                 result = _DtCvFALSE;
268
269                 /*
270                  * Does it have something else infringing one it?
271                  * Or does it hang down below the test line?
272                  */
273                 if (maxY > y2 || _DtCvTRUE == CheckAround(lines, cnt, i, y2))
274                     result = _DtCvTRUE;
275               }
276           }
277
278         i++;
279       }
280
281     /*
282      * Clear that this line has be processed. Otherwise, rendering will
283      * think this has been rendered when it hasn't.
284      */
285     _DtCvClearProcessed(lines[idx]);
286
287     return result;
288 }
289
290 /*****************************************************************************
291  * Function: FindChar
292  *
293  *    FindChar calculates the char that is x pixels into the string.
294  *
295  *****************************************************************************/
296 static  int
297 FindChar (
298     _DtCanvasStruct     *canvas,
299     _DtCvSegmentI       *segment,
300     void                *string,
301     int                  max_len,
302     _DtCvUnit            x_pos,
303     _DtCvUnit           *diff)
304 {
305     int     myIndex;
306     _DtCvUnit    myDiff = 0;
307     _DtCvUnit    len;
308     _DtCvUnit    charWidth;
309     _DtCvValue triedBack    = False;
310     _DtCvValue triedForward = False;
311
312     /*
313      * get information about the font used
314      */
315     _DtCvFontMetrics(canvas, _DtCvFontOfStringSeg(segment),
316                                         NULL, NULL, &charWidth, NULL, NULL);
317
318     /*
319      * try to get close to the correct index.
320      */
321     myIndex = x_pos / charWidth;
322     if (myIndex >= max_len)
323         myIndex = max_len - 1;
324     
325     while (!triedBack || !triedForward)
326       {
327         len = _DtCvGetStringWidth(canvas, segment, string, myIndex + 1);
328
329         if (len > x_pos)
330           {
331             myDiff       = len - x_pos;
332             triedForward = True;
333             if (!triedBack && myIndex)
334                 myIndex--;
335             else
336                 triedBack = True;
337           }
338         else if (len < x_pos)
339           {
340             myDiff    = x_pos - len;
341             triedBack = True;
342             myIndex++;
343             if (myIndex >= max_len)
344               {
345                 myIndex--;
346                 triedForward = True;
347               }
348           }
349         else /* len == x_pos */
350           {
351             myIndex++;
352             triedBack    = True;
353             triedForward = True;
354             myDiff       = 0;
355           }
356       }
357
358     if (diff != NULL)
359         *diff = myDiff;
360
361     return (myIndex);
362 }
363
364 /*****************************************************************************
365  * Function: DrawCanvasLines
366  *
367  *****************************************************************************/
368 static void
369 DrawCanvasLines(
370     _DtCanvasStruct     *canvas,
371     _DtCvUnit            x1,
372     _DtCvUnit            y1,
373     _DtCvUnit            x2,
374     _DtCvUnit            y2,
375     _DtCvRenderType      flag,
376     _DtCvUnit           *ret_y,
377     _DtCvUnit           *ret_next)
378 {
379     int    i;
380     _DtCvUnit     newY2 = y2;
381     _DtCvLineSeg *pLS;
382     _DtCvLineInfo lnInfo;
383
384     /*
385      * are there any lines?
386      */
387     if (canvas->line_lst != NULL && canvas->line_cnt &&
388                                 NULL != canvas->virt_functions.render_elem)
389       {
390         /*
391          * find the maximum y of all the lines that fit in the page.
392          * do this only if the flag indicates whole lines.
393          */
394         if (_DtCvRENDER_COMPLETE == flag)
395           {
396             for (i = 0, pLS = canvas->line_lst;
397                                         i < canvas->line_cnt; i++, pLS++)
398               {
399                 /*
400                  * Does this line end off the page?
401                  */
402                 if (pLS->max_y > newY2 && pLS->pos_y < newY2)
403                     newY2 = pLS->pos_y - 1;
404               }
405           }
406
407         /*
408          * check each line to see if it is on the 'page'
409          */
410         for (i = 0, pLS = canvas->line_lst; i < canvas->line_cnt; i++, pLS++)
411           {
412             lnInfo.width = pLS->width;
413             lnInfo.data  = pLS->data;
414             lnInfo.x2    = pLS->pos_x;
415             lnInfo.y2    = pLS->pos_y;
416
417             /*
418              * horizontal or vertial line?
419              */
420             if (_DtCvLINE_HORZ == pLS->dir)
421                 lnInfo.x2 = pLS->max_x;
422             else
423                 lnInfo.y2 = pLS->max_y;
424
425             /*
426              * does it fit on the page? Take into account the rendering type.
427              */
428             if (pLS->max_y >= y1 && pLS->pos_y <= newY2
429                 && lnInfo.x2 >= x1 && pLS->pos_x <= x2
430                 && (_DtCvRENDER_PARTIAL == flag || pLS->max_y <= newY2))
431               {
432                 if (pLS->max_y > *ret_y)
433                     *ret_y = pLS->max_y;
434
435                 (*(canvas->virt_functions.render_elem))(
436                         canvas->client_data, _DtCvLINE_TYPE,
437                         pLS->pos_x, pLS->pos_y, -1, 0, 0,
438                         _DtCvBAD_TYPE, NULL, &lnInfo);
439               }
440             /*
441              * otherwise, would this start the next page?
442              * make sure this is in the horizontal space.
443              */
444             else if (lnInfo.x2 >= x1 && pLS->pos_x <= x2 && pLS->max_y > newY2
445                                 && (-1 == *ret_next || *ret_next > pLS->pos_y))
446                 *ret_next = pLS->pos_y;
447           }
448       }
449 } /* End DrawCanvasLines */
450
451 /******************************************************************************
452  * Function: DrawText
453  *
454  * Parameters:
455  *              canvas          Specifies the canvas on which to render
456  *                              the text.
457  *              line            Specifies the line in the line table.
458  *              start_x         Specifies the starting x position to use
459  *                              for selected text. If greater than the
460  *                              starting position for the segment, determine
461  *                              the closest character to 'start_x' and
462  *                              use it.
463  *              end_x           Specifies the ending x position to use
464  *                              for selected text. If -1, means display
465  *                              the entire set of segments.
466  *              old_flag        Specifies....
467  *              new_flag        Specifies....
468  *
469  * Returns:     max_x           Returns the maximum x unit processed.
470  *
471  * Purpose: DrawText draws text segments on one line in the
472  *          line table.
473  *
474  *****************************************************************************/
475 static _DtCvUnit
476 DrawText(
477     _DtCanvasStruct     *canvas,
478     _DtCvDspLine        *line,
479     int                  txt_line,
480     _DtCvFlags           old_flag,
481     _DtCvFlags           new_flag )
482 {
483     int          len;
484     int          curIdx  = 0;
485     int          lastLnk = -1;
486     int          count   = line->length;
487     int          start   = line->byte_index;
488     _DtCvUnit    xPos;
489     _DtCvUnit    superWidth = 0;
490     _DtCvUnit    superY     = 0;
491     _DtCvUnit    subWidth   = 0;
492     _DtCvUnit    subY       = 0;
493     _DtCvUnit    scriptX    = 0;
494     _DtCvValue   lastWasSuper = False;
495     _DtCvValue   lastWasSub   = False;
496     _DtCvValue   lastLnkVis   = False;
497     _DtCvSegmentI *pSeg;
498
499     xPos = _DtCvGetStartXOfLine(line, &pSeg);
500
501     /*
502      * get the corrected x for links and traversals.
503      */
504     xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos, &lastLnk, &lastLnkVis);
505
506     /*
507      * take into account the if this is a super or sub script - or not.
508      */
509     xPos = _DtCvAdjustForSuperSub(canvas, pSeg, xPos,
510                                         &scriptX, &superWidth, &superY,
511                                         &subWidth, &subY,
512                                         &lastWasSuper, &lastWasSub);
513     /*
514      * now process the line
515      */
516     while (NULL != pSeg && 0 < count)
517       {
518         len = count;
519
520         /*
521          * check for selected and marked text.
522          */
523         _DtCvCheckLineMarks(canvas, txt_line, curIdx, count, xPos,
524                                 (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
525                                 &len, &old_flag, &new_flag);
526
527         /*
528          * if this is the last segment(s) of the (un)selection
529          * set the end flags.
530          */
531         if (len == count)
532           {
533             new_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
534             old_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
535           }
536
537         /*
538          * render the segment length returned by _DtCvCheckLineMarks
539          */
540         xPos = _DtCvDrawSegments(canvas, *line, pSeg, start, len,
541                                 &lastLnk, xPos, xPos,
542                                 &scriptX, &superWidth, &superY, &subWidth,
543                                 &subY, &lastWasSub, &lastWasSuper,
544                                 &lastLnkVis, old_flag, new_flag,
545                                 _DtCvBAD_TYPE, NULL);
546         /*
547          * decrement the count by the length processed
548          */
549         count  -= len;
550         curIdx += len;
551         if (0 < count)
552                 _DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
553                                                 &start, &pSeg);
554       }
555
556     return xPos;
557
558 } /* End DrawText */
559
560 /*****************************************************************************
561  * Function: IsLineSpecial (
562  *
563  * Purpose:     Call a virtual function to draw the traversal indicator
564  *****************************************************************************/
565 static  _DtCvValue
566 IsLineSpecial (
567     _DtCvSelectData     start,
568     _DtCvSelectData     end,
569     _DtCvDspLine        line,
570     int                 line_idx,
571     int                 char_idx,
572     int                 length,
573     _DtCvUnit           dst_x,
574     int                 *ret_len,
575     _DtCvFlags          *ret_flag)
576 {
577     _DtCvUnit  maxY = line.baseline + line.descent;
578     _DtCvUnit  minY = line.baseline - line.ascent;
579     _DtCvFlags flag = 0;
580
581     /*
582      * zero out the return flag (which will be a logical OR of
583      * the mark flags.
584      */
585     if (NULL != ret_flag)
586         *ret_flag = 0;
587
588     /*
589      * initialize the return value to the given inspection length.
590      */
591     *ret_len = length;
592
593     /*
594      * is there anything to look at?
595      */
596     if (start.y == -1 || maxY < start.y || minY >= end.y)
597         return False;
598
599     /*
600      * starts the mark/selection?
601      */
602     if (line_idx == start.line_idx)
603       {
604         /*
605          * does this segment straddle the start of the mark/selection?
606          */
607         if (start.char_idx > char_idx)
608           {
609             /*
610              * draw part(or all) of the segment un-mark/selected.
611              * never return a value larger than the inspection length!
612              */
613             if (start.char_idx < char_idx + length)
614                 *ret_len = start.char_idx - char_idx;
615
616             return False;
617           }
618
619         /*
620          * does this segment start the line? Set the start flag if so.
621          */
622         if (start.char_idx == char_idx)
623             flag |= _DtCvMARK_BEGIN;
624
625         /*
626          * does this line end the mark/selection?
627          */
628         if (line_idx == end.line_idx)
629           {
630             /*
631              * does this line straddle the end?
632              */
633             if (char_idx >= end.char_idx)
634               {
635                 /*
636                  * draw this un mark/selected.
637                  * Its after the mark/selected part.
638                  */
639                 return False;
640               }
641
642             if (char_idx + length > end.char_idx)
643               {
644                 /*
645                  * draw the mark/selected part
646                  */
647                 *ret_len = end.char_idx - char_idx;
648                 flag    |= _DtCvMARK_END;
649               }
650           }
651
652         /*
653          * draw the current *ret_len as mark/selected
654          */
655       }
656
657     /*
658      * does this start the mark/selection?
659      */
660     else if (line_idx == end.line_idx)
661       {
662         /*
663          * does not start the mark/selection.
664          * does end the mark/selection.
665          */
666         if (char_idx >= end.char_idx)
667             return False;
668
669         /*
670          * straddle the end position?
671          */
672         if (char_idx + length > end.char_idx)
673           {
674             *ret_len = end.char_idx - char_idx;
675             flag    |= _DtCvMARK_END;
676           }
677         /*
678          * draw the current *ret_len as mark/selected
679          */
680       }
681
682     /*
683      * start.y != -1
684      * start.y <= maxY && minY < end.y
685      */
686     else if (minY < start.y)
687       {
688         /*
689          * straddles the start y
690          */
691         if (dst_x < start.x)
692             return False;
693
694         /*
695          * dst_x > start.x
696          */
697         if (start.y != end.y)
698           {
699             if (NULL != ret_flag)
700                 *ret_flag = flag;
701             return True;
702           }
703
704         /*
705          * dst_x >= end.x
706          */
707         if (dst_x > end.x)
708             return False;
709       }
710     /*
711      * start.y <= minY and maxY
712      * minY < end.y
713      */
714     else if (end.y <= maxY)
715       {
716         /*
717          * straddles the end y position
718          */
719         if (dst_x >= end.x)
720             return False;
721       }
722     /*
723      * start.y <= minY and maxY
724      * minY && maxY < end.y
725      */
726     if (NULL != ret_flag)
727         *ret_flag = flag;
728
729     return True;
730 }
731
732 /*****************************************************************************
733  * Function: DrawTraversalIndicator (_DtCanvasStruct *canvas, _DtCvValue flag)
734  *
735  * Purpose: (Un)draws the traversal around the currently active link.
736  *****************************************************************************/
737 static  void
738 DrawTraversalIndicator (
739     _DtCanvasStruct     *canvas,
740     _DtCvValue           render,
741     _DtCvValue           draw_flag,
742     _DtCvUnit           *ret_x,
743     _DtCvUnit           *ret_y,
744     _DtCvUnit           *ret_baseline,
745     _DtCvUnit           *ret_height)
746 {
747     int     count;
748     int     len;
749     int     start;
750     int     wrkChr;
751     int     totCnt;
752     int     travIdx = canvas->cur_trav;
753     int     curIdx = 0;
754     int     txtLine   = canvas->trav_lst[travIdx].idx;
755     int     linkIndex;
756     int     lstLnk    = -1;
757
758     _DtCvUnit    height = 0;
759     _DtCvUnit    dstX;
760     _DtCvUnit    tmpWidth;
761     _DtCvUnit    superWidth   = 0;
762     _DtCvUnit    superY       = 0;
763     _DtCvUnit    subWidth     = 0;
764     _DtCvUnit    subY         = 0;
765     _DtCvUnit    scriptX      = 0;
766
767     _DtCvFlags   oldFlag = 0;
768     _DtCvFlags   newFlag = 0;
769
770     _DtCvValue lastWasSub   = False;
771     _DtCvValue lastWasSuper = False;
772     _DtCvValue lstLnkVis    = False;
773
774     _DtCvSegmentI       *pSeg;
775     _DtCvSegmentI       *tmpSeg;
776
777     /*
778      * determine the flags for rendering.
779      */
780     if (draw_flag)
781         newFlag = _DtCvTRAVERSAL_FLAG;
782     else
783         oldFlag = _DtCvTRAVERSAL_FLAG;
784
785     /*
786      * allow traversal to marks.
787      */
788     if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type)
789       {
790         int markIdx = canvas->trav_lst[travIdx].idx;
791         if (True == render)
792           {
793             oldFlag = oldFlag | _DtCvMARK_FLAG
794                               | _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
795             newFlag = newFlag | _DtCvMARK_FLAG
796                               | _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
797
798             if (_DtCvTRUE == canvas->marks[markIdx].on)
799               {
800                 oldFlag |= _DtCvMARK_ON;
801                 newFlag |= _DtCvMARK_ON;
802               }
803
804             _DtCvDrawAreaWithFlags(canvas,
805                                 canvas->marks[markIdx].beg,
806                                 canvas->marks[markIdx].end,
807                                 oldFlag, newFlag,
808                                 _DtCvMARK_TYPE,
809                                 canvas->marks[markIdx].client_data);
810           }
811
812         if (ret_height)
813             *ret_height = canvas->marks[markIdx].end.y -
814                 canvas->marks[markIdx].beg.y +
815                 canvas->txt_lst[canvas->marks[markIdx].end.line_idx].descent +
816                 canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
817
818         /*
819          * set some return variables
820          */
821         if (ret_x)
822             *ret_x = canvas->marks[markIdx].beg.x;
823
824         if (ret_y)
825             *ret_y = canvas->marks[markIdx].beg.y -
826                 canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
827
828         if (ret_baseline)
829             *ret_baseline = canvas->marks[markIdx].beg.y;
830
831         return;
832       }
833
834     /*
835      * get the link index
836      */
837     linkIndex = canvas->trav_lst[travIdx].seg_ptr->link_idx;
838
839     /*
840      * determine the location of the hypertext segment.
841      */
842     pSeg  = canvas->trav_lst[travIdx].seg_ptr;
843     start = canvas->txt_lst[txtLine].byte_index;
844     count = canvas->txt_lst[txtLine].length;
845
846     /*
847      * get the start of the line
848      */
849     dstX  = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
850
851     while (pSeg->link_idx != linkIndex)
852       {
853         /*
854          * get the corrected x
855          */
856         dstX = _DtCvAdvanceXOfLine (canvas, pSeg, dstX, &lstLnk, &lstLnkVis);
857
858         /*
859          * move the text x position base on if this is a super or
860          * sub script - or not.
861          */
862         dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
863                             &superWidth, &superY, &subWidth, &subY,
864                             &lastWasSuper, &lastWasSub);
865
866         /*
867          * get the width of the segment.
868          */
869         _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
870                                                     &len, &tmpWidth, NULL);
871         dstX += tmpWidth;
872
873         /*
874          * update pointers
875          */
876         lstLnk  = pSeg->link_idx;
877         count  -= len;
878         curIdx += len;
879         pSeg    = pSeg->next_disp;
880         start   = 0;
881       }
882
883     /*
884      * set some return variables
885      */
886     if (ret_x)
887         *ret_x = dstX;
888
889     if (ret_y)
890         *ret_y = canvas->txt_lst[txtLine].baseline -
891                                         canvas->txt_lst[txtLine].ascent;
892     if (ret_baseline)
893         *ret_baseline = canvas->txt_lst[txtLine].baseline;
894
895     /*
896      * start drawing the traversals
897      */
898     height = 0;
899     if (True == render)
900       {
901         while (txtLine < canvas->txt_cnt && linkIndex == pSeg->link_idx)
902           {
903             /*
904              * get the corrected x
905              */
906             dstX = _DtCvAdvanceXOfLine (canvas,pSeg, dstX, &lstLnk, &lstLnkVis);
907
908             /*
909              * move the text x position base on if this is a super or
910              * sub script - or not.
911              */
912             dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
913                                 &superWidth, &superY, &subWidth, &subY,
914                                 &lastWasSuper, &lastWasSub);
915
916             /*
917              * now count up the number of bytes to display for
918              * the traversal.
919              */
920             totCnt = count;
921             tmpSeg = pSeg;
922             count  = 0;
923             wrkChr = start;
924             while  (totCnt > 0 && tmpSeg != NULL
925                                         && tmpSeg->link_idx == linkIndex)
926               {
927                 _DtCvGetWidthOfSegment(canvas, tmpSeg, wrkChr,
928                                                 totCnt, &len, NULL, NULL);
929                 totCnt    -= len;
930                 count     += len;
931                 wrkChr     = 0;
932                 tmpSeg     = tmpSeg->next_disp;
933               }
934
935             /*
936              * set the begin flag.
937              */
938             newFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
939             oldFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
940             while (count > 0 && pSeg != NULL && pSeg->link_idx == linkIndex)
941               {
942                 /*
943                  * the original count for the traversal.
944                  */
945                 len = count;
946
947                 /*
948                  * if there is mark/selected text, determine, how much
949                  */
950                 _DtCvCheckLineMarks(canvas, txtLine, curIdx, count, dstX,
951                                         (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
952                                         &len, &oldFlag, &newFlag);
953                 /*
954                  * if this is the last segment(s) of the traversal
955                  * set the end flags.
956                  */
957                 if (len == count)
958                   {
959                     newFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
960                     oldFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
961                   }
962
963                 /*
964                  * render the segments
965                  */
966                 dstX = _DtCvDrawSegments(canvas, canvas->txt_lst[txtLine],
967                             pSeg, start, len, &lstLnk, dstX, dstX,
968                             &scriptX,&superWidth,&superY,&subWidth,&subY,
969                             &lastWasSub, &lastWasSuper,
970                             &lstLnkVis, oldFlag, newFlag,
971                             _DtCvLINK_TYPE, NULL);
972
973                 count  -= len;
974                 curIdx += len;
975                 if (count > 0)
976                   {
977                     _DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
978                                         &start, &pSeg);
979                     newFlag &= ~(_DtCvTRAVERSAL_BEGIN);
980                     oldFlag &= ~(_DtCvTRAVERSAL_BEGIN);
981                   }
982               }
983
984             height += canvas->txt_lst[txtLine].ascent
985                                 + canvas->txt_lst[txtLine].descent;
986             txtLine++;
987             if (txtLine < canvas->txt_cnt)
988               {
989                 start  = canvas->txt_lst[txtLine].byte_index;
990                 count  = canvas->txt_lst[txtLine].length;
991                 curIdx       = 0;
992                 superWidth   = 0;
993                 superY       = 0;
994                 subWidth     = 0;
995                 subY         = 0;
996                 scriptX      = 0;
997                 lstLnk       = -1;
998                 lastWasSuper = False;
999                 lastWasSub   = False;
1000                 lstLnkVis    = False;
1001
1002                 /*
1003                  * get the correct x
1004                  */
1005                 dstX = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
1006               }
1007           }
1008       }
1009
1010     if (ret_height)
1011         *ret_height = height;
1012
1013 } /* End DrawTraversalIndicator */
1014
1015 /*****************************************************************************
1016  *              Semi-Public Functions
1017  *****************************************************************************/
1018 /*****************************************************************************
1019  * Function: _DtCvGetSearchLineMetrics (
1020  *
1021  * Purpose:  gets the text line metrics for the search item.
1022  *****************************************************************************/
1023 int
1024 _DtCvGetSearchLineMetrics(_DtCvHandle handle, int idx, _DtCvUnit* baseline,
1025                                 _DtCvUnit* descent, _DtCvUnit* ascent)
1026 {
1027     int ret = 0;
1028     _DtCanvasStruct* canvas = (_DtCanvasStruct*)handle;
1029     _DtCvDspLine* line;
1030
1031     if (idx < 0 || idx >= canvas->search_cnt)
1032         return -1;
1033
1034     line = &(canvas->txt_lst[canvas->searchs[idx].idx]);
1035
1036     *baseline = line->baseline;
1037     *descent  = line->descent;
1038     *ascent   = line->ascent;
1039
1040     return ret;
1041 }
1042
1043 /*****************************************************************************
1044  * Function: _DtCvCheckInfringement (
1045  *
1046  * Purpose:  Checks to see if one object infringes vertically on another
1047  *           object.
1048  *****************************************************************************/
1049 _DtCvStatus
1050 _DtCvCheckInfringement (
1051     _DtCvUnit            tst_top,
1052     _DtCvUnit            tst_bot,
1053     _DtCvUnit            obj_top,
1054     _DtCvUnit            obj_bot)
1055 {
1056     _DtCvStatus  result = False;
1057
1058     /*
1059      * check to see if the object is to the left or right of the test
1060      * object and that it 'infringes' on the vertical space of the test
1061      * object.
1062      *
1063      * I.e.     ----obj_top------
1064      *          |               |   ----tst_top----
1065      *          ----obj_bot------   |             |
1066      *                              ----tst_bot----
1067      *
1068      * I.e.                         ----tst_top----
1069      *          ----obj_top-------  |             |
1070      *          |                |  ----tst_bot----
1071      *          ----obj_bot-------
1072      *
1073      * I.e.     ----obj_top------
1074      *          |               |   ----tst_top----
1075      *          |               |   |             |
1076      *          |               |   ----tst_bot----
1077      *          ----obj_bot------
1078      *
1079      * I.e.                         ----tst_top----
1080      *          ----obj_top-------  |             |
1081      *          |                |  |             |
1082      *          ----obj_bot-------  |             |
1083      *                              ----tst_bot----
1084      */
1085     if ((obj_top <  tst_top && tst_top <  obj_bot)
1086          || (obj_top <  tst_bot && tst_bot <  obj_bot)
1087          || (obj_top <= tst_top && tst_bot <= obj_bot)
1088          || (tst_top <  obj_top && obj_bot <  tst_bot))
1089         result = True;
1090
1091     return result;
1092 }
1093
1094 /*****************************************************************************
1095  * Function: _DtCvCheckLineMarks (
1096  *
1097  * Parameters:
1098  *              canvas          Specifies the canvas to check for
1099  *                              marks and/or selections.
1100  *              line_idx        Specifies the line index into the
1101  *                              list of text lines in the canvas.
1102  *              char_idx        Specifies the starting character index
1103  *                              in the text line.
1104  *              length          Specifies the length of the text line
1105  *                              to consider.
1106  *              dst_x           Specifies the x position of the
1107  *                              starting character in the text line.
1108  *              check_flags     Specifies which type to look for -
1109  *                              selection, marks or both.
1110  *              ret_len         Returns the length of the text line
1111  *                              starting at the starting character
1112  *                              index for which the flags returned
1113  *                              in ret_old and ret_new are valid.
1114  *              ret_old, ret_new
1115  *                              Returns the values in ret_old and ret_new
1116  *                              and may add _DtCvSELECTED_FLAG and/or
1117  *                              _DtCvMARK_FLAG.
1118  *
1119  * Purpose:     Find out how much of the line is (un)marked in some way.
1120  *****************************************************************************/
1121 void
1122 _DtCvCheckLineMarks (
1123     _DtCanvasStruct     *canvas,
1124     int                 line_idx,
1125     int                 char_idx,
1126     int                 length,
1127     _DtCvUnit           dst_x,
1128     _DtCvFlags          check_flags,
1129     int                 *ret_len,
1130     _DtCvFlags          *ret_old,
1131     _DtCvFlags          *ret_new)
1132 {
1133     int         i;
1134     _DtCvFlags  flag = 0;
1135
1136     /*
1137      * check the selection
1138      */
1139     if ((check_flags & _DtCvSELECTED_FLAG) && canvas->select_start.y != -1)
1140       {
1141         _DtCvSelectData  start = canvas->select_start;
1142         _DtCvSelectData  end   = canvas->select_end;
1143
1144         /*
1145          * check to see if we need to switch the selection points
1146          */
1147         if (start.y > end.y || (start.y == end.y && start.x > end.x))
1148           {
1149             end   = canvas->select_start;
1150             start = canvas->select_end;
1151           }
1152
1153         /*
1154          * clear the selected flag
1155          */
1156         *ret_old &= ~(_DtCvSELECTED_FLAG);
1157         *ret_new &= ~(_DtCvSELECTED_FLAG);
1158
1159         if (IsLineSpecial(start, end,
1160                                 canvas->txt_lst[line_idx], line_idx,
1161                                 char_idx, length, dst_x,
1162                                 &length, NULL))
1163           {
1164             /*
1165              * set the selected flag.
1166              */
1167             *ret_old = *ret_old | _DtCvSELECTED_FLAG;
1168             *ret_new = *ret_new | _DtCvSELECTED_FLAG;
1169           }
1170       }
1171
1172     if ((check_flags & _DtCvMARK_FLAG) && 0 < canvas->mark_cnt)
1173       {
1174         /*
1175          * strip the mark flags from the old and new flags
1176          */
1177         *ret_old &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
1178                                                 _DtCvMARK_END | _DtCvMARK_ON);
1179         *ret_new &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
1180                                                 _DtCvMARK_END | _DtCvMARK_ON);
1181
1182         /*
1183          * now add the correct flags into the old/new flags
1184          */
1185         for (i = 0; i < canvas->mark_cnt; i++)
1186           {
1187             if (IsLineSpecial(canvas->marks[i].beg, canvas->marks[i].end,
1188                                 canvas->txt_lst[line_idx], line_idx,
1189                                 char_idx, length, dst_x,
1190                                 &length, &flag))
1191               {
1192                 /*
1193                  * A false return from IsLineSpecial means that 'length'
1194                  * is outside this mark.
1195                  *
1196                  * When true, it means that some part of this mark will
1197                  * be rendered on the call. Therefore set the mark flag
1198                  * and any other flags returned and check for mark 'on'.
1199                  */
1200                 if (_DtCvTRUE == canvas->marks[i].on)
1201                     flag |= _DtCvMARK_ON;
1202
1203                 *ret_old = *ret_old | _DtCvMARK_FLAG | flag;
1204                 *ret_new = *ret_new | _DtCvMARK_FLAG | flag;
1205               }
1206           }
1207       }
1208
1209     /*
1210      * return the next length that is marked/unmarked in someway.
1211      */
1212     *ret_len = length;
1213 }
1214
1215 /******************************************************************************
1216  * Function: _DtCvSkipLineChars
1217  *
1218  * Parameters:
1219  *              canvas          Specifies the canvas on which to render
1220  *                              the text.
1221  *
1222  * Purpose: Given a length, skip ahead that number of 'characters' on
1223  *          the line.
1224  *****************************************************************************/
1225 void
1226 _DtCvSkipLineChars(
1227     _DtCanvasStruct     *canvas,
1228     _DtCvSegmentI       *p_seg,
1229     int                  start,
1230     int                  max_cnt,
1231     int                  use_len,
1232     int                 *ret_start,
1233     _DtCvSegmentI       **ret_seg)
1234 {
1235     int  len;
1236
1237     /*
1238      * not all of the traversal line was displayed because
1239      * part of it is selected. So skip what's been rendered,
1240      * and do it again.
1241      */
1242     while (use_len > 0)
1243       {
1244         /*
1245          * get the byte length of the segment processed.
1246          */
1247         _DtCvGetWidthOfSegment(canvas, p_seg, start, max_cnt, &len, NULL, NULL);
1248         /*
1249          * increment the start index by the number of total
1250          * bytes processed. If this is more that what is in
1251          * the segment, then the if stmt will catch this and
1252          * set the start index to zero.
1253          */
1254         if (len > use_len)
1255           {
1256             len    = use_len;
1257             start += len;
1258           }
1259         else /* if (len <= use_len) */
1260           {
1261             start = 0;
1262             p_seg = p_seg->next_disp;
1263           }
1264
1265         /*
1266          * reduce the total number of bytes
1267          * processed by the number in this segment.
1268          */
1269         use_len -= len;
1270         max_cnt -= len;
1271       }
1272
1273     *ret_start = start;
1274     *ret_seg   = p_seg;
1275 }
1276
1277 /******************************************************************************
1278  * Function: _DtCvClearInternalUse
1279  *
1280  * Init every internal_use pointer on containers to NULL.
1281  *****************************************************************************/
1282 void
1283 _DtCvClearInternalUse(
1284     _DtCvSegmentI       *list,
1285     _DtCvStatus          flag)
1286 {
1287     while (NULL != list)
1288       {
1289         /*
1290          * initialize the internal variables
1291          */
1292         list->internal_use = (void *) -1;
1293
1294         if (_DtCvIsSegContainer(list))
1295             _DtCvClearInternalUse(_DtCvContainerListOfSeg(list), flag);
1296
1297         list = list->next_seg;
1298       }
1299 }
1300
1301 /******************************************************************************
1302  * Function: _DtCvGetCharIdx
1303  *
1304  * Parameters:
1305  *              canvas          Specifies the canvas on which to render
1306  *                              the text.
1307  *              line            Specifies the line in the line table.
1308  *              find_x          Specifies the x position of the character.
1309  *
1310  * Returns:     ??              Returns the idx of the character.
1311  *
1312  * Purpose:
1313  *****************************************************************************/
1314 int
1315 _DtCvGetCharIdx(
1316     _DtCanvasStruct     *canvas,
1317     _DtCvDspLine         line,
1318     _DtCvUnit            find_x)
1319 {
1320     void        *pChar;
1321     _DtCvValue   done         = FALSE;
1322     _DtCvValue   lastLinkVisible = FALSE;
1323     int          count        = line.length;
1324     int          start        = line.byte_index;
1325     int          len    = -1;
1326     int          lnkInd = -1;
1327     _DtCvUnit    segWidth;
1328     _DtCvUnit    xPos;
1329     _DtCvSegmentI   *pSeg;
1330
1331     xPos = _DtCvGetStartXOfLine(&line, &pSeg);
1332
1333     /*
1334      * check to see if the start is in the middle of the line.
1335      * If so, bump the x position and start indexes to the
1336      * correct locations.
1337      */
1338     while (!done && find_x > xPos && count > 0)
1339       {
1340         xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
1341                                                 &lnkInd, &lastLinkVisible);
1342
1343         if (xPos < find_x)
1344           {
1345             /*
1346              * advance the pointer by the width
1347              */
1348             _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
1349                                                         &len, &segWidth, NULL);
1350             if (segWidth + xPos <= find_x)
1351               {
1352                 xPos  += segWidth;
1353                 pSeg   = pSeg->next_disp;
1354                 count -= len;
1355                 start  = 0;
1356               }
1357             else  /* if (xPos < find_x && find_x < xPos + segWidth) */
1358               {
1359                 if (_DtCvIsSegString(pSeg))
1360                   {
1361                     pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
1362                                         _DtCvIsSegWideChar(pSeg), start);
1363                     len   = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
1364
1365                     if (len > count)
1366                         len = count;
1367
1368                     count -= FindChar(canvas, pSeg, pChar, len,
1369                                                         find_x - xPos, NULL);
1370                   }
1371                 done = True;
1372               }
1373           }
1374
1375         len = line.length - count;
1376       }
1377
1378     return len;
1379 }
1380
1381 /*****************************************************************************
1382  * Function: _DtCvGetStartXOfLine
1383  *
1384  * Purpose: Get the starting 'x' of the specified line
1385  *          Does *not* take into account traversal or link info.
1386  *****************************************************************************/
1387 _DtCvUnit
1388 _DtCvGetStartXOfLine (
1389     _DtCvDspLine         *line,
1390     _DtCvSegmentI       **p_seg)
1391 {
1392     *p_seg = line->seg_ptr;
1393
1394     return line->text_x;
1395 }
1396
1397 /*****************************************************************************
1398  * Function: _DtCvAdvanceXOfLine
1399  *
1400  * Purpose: Move the 'x' to after the traversal and link info.
1401  *****************************************************************************/
1402 _DtCvUnit
1403 _DtCvAdvanceXOfLine (
1404     _DtCanvasStruct     *canvas,
1405     _DtCvSegmentI       *p_seg,
1406     _DtCvUnit            x_pos,
1407     int                 *link_idx,
1408     _DtCvValue          *link_flag)
1409 {
1410     _DtCvValue  junk;
1411
1412     /*
1413      * take into account the link before and after space
1414      */
1415     junk = _DtCvIsSegVisibleLink(p_seg);
1416     *link_flag = _DtCvModifyXpos (canvas->link_info, p_seg, junk,
1417                         *link_flag, *link_idx, &x_pos);
1418
1419     /*
1420      * take into account the traversal before and after space
1421      */
1422     junk = _DtCvIsSegALink(p_seg);
1423     (void) _DtCvModifyXpos (canvas->traversal_info, p_seg, junk,
1424                         ((_DtCvValue) True), *link_idx, &x_pos);
1425
1426     *link_idx = p_seg->link_idx;
1427
1428     return x_pos;
1429 }
1430
1431 /******************************************************************************
1432  * Function: _DtCvGetWidthOfSegment
1433  *
1434  *  DetermineWidthOfSegment determines the width of the segment.
1435  *  The segment must have been already initialized with the correct
1436  *  font (for strings), the spc resolve, the graphic loaded, etc.
1437  *
1438  *****************************************************************************/
1439 void
1440 _DtCvGetWidthOfSegment(
1441     _DtCanvasStruct     *canvas,
1442     _DtCvSegmentI       *p_seg,
1443     int                  start,
1444     int                  max_cnt,
1445     int                 *ret_cnt,
1446     _DtCvUnit           *ret_w,
1447     _DtCvValue          *ret_trimmed)
1448 {
1449     void        *pChar;
1450
1451     /*
1452      * return the width of the segment.
1453      */
1454     *ret_cnt = 0;
1455     if (ret_w != NULL)
1456         *ret_w = 0;
1457
1458     if (ret_trimmed != NULL)
1459         *ret_trimmed = False;
1460
1461     if (!(_DtCvIsSegNoop(p_seg)))
1462       {
1463         if (_DtCvIsSegRegion(p_seg))
1464           {
1465             *ret_cnt = 1;
1466             if (ret_w != NULL)
1467                 *ret_w = _DtCvWidthOfRegionSeg(p_seg);
1468           }
1469         else 
1470           {
1471             pChar    = _DtCvStrPtr(_DtCvStringOfStringSeg(p_seg),
1472                                         _DtCvIsSegWideChar(p_seg), start);
1473             *ret_cnt = _DtCvStrLen (pChar, _DtCvIsSegWideChar(p_seg));
1474             if (*ret_cnt > max_cnt)
1475               {
1476                 *ret_cnt = max_cnt;
1477                 if (ret_trimmed != NULL)
1478                     *ret_trimmed = True;
1479               }
1480
1481             /*
1482              * determine the width of the string.
1483              */
1484             if (ret_w != NULL)
1485                 *ret_w = _DtCvGetStringWidth(canvas, p_seg,pChar,*ret_cnt);
1486           }
1487       }
1488 }
1489
1490 /******************************************************************************
1491  * Function: _DtCvModifyXpos
1492  *****************************************************************************/
1493 _DtCvValue
1494 _DtCvModifyXpos (
1495     _DtCvSpaceMetrics    info,
1496     _DtCvSegmentI       *seg,
1497     _DtCvValue           tst_result,
1498     _DtCvValue           cur_flag,
1499     int                  last_idx,
1500     _DtCvUnit           *x)
1501 {
1502     int    addx = 0;
1503
1504     /*
1505      * take into account the link before and after space
1506      */
1507     if (tst_result)
1508       {
1509         /*
1510          * Ignore if the same link
1511          */
1512         if (last_idx != seg->link_idx)
1513           {
1514             /*
1515              * if one link followed by another add the space after.
1516              */
1517             if (last_idx != -1)
1518                 addx = info.space_after;
1519
1520             /*
1521              * add the space before the link
1522              */
1523             addx += info.space_before;
1524           }
1525         cur_flag = True;
1526       }
1527     else
1528       {
1529         if (last_idx != -1 && cur_flag == True)
1530             addx = info.space_after;
1531         cur_flag = False;
1532       }
1533
1534     *x += addx;
1535     return cur_flag;
1536 }
1537
1538 /*****************************************************************************
1539  * Function: _DtCvAdjustForSuperSub
1540  *
1541  * Parameters:
1542  *              canvas          Specifies the canvas.
1543  *              start_x         Specifies the current text x position.
1544  *              script_x        Specifies the current super and sub
1545  *                              scripting x position.  Returns the same
1546  *                              value as start_x if the segment is not a
1547  *                              super or sub script.
1548  *              super_width     Specifies the width of the previously
1549  *                              rendered super script.  Set to 0 if the
1550  *                              next segment is not a super or sub
1551  *                              script.
1552  *              super_y         Specifies the y offset for super
1553  *                              scripts.  Set to a new value if the last
1554  *                              segment was not a super or sub script.
1555  *              sub_width       Specifies the width of the previously
1556  *                              rendered sub script.  Set to 0 if the
1557  *                              next segment is not a super or sub
1558  *                              script.
1559  *              sub_y           Specifies the y offset for sub scripts.
1560  *                              Set to a new value if the last segment
1561  *                              was not a super or sub script.
1562  *              last_was_super  Specifies if the last item was a super
1563  *                              script. Set to False if the segment
1564  *                              is not a super or sub script.
1565  *              last_was_sub    Specifies if the last item was a sub
1566  *                              script. Set to False if the segment
1567  *                              is not a super or sub script.
1568  * Returns: new text x positon.
1569  *
1570  * Purpose: Determines the super and sub scripting positions for text.
1571  *          If the last item was not a script, then the base offset for
1572  *          scripting (script_x) is moved to start_x. If the current
1573  *          item is a string, its scripting y position is determined
1574  *          (super_y and sub_y).  If the new item is a super or sub
1575  *          script, the next text placement (start_x) is moved to after
1576  *          the script_x plus the super or sub script size currently
1577  *          active(super_width and sub_width).  Otherwise, the the flags
1578  *          are set to false and the widths are set to 0.
1579  *
1580  *****************************************************************************/
1581 _DtCvUnit
1582 _DtCvAdjustForSuperSub(
1583     _DtCanvasStruct     *canvas,
1584     _DtCvSegmentI       *pSeg,
1585     _DtCvUnit            start_x,
1586     _DtCvUnit           *script_x,
1587     _DtCvUnit           *super_width,
1588     _DtCvUnit           *super_y,
1589     _DtCvUnit           *sub_width,
1590     _DtCvUnit           *sub_y,
1591     _DtCvValue          *last_was_super,
1592     _DtCvValue          *last_was_sub)
1593 {
1594     /*
1595      * if the last item was not a super or sub script,
1596      * move the script x to the end of the last output.
1597      */
1598     if (!(*last_was_super || *last_was_sub))
1599         *script_x = start_x;
1600
1601     /*
1602      * check for super and sub scripts.
1603      * adjust text x positioning accordingly.
1604      */
1605     if (_DtCvIsSegSuperScript(pSeg))
1606       {
1607         start_x         = *script_x + *super_width;
1608         *last_was_super = True;
1609       }
1610     else if (_DtCvIsSegSubScript(pSeg))
1611       {
1612         start_x       = *script_x + *sub_width;
1613         *last_was_sub = True;
1614       }
1615     else if (*last_was_super || *last_was_sub)
1616       {
1617         *sub_width      = 0;
1618         *super_width    = 0;
1619         *last_was_super = False;
1620         *last_was_sub   = False;
1621       }
1622
1623     /*
1624      * if this wasn't a super or sub script, find out where
1625      * they get placed on this string.
1626      */
1627     if (!(*last_was_super || *last_was_sub))
1628       {
1629         if (_DtCvIsSegString(pSeg))
1630             _DtCvFontMetrics (canvas,_DtCvFontOfStringSeg(pSeg),
1631                                 NULL, NULL, NULL, super_y, sub_y);
1632         else if (_DtCvIsSegRegion(pSeg))
1633           {
1634             *super_y = _DtCvHeightOfRegionSeg(pSeg) * 4 / 10;
1635             *sub_y   = *super_y;
1636           }
1637       }
1638
1639     return start_x;
1640 }
1641
1642 /******************************************************************************
1643  * Function: _DtCvDrawSegments
1644  *
1645  * Parameters:
1646  *              canvas          Specifies the canvas on which to render
1647  *                              the text.
1648  *              line            Specifies the line metrics.
1649  *              p_seg           Specifies the starting segment.
1650  *              start_char      Specifies the starting index in a string
1651  *                              segment. 0 for all others.
1652  *              count           Specifies the number of characters
1653  *                              (including special characters to
1654  *                              render).
1655  *              prev_lnk        Indicates the previous link index.  Used
1656  *                              to calculate extra spacing needed for
1657  *                              traversal and link markup.
1658  *              txt_x           Specifies the starting x of the
1659  *                              segment(s).  This does *NOT* take into
1660  *                              account traversal or link spacing.  This
1661  *                              routine will do that.  This is so
1662  *                              selected links will have correct spacing
1663  *                              indicated.
1664  *              sel_x           Specifies where the selection x position
1665  *                              begins.  Usually it equals txt_x, but
1666  *                              sometimes it will be less than it to
1667  *                              indicate blank space has been selected.
1668  *              super_width     Specifies the last super script x offset.
1669  *              super_y         Specifies the last super script y offset.
1670  *              sub_width               Specifies the last sub script x offset.
1671  *              sub_y           Specifies the last sub script y offset.
1672  *              last_was_sub    Specifies if the last element was a
1673  *                              subscript.
1674  *              last_was_super  Specifies if the last element was a
1675  *                              superscript.
1676  *              last_was_vis    Specifies if the last element was a
1677  *                              visible hypertext link.
1678  *              old_flag        Specifies what the line use to look like.
1679  *              new_flag        Specifies what the line is to look like.
1680  *
1681  * Returns:     txt_x           Returns the maximum x unit processed.
1682  *
1683  * Purpose: _DtCvDrawSegments draws one or more segments based on
1684  *          the count passed in.
1685  *
1686  *          This routine adds CELink to new_flag when rendering segments
1687  *          that are hypertext links.  At the same time it will
1688  *          determine the correct window hint and may place in old_flag
1689  *          and new_flag either _DtCvLINK_POP_UP or _DtCvLINK_NEW_WINDOW.
1690  *
1691  *          This routine strips the _DtCvTRAVERSAL_END from old_flag and
1692  *          new_flag (based on what's in new_flag).  It will restore
1693  *          these flags (if specified) when it renders the last element
1694  *          in the count sequence.
1695  *
1696  *****************************************************************************/
1697 _DtCvUnit
1698 _DtCvDrawSegments(
1699     _DtCanvasStruct     *canvas,
1700     _DtCvDspLine         line,
1701     struct _dtCvSegment *p_seg,
1702     int                  start_char,
1703     int                  count,
1704     int                 *prev_lnk,
1705     _DtCvUnit            txt_x,
1706     _DtCvUnit            sel_x,
1707     _DtCvUnit           *script_x,
1708     _DtCvUnit           *super_width,
1709     _DtCvUnit           *super_y,
1710     _DtCvUnit           *sub_width,
1711     _DtCvUnit           *sub_y,
1712     _DtCvValue          *last_was_sub,
1713     _DtCvValue          *last_was_super,
1714     _DtCvValue          *last_link_vis,
1715     _DtCvFlags           old_flag,
1716     _DtCvFlags           new_flag,
1717     _DtCvElemType        trav_type,
1718     _DtCvPointer         trav_data )
1719 {
1720     int          linkType = 0;
1721     int          len;
1722     short        cropped  = _DtCvFALSE;
1723     short        image_offset = _DtCvFALSE;
1724     _DtCvUnit    segWidth;
1725     _DtCvUnit    yPos;
1726     void        *pChar;
1727     _DtCvFlags   saveEnd = new_flag &
1728         (_DtCvTRAVERSAL_END | _DtCvLINK_END | _DtCvMARK_END);
1729     _DtCvElemType   elemType;
1730     _DtCvRenderInfo posInfo;
1731     _DtCvStringInfo strInfo;
1732
1733     /*
1734      * skip any leading no-op lines
1735      */
1736     while (p_seg != NULL && _DtCvIsSegNoop(p_seg))
1737       {
1738         start_char = 0;
1739         p_seg  = p_seg->next_disp;
1740       }
1741
1742     /*
1743      * strip the any end info from the flags.
1744      * it will be put back on with the last element that makes up the count.
1745      */
1746     old_flag &= ~saveEnd;
1747     new_flag &= ~saveEnd;
1748
1749     /*
1750      * now process the segments included in 'count'
1751      */
1752     while (p_seg != NULL && count > 0)
1753       {
1754         /*
1755          * reset the baseline.
1756          * when processing super or sub scripts, this gets changed.
1757          */
1758         yPos = line.baseline;
1759
1760         /*
1761          * take into account the visible link and traversal info.
1762          */
1763         txt_x = _DtCvAdvanceXOfLine(canvas, p_seg, txt_x,
1764                                                 prev_lnk, last_link_vis);
1765
1766         /*
1767          * check for super and sub scripts.
1768          * adjust text x positioning accordingly.
1769          */
1770         txt_x = _DtCvAdjustForSuperSub(canvas, p_seg, txt_x,
1771                                         script_x, super_width, super_y,
1772                                         sub_width, sub_y,
1773                                         last_was_super, last_was_sub);
1774         if (sel_x > txt_x)
1775             sel_x = txt_x;
1776
1777         /*
1778          * set visible link indicator flags
1779          */
1780         _DtCvClearLinkFlags(old_flag);
1781         _DtCvClearLinkFlags(new_flag);
1782
1783         /*
1784          * is this a visible link?
1785          */
1786         if (_DtCvIsSegVisibleLink(p_seg))
1787           {
1788             /*
1789              * visible link - set the flags.
1790              */
1791             new_flag |= _DtCvLINK_FLAG;
1792             old_flag |= _DtCvLINK_FLAG;
1793
1794             /*
1795              * is this the start of a new link? If so, set the begin flag.
1796              */
1797             if (*prev_lnk != p_seg->link_idx)
1798               {
1799                 new_flag |= _DtCvLINK_BEGIN;
1800                 old_flag |= _DtCvLINK_BEGIN;
1801               }
1802
1803             /*
1804              * get the link type and set the window hint.
1805              */
1806             linkType  = _DtLinkDbGetLinkType(canvas->link_data,p_seg->link_idx);
1807             switch (_DtLinkDbGetHint(canvas->link_data, p_seg->link_idx))
1808               {
1809                 case _DtCvWindowHint_PopupWindow:
1810                                 new_flag |= _DtCvLINK_POP_UP;
1811                                 old_flag |= _DtCvLINK_POP_UP;
1812                                 break;
1813                 case _DtCvWindowHint_NewWindow:
1814                                 new_flag |= _DtCvLINK_NEW_WINDOW;
1815                                 old_flag |= _DtCvLINK_NEW_WINDOW;
1816                                 break;
1817               }
1818           }
1819         
1820         /*
1821          * rememeber this link index.
1822          */
1823         *prev_lnk = p_seg->link_idx;
1824
1825         /*
1826          * set the search flag
1827          */
1828         _DtCvClearSearchFlags(old_flag);
1829         _DtCvClearSearchFlags(new_flag);
1830
1831         old_flag |= (p_seg->type & _DtCvSEARCH_FLAG);
1832         new_flag |= (p_seg->type & _DtCvSEARCH_FLAG);
1833
1834         if (0 == start_char)
1835           {
1836             _DtCvSetSearchBegin(old_flag, p_seg);
1837             _DtCvSetSearchBegin(new_flag, p_seg);
1838             
1839           }
1840
1841         old_flag &= ~_DtCvAPP_FLAG2;
1842         new_flag &= ~_DtCvAPP_FLAG2;
1843         old_flag |= p_seg->type & _DtCvAPP_FLAG2;
1844         new_flag |= p_seg->type & _DtCvAPP_FLAG2;
1845
1846         old_flag &= ~(_DtCvAPP_FLAG3 | _DtCvAPP_FLAG4);
1847         new_flag &= ~(_DtCvAPP_FLAG3 | _DtCvAPP_FLAG4);
1848
1849         /*
1850          * init some variables
1851          */
1852         segWidth = 0;
1853         len      = 0;
1854
1855         /*
1856          * adjust the yPos for sub/superscripts.
1857          */
1858         if (_DtCvIsSegSuperScript(p_seg))
1859             yPos -= *super_y;
1860         else if (_DtCvIsSegSubScript(p_seg))
1861             yPos += *sub_y;
1862
1863         elemType = -1;
1864         switch (_DtCvPrimaryTypeOfSeg(p_seg))
1865           {
1866             case _DtCvSTRING:
1867                 /*
1868                  * set the type
1869                  */
1870                 elemType = _DtCvSTRING_TYPE;
1871
1872                 /*
1873                  * get the string and its length.
1874                  */
1875                 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(p_seg),
1876                                         _DtCvIsSegWideChar(p_seg), start_char);
1877                 len   = _DtCvStrLen (pChar, _DtCvIsSegWideChar(p_seg));
1878
1879                 /*
1880                  * if length of the string is longer than we want to
1881                  * output, crop.
1882                  */
1883                 if (len > count)
1884                   {
1885                     len     = count;
1886                     cropped = _DtCvTRUE;
1887                   }
1888
1889                 /*
1890                  * initialize the string structure.
1891                  */
1892                 strInfo.string   = pChar;
1893                 strInfo.byte_len = len;
1894                 strInfo.wc       = _DtCvIsSegWideChar(p_seg);
1895                 strInfo.font_ptr = _DtCvFontOfStringSeg(p_seg);
1896                 strInfo.csd      = p_seg->client_use;
1897
1898                 /*
1899                  * now get the width of the string to update the x positions
1900                  */
1901                 segWidth     = _DtCvGetStringWidth(canvas, p_seg, pChar, len);
1902
1903                 /*
1904                  * attach the string information to the position info.
1905                  */
1906                 posInfo.info = &strInfo;
1907
1908                 /*
1909                  * reset starting index.
1910                  */
1911                 start_char   = 0;
1912                 break;
1913
1914             case _DtCvREGION:
1915                 /*
1916                  * set the type, length and width
1917                  */
1918                 elemType = _DtCvREGION_TYPE;
1919                 len      = 1;
1920                 segWidth = _DtCvWidthOfRegionSeg(p_seg);
1921
1922                 /*
1923                  * attach the region information to the position info.
1924                  */
1925                 posInfo.info       = _DtCvInfoOfRegionSeg(p_seg);
1926
1927                 break;
1928           }
1929
1930         /*
1931          * do we have valid information?
1932          */
1933         if (-1 != elemType)
1934           {
1935             /*
1936              * now set up the position information
1937              */
1938             posInfo.box_x      = sel_x;
1939             posInfo.box_y      = line.baseline - line.ascent;
1940             posInfo.box_height = line.ascent + line.descent + 1;
1941             posInfo.box_width  = segWidth;
1942
1943             /*
1944              * if this is the last segment to be rendered,
1945              * restore the end flags.
1946              */
1947             if (len == count)
1948               {
1949                 new_flag |= saveEnd;
1950                 old_flag |= saveEnd;
1951
1952               }
1953
1954             /*
1955              * if the item (string) was not cropped, set the Search end
1956              * flag accordingly.
1957              */
1958             if (_DtCvFALSE == cropped)
1959               {
1960                 _DtCvSetSearchEnd(old_flag, p_seg);
1961                 _DtCvSetSearchEnd(new_flag, p_seg);
1962
1963                 if (new_flag & _DtCvSEARCH_END && new_flag & _DtCvAPP_FLAG2 &&
1964                     !(new_flag & _DtCvSELECTED_FLAG)) {
1965                     new_flag |= _DtCvAPP_FLAG4;
1966                 }
1967               }
1968
1969             if (image_offset == _DtCvTRUE) {
1970                 old_flag |= _DtCvAPP_FLAG3;
1971                 new_flag |= _DtCvAPP_FLAG3;
1972                 image_offset = _DtCvFALSE;
1973             }
1974
1975             /*
1976              * render the element
1977              */
1978             if (NULL != canvas->virt_functions.render_elem)
1979                 (*(canvas->virt_functions.render_elem))(
1980                                 canvas->client_data, elemType,
1981                                 txt_x, yPos,
1982                                 linkType, old_flag, new_flag,
1983                                 trav_type, trav_data, &posInfo);
1984
1985             if (cropped == _DtCvFALSE && new_flag & _DtCvSEARCH_END
1986                                       && new_flag & _DtCvAPP_FLAG2
1987                                       && !(new_flag & _DtCvSELECTED_FLAG))
1988                 image_offset = _DtCvTRUE;
1989           }
1990
1991         /*
1992          * strip the any begin flags.
1993          */
1994         _DtCvRemoveBeginFlags(old_flag);
1995         _DtCvRemoveBeginFlags(new_flag);
1996
1997         /*
1998          * take into account subscripting and superscripting.
1999          */
2000         if (_DtCvIsSegSuperScript(p_seg))
2001             *super_width += segWidth;
2002         else if (_DtCvIsSegSubScript(p_seg))
2003             *sub_width += segWidth;
2004
2005         /*
2006          * adjust the pointers
2007          */
2008         txt_x += segWidth;
2009         sel_x  = txt_x;
2010         count -= len;
2011
2012         p_seg = p_seg->next_disp;
2013       }
2014
2015     return txt_x;
2016
2017 } /* End _DtCvDrawSegments */
2018
2019 /*****************************************************************************
2020  *              Public Functions
2021  *****************************************************************************/
2022 /*****************************************************************************
2023  * Function:    _DtCvHandle _DtCanvasCreate (_DtCvVirtualInfo virt_info);
2024  *
2025  * Parameters:
2026  *              virt_info       Specifies the virtual functions to attach
2027  *                              to the created canvas.
2028  *
2029  * Returns:     A handle to the canvas or NULL if an error occurs.
2030  *
2031  * Purpose:     Create a canvas and attach the appropriate virtual functions
2032  *              to the canvas.
2033  *****************************************************************************/
2034 _DtCvHandle
2035 _DtCanvasCreate (
2036     _DtCvVirtualInfo    virt_info,
2037     _DtCvPointer        client_data)
2038 {
2039     _DtCanvasStruct     *newCanvas;
2040
2041     newCanvas = (_DtCanvasStruct *) malloc (sizeof (_DtCanvasStruct));
2042     if (newCanvas == NULL)
2043         return NULL;
2044
2045     *newCanvas                = DefaultCanvas;
2046     newCanvas->virt_functions = virt_info;
2047     newCanvas->client_data    = client_data;
2048     newCanvas->mb_length      = MB_CUR_MAX;
2049
2050     /*
2051      * load the metrics
2052      */
2053     _DtCanvasLoadMetrics((_DtCvHandle)newCanvas);
2054
2055     return ((_DtCvHandle)(newCanvas));
2056
2057 } /* End _DtCanvasCreate */
2058
2059 void _DtCanvasLoadMetrics(_DtCvHandle handle)
2060 {
2061     _DtCanvasStruct *canvas = (_DtCanvasStruct*)handle;
2062     (*(canvas->virt_functions.get_metrics))(canvas->client_data,
2063                                         _DtCvCANVAS_TYPE, &(canvas->metrics));
2064     (*(canvas->virt_functions.get_metrics))(canvas->client_data,
2065                                         _DtCvLINK_TYPE, &(canvas->link_info));
2066     (*(canvas->virt_functions.get_metrics))(canvas->client_data,
2067                         _DtCvTRAVERSAL_TYPE, &(canvas->traversal_info));
2068     if (MB_CUR_MAX > 1)
2069         (*(canvas->virt_functions.get_metrics))(canvas->client_data,
2070                         _DtCvLOCALE_TYPE, &(canvas->locale));
2071 }
2072
2073 /*****************************************************************************
2074  * Function:    void _DtCanvasClean (_DtCvHandle canvas_handle);
2075  *
2076  * Parameters:
2077  *              canvas          Specifies the handle for the canvas.
2078  *
2079  * Returns:     A handle to the canvas or NULL if an error occurs.
2080  *
2081  * Purpose:     Create a canvas and attach the appropriate virtual functions
2082  *              to the canvas.
2083  *****************************************************************************/
2084 void
2085 _DtCanvasClean (_DtCvHandle canvas_handle)
2086 {
2087     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
2088
2089     /*
2090      * clean the selection
2091      */
2092     _DtCanvasProcessSelection (canvas_handle, 0, 0, _DtCvSELECTION_CLEAR);
2093
2094     /*
2095      * zero the lists
2096      */
2097     canvas->txt_cnt  = 0;
2098     canvas->line_cnt = 0;
2099     canvas->mark_cnt = 0;
2100     canvas->trav_cnt = 0;
2101     canvas->search_cnt = 0;
2102     canvas->brk_cnt    = 0;
2103
2104     /*
2105      * reset some indicators
2106      */
2107     canvas->error    = 0;
2108     canvas->cur_trav = -1;
2109
2110     /*
2111      * free the internal use structures.
2112      */
2113     _DtCvClearInternalUse(canvas->element_lst, _DtCvTRUE);
2114     canvas->element_lst = NULL;
2115     canvas->link_data   = NULL;
2116
2117 } /* End _DtCanvasClean */
2118
2119 /*****************************************************************************
2120  * Function:    void _DtCanvasDestroy (_DtCvHandle canvas_handle);
2121  *
2122  * Parameters:
2123  *              canvas          Specifies the handle for the canvas.
2124  *
2125  * Returns:     A handle to the canvas or NULL if an error occurs.
2126  *
2127  * Purpose:     Create a canvas and attach the appropriate virtual functions
2128  *              to the canvas.
2129  *****************************************************************************/
2130 void
2131 _DtCanvasDestroy (_DtCvHandle canvas_handle)
2132 {
2133     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
2134
2135     _DtCanvasClean (canvas_handle);
2136
2137     if (NULL != canvas->txt_lst)
2138         free ((void *) canvas->txt_lst);
2139     if (NULL != canvas->line_lst)
2140         free ((void *) canvas->line_lst);
2141     if (NULL != canvas->trav_lst)
2142         free ((void *) canvas->trav_lst);
2143     if (NULL != canvas->marks)
2144       free ((void*) canvas->marks);
2145     if (NULL != canvas->searchs)
2146       free ((void*) canvas->searchs);
2147     if (NULL != canvas->pg_breaks)
2148       free ((void*) canvas->pg_breaks);
2149       
2150     free ((void *) canvas);
2151     return;
2152
2153 } /* End _DtCanvasDestroy */
2154
2155 /*****************************************************************************
2156  * Function:    void _DtCanvasRender (_DtCvHandle canvas_handle);
2157  *
2158  * Parameters:
2159  *              canvas          Specifies the handle for the canvas.
2160  *
2161  * Returns:     A handle to the canvas or NULL if an error occurs.
2162  *
2163  * Purpose:
2164  *
2165  *****************************************************************************/
2166 void
2167 _DtCanvasRender (
2168     _DtCvHandle          canvas_handle,
2169     _DtCvUnit            x1,
2170     _DtCvUnit            y1,
2171     _DtCvUnit            x2,
2172     _DtCvUnit            y2,
2173     _DtCvRenderType      flag,
2174     _DtCvValue           pg_break,
2175     _DtCvUnit           *max_y,
2176     _DtCvUnit           *next_y)
2177 {
2178     int                  i        = 0;
2179     _DtCvUnit            lastY    = 0;
2180     _DtCvUnit            nextY    = -1;
2181     _DtCvUnit            minY;
2182     _DtCvUnit            maxY;
2183     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
2184     _DtCvDspLine        *lines;
2185     _DtCvFlags           sideCk;
2186
2187     /*
2188      * check the list of page breaks, it may constrain y2
2189      */
2190     if (_DtCvTRUE == pg_break && 0 != canvas->brk_cnt)
2191       {
2192         i = 0;
2193         while (y1 > canvas->pg_breaks[i]) i++;
2194
2195         if (i < canvas->brk_cnt && y2 > canvas->pg_breaks[i])
2196             y2 = canvas->pg_breaks[i];
2197       }
2198
2199     /*
2200      * Draw the lines first, they may constrain y2
2201      */
2202     DrawCanvasLines (canvas, x1, y1, x2, y2, flag, &lastY, &nextY);
2203
2204     if (-1 != nextY && y2 > nextY)
2205         y2 = nextY - 1;
2206
2207     /*
2208      * clear the processed flag from all the text lines.
2209      */
2210     for (i = 0; i < canvas->txt_cnt; i++)
2211         _DtCvClearProcessed(canvas->txt_lst[i]);
2212
2213     for (lines = canvas->txt_lst, i = 0;
2214                         NULL != lines && i < canvas->txt_cnt; lines++, i++)
2215       {
2216         /*
2217          * get the minimum and maximum y of the next line
2218          */
2219         minY = lines->baseline - lines->ascent;
2220         maxY = lines->baseline + lines->descent;
2221
2222         /*
2223          * is this line on the 'page'?
2224          * Does it hang off the 'page' (and if so is it allowed)?
2225          */
2226         sideCk = _DtCvSTATUS_NONE;
2227         if (_DtCvIsNotProcessed(*lines) && maxY >= y1 && minY <= y2 &&
2228             (_DtCvRENDER_PARTIAL == flag ||
2229                 (maxY <= y2 &&
2230                 _DtCvTRUE != (sideCk = CheckAround(canvas->txt_lst, canvas->txt_cnt, i, y2)))))
2231           {
2232             (void) DrawText (canvas, lines, i, 0, 0);
2233
2234             /*
2235              * indicate that this line has been rendered.
2236              */
2237             _DtCvSetProcessed(*lines);
2238
2239             /*
2240              * if doing complete printing, get any other lines that exist
2241              * next to this one, but don't fit the [y1,y2] pair. This will
2242              * catch scrolling problems using _DtCvRENDER_COMPLETE.
2243              * 
2244              * The previous CheckAround() call will have set sideCk to
2245              * _DtCvFALSE if there are other items to the side, but these
2246              * items did not violate the maximum y.
2247              *
2248              * sideCk will be _DtCvSTATUS_NONE if there is nothing to the
2249              * side for _DtCvRENDER_COMPLETE or if flag is _DtCvRENDER_PARTIAL.
2250              */
2251             if (_DtCvFALSE == sideCk)
2252                 RenderSubSet(canvas, canvas->txt_lst, canvas->txt_cnt,
2253                                                 minY, maxY, &lastY);
2254
2255             /*
2256              * is this the maximum that we've rendered?
2257              */
2258             if (lastY < maxY)
2259                 lastY = maxY;
2260           }
2261         /*
2262          * otherwise, would this 'start' the next 'page'?
2263          *
2264          * a) the render type is _DtCvRENDER_PARTIAL but the top of the
2265          *    text(minY) is beyound y2 (and so would maxY).
2266          * b) the render type is _DtCvRENDER_COMPLETE and the line is
2267          *    split across a page boundary (maxY greater than y2).
2268          * c) the render type is _DtCvRENDER_COMPLETE and there is text
2269          *    to the side of this text and it is split across a page
2270          *    boundary (sideCk == _DtCvTRUE).
2271          */
2272         else if ((-1 == nextY || nextY > minY) &&
2273                                         (maxY > y2 || _DtCvTRUE == sideCk))
2274             nextY = minY;
2275       }
2276
2277     /*
2278      * if doing _DtCvRENDER_PARTIAL, lastY will end up larger than
2279      * actually rendered. So set it back.
2280      */
2281     if (lastY > y2)
2282         lastY = y2;
2283
2284     /*
2285      * return the values if the user asked for them.
2286      */
2287     if (NULL != max_y)
2288         *max_y = lastY;
2289
2290     if (NULL != next_y)
2291         *next_y = nextY;
2292
2293 } /* End _DtCanvasRender */
2294
2295 /*****************************************************************************
2296  * Function:    void _DtCanvasMoveTraversal ()
2297  *
2298  * Parameters:
2299  *              canvas          Specifies the handle for the canvas.
2300  *
2301  * Returns:     A handle to the canvas or NULL if an error occurs.
2302  *
2303  * Purpose:
2304  *
2305  *****************************************************************************/
2306 _DtCvStatus
2307 _DtCanvasMoveTraversal (
2308     _DtCvHandle          canvas_handle,
2309     _DtCvTraversalCmd    cmd,
2310     _DtCvValue           wrap,
2311     _DtCvValue           render,
2312     _DtCvPointer         rid,
2313     _DtCvUnit           *ret_x,
2314     _DtCvUnit           *ret_y,
2315     _DtCvUnit           *ret_baseline,
2316     _DtCvUnit           *ret_height)
2317 {
2318     int                  newIndex;
2319     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
2320
2321     if (0 == canvas->trav_cnt)
2322         return _DtCvSTATUS_NONE;
2323
2324     newIndex = canvas->cur_trav;
2325     if (-1 == newIndex)
2326         newIndex = 0;
2327
2328     switch (cmd)
2329       {
2330         case _DtCvTRAVERSAL_TOP:
2331                 newIndex = 0;
2332                 break;
2333
2334         case _DtCvTRAVERSAL_NEXT:
2335                 newIndex++;
2336                 if (newIndex >= canvas->trav_cnt)
2337                   {
2338                     newIndex--;
2339                     if (wrap == True)
2340                         newIndex = 0;
2341                   }
2342                 break;
2343
2344         case _DtCvTRAVERSAL_PREV:
2345                 newIndex--;
2346                 if (newIndex < 0)
2347                   {
2348                     newIndex = 0;
2349                     if (wrap == True)
2350                         newIndex = canvas->trav_cnt - 1;
2351                   }
2352                 break;
2353
2354         case _DtCvTRAVERSAL_BOTTOM:
2355                 newIndex = canvas->trav_cnt - 1;
2356                 break;
2357
2358         case _DtCvTRAVERSAL_ID:
2359         case _DtCvTRAVERSAL_MARK:
2360                 if (NULL != rid)
2361                   {
2362                     int          idx;
2363                     char        *lnkId;
2364                     _DtCvValue   found = False;
2365
2366                     newIndex = 0;
2367                     while (False == found && newIndex < canvas->trav_cnt)
2368                       {
2369                         if (_DtCvTRAVERSAL_ID == cmd &&
2370                             _DtCvTraversalLink ==
2371                                                 canvas->trav_lst[newIndex].type)
2372                           {
2373                             idx  = canvas->trav_lst[newIndex].seg_ptr->link_idx;
2374                             lnkId = _DtLinkDbGetLinkSpec(canvas->link_data,
2375                                                                         idx);
2376
2377                             if (_DtCvStrCaseCmpLatin1(lnkId, rid) == 0)
2378                                 found = True;
2379                           }
2380                         else if (_DtCvTRAVERSAL_MARK == cmd &&
2381                                  _DtCvTraversalMark == canvas->trav_lst[newIndex].type)
2382                           {
2383                             idx = canvas->trav_lst[newIndex].idx;
2384                             if (rid == canvas->marks[idx].client_data)
2385                                 found = True;
2386                            }
2387
2388                         if (False == found)
2389                             newIndex++;
2390                       }
2391
2392                     if (False == found)
2393                         return _DtCvSTATUS_BAD;
2394                   }
2395                 break;
2396       }
2397
2398     /*
2399      * turn off the old traversal
2400      */
2401     if (cmd == _DtCvTRAVERSAL_OFF)
2402       {
2403         if (-1 != canvas->cur_trav)
2404             DrawTraversalIndicator (canvas, render, False,
2405                                         NULL, NULL, NULL, NULL);
2406         canvas->trav_on = _DtCvFALSE;
2407       }
2408     /*
2409      * turn off the old traversal and turn on the new one.
2410      */
2411     else if (newIndex != canvas->cur_trav)
2412       {
2413         if (-1 != canvas->cur_trav)
2414             DrawTraversalIndicator (canvas, render, False,
2415                                         NULL, NULL, NULL, NULL);
2416
2417         canvas->cur_trav = newIndex;
2418         DrawTraversalIndicator (canvas, render, True,
2419                                         ret_x, ret_y, ret_baseline, ret_height);
2420         canvas->trav_on = _DtCvTRUE;
2421         return _DtCvSTATUS_OK;
2422       }
2423     /*
2424      * Other wise turn on the traversal
2425      */
2426     else if (cmd == _DtCvTRAVERSAL_ON && -1 != canvas->cur_trav)
2427       {
2428         DrawTraversalIndicator (canvas, render, True,
2429                                        ret_x, ret_y, ret_baseline, ret_height);
2430         canvas->trav_on = _DtCvTRUE;
2431         return _DtCvSTATUS_OK;
2432       }
2433
2434     return _DtCvSTATUS_NONE;
2435 }
2436
2437 /*****************************************************************************
2438  * Function:    void _DtCanvasGetPosLink (_DtCvHandle canvas_handle,
2439  *                                              _DtCvUnit x, _DtCvUnit y);
2440  *
2441  * Parameters:
2442  *              canvas          Specifies the handle for the canvas.
2443  *
2444  * Returns:     A handle to the canvas or NULL if an error occurs.
2445  *
2446  * Purpose:
2447  *
2448  *****************************************************************************/
2449 _DtCvStatus
2450 _DtCanvasGetPosLink (
2451     _DtCvHandle  canvas_handle,
2452     _DtCvUnit    x1,
2453     _DtCvUnit    y1,
2454     _DtCvUnit    x2,
2455     _DtCvUnit    y2,
2456     _DtCvLinkInfo *ret_info)
2457 {
2458     int                  travIdx;
2459     int                  line;
2460     int                  len;
2461     int                  count;
2462     int                  startChar;
2463     _DtCvUnit            topY;
2464     _DtCvUnit            botY;
2465     _DtCvUnit            startX;
2466     _DtCvUnit            endX;
2467     void                *pChar;
2468     _DtCvValue           junk;
2469     _DtCvStatus          found = _DtCvSTATUS_NONE;
2470     _DtCvSegmentI       *pSeg  = NULL;
2471     _DtCanvasStruct     *canvas   = (_DtCanvasStruct *) canvas_handle;
2472     _DtCvTraversalInfo  *lnkSegs  = canvas->trav_lst;
2473
2474     if (0 == canvas->trav_cnt)
2475         return _DtCvSTATUS_NONE;
2476
2477     botY = 0;
2478     topY = 0;
2479     line = 0;
2480     while (line < canvas->txt_cnt && _DtCvSTATUS_NONE == found)
2481       {
2482         topY   = canvas->txt_lst[line].baseline - canvas->txt_lst[line].ascent;
2483         botY   = canvas->txt_lst[line].baseline + canvas->txt_lst[line].descent;
2484         startX = canvas->txt_lst[line].text_x;
2485
2486         /*
2487          * make sure the requested link is on this line.
2488          */
2489         if (topY <= y1 && y1 <= botY && startX <= x1 &&
2490                                         x1 <= canvas->txt_lst[line].max_x)
2491           {
2492             int  lnkIndx = -1;
2493             _DtCvValue lstVisible = False;
2494
2495             count     = canvas->txt_lst[line].length;
2496             pSeg      = canvas->txt_lst[line].seg_ptr;
2497             startChar = canvas->txt_lst[line].byte_index;
2498     
2499             while (count > 0 && _DtCvSTATUS_NONE == found)
2500               {
2501                 /*
2502                  * adjust the starting position by the link space
2503                  */
2504                 junk = _DtCvIsSegVisibleLink(pSeg);
2505                 lstVisible = _DtCvModifyXpos (canvas->link_info, pSeg,
2506                             junk, lstVisible, lnkIndx, &startX);
2507                 /*
2508                  * adjust the starting position by the traversal space
2509                  */
2510                 junk = _DtCvIsSegALink(pSeg);
2511                 (void) _DtCvModifyXpos (canvas->traversal_info, pSeg,
2512                             junk, ((_DtCvValue) True), lnkIndx, &startX);
2513
2514                 lnkIndx = pSeg->link_idx;
2515
2516                 /*
2517                  * skip no-op
2518                  */
2519                 if (_DtCvIsSegNoop(pSeg))
2520                     len = 0;
2521                 /*
2522                  * check region
2523                  */
2524                 else if (_DtCvIsSegRegion(pSeg))
2525                   {
2526                     len  = 1;
2527                     endX = startX + _DtCvWidthOfRegionSeg(pSeg);
2528                   }
2529                 else
2530                   {
2531                     /*
2532                      * initialize the pointer to the string
2533                      */
2534                     pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
2535                                         _DtCvIsSegWideChar(pSeg), startChar);
2536     
2537                     /*
2538                      * get the length of the current string.
2539                      * If it is longer than the line count indicates,
2540                      * it must be wrapped to the next line. We are
2541                      * only interested in in the part of the line
2542                      * that is on the line selected.
2543                      */
2544                     len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
2545                     if (len > count)
2546                         len = count;
2547     
2548                     /*
2549                      * calculate the ending pixel postion for
2550                      * this string segment.
2551                      */
2552                     endX = startX + _DtCvGetStringWidth(canvas, pSeg,
2553                                                                 pChar, len);
2554                   }
2555     
2556                 /*
2557                  * test to see if the selected segment was this segment.
2558                  */
2559                 if (x1 >= startX && x1 < endX && x2 >= startX && x2 < endX)
2560                   {
2561                     found = _DtCvSTATUS_OK;
2562                     /*
2563                      * Find the hypertext entry.
2564                      */
2565                     travIdx = 0;
2566                     while (travIdx < canvas->trav_cnt
2567                                 && _DtCvTraversalLink == lnkSegs->type
2568                                 && lnkSegs->seg_ptr->link_idx != pSeg->link_idx)
2569                       {
2570                         lnkSegs++;
2571                         travIdx++;
2572                       }
2573                   }
2574                 else
2575                   {
2576                     /*
2577                      * go to the next segment.
2578                      */
2579                     pSeg = pSeg->next_disp;
2580     
2581                     /*
2582                      * adjust for the new begining.
2583                      */
2584                     startX    = endX;
2585                     count     = count - len;
2586                     startChar = 0;
2587                   }
2588               }
2589           }
2590         line++;
2591       }
2592
2593     /*
2594      * check to see if we found a segment and 
2595      * see if it is a hypertext segment
2596      */
2597     if (_DtCvSTATUS_OK == found)
2598       {
2599         found = _DtCvSTATUS_NONE;
2600         if (_DtCvIsSegALink(pSeg) &&
2601                 _DtLinkDbGetLinkInfo(canvas->link_data, pSeg->link_idx,
2602                                 canvas->virt_functions.exec_cmd_filter,
2603                                 canvas->client_data, ret_info) == 0)
2604           {
2605             ret_info->offset_x = x1 - startX;
2606             ret_info->offset_y = y1 - topY;
2607             found = _DtCvSTATUS_OK;
2608           }
2609       }
2610
2611     return found;
2612
2613 }  /* End _DtCanvasGetPosLink */
2614
2615 /*****************************************************************************
2616  * Function:    void _DtCanvasGetCurLink ()
2617  *
2618  * Parameters:
2619  *              canvas          Specifies the handle for the canvas.
2620  *
2621  * Returns:     A handle to the canvas or NULL if an error occurs.
2622  *
2623  * Purpose:
2624  *
2625  *****************************************************************************/
2626 _DtCvStatus
2627 _DtCanvasGetCurLink (
2628     _DtCvHandle          canvas_handle,
2629     _DtCvLinkInfo       *ret_info)
2630 {
2631     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
2632     _DtCvSegmentI       *pSeg;
2633     int                  curTrav = canvas->cur_trav;
2634
2635     /*
2636      * if there isn't any traversal entry or it is a mark, return nothing.
2637      */
2638     if (0 == canvas->trav_cnt || -1 == curTrav ||
2639                         _DtCvTraversalMark == canvas->trav_lst[curTrav].type)
2640         return _DtCvSTATUS_NONE;
2641
2642     /*
2643      * otherwise this is a hypertext link
2644      */
2645     if (NULL != ret_info &&
2646                         _DtCvTraversalLink == canvas->trav_lst[curTrav].type)
2647       {
2648         pSeg = canvas->trav_lst[curTrav].seg_ptr;
2649         if (_DtLinkDbGetLinkInfo(canvas->link_data, pSeg->link_idx,
2650                                 canvas->virt_functions.exec_cmd_filter,
2651                                 canvas->client_data, ret_info) == 0)
2652         return _DtCvSTATUS_OK;
2653       }
2654
2655     return _DtCvSTATUS_BAD;
2656 }
2657
2658 /*****************************************************************************
2659  * Function:    void _DtCanvasGetCurTraversal ()
2660  *
2661  * Parameters:
2662  *              canvas          Specifies the handle for the canvas.
2663  *
2664  * Returns:     A handle to the canvas or NULL if an error occurs.
2665  *
2666  * Purpose:
2667  *
2668  *****************************************************************************/
2669 _DtCvStatus
2670 _DtCanvasGetCurTraversal (
2671     _DtCvHandle          canvas_handle,
2672     _DtCvLinkInfo       *ret_info,
2673     _DtCvPointer        *ret_data)
2674 {
2675     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
2676     _DtCvSegmentI       *pSeg;
2677     int                  curTrav = canvas->cur_trav;
2678
2679     /*
2680      * if there isn't any traversal entry, return nothing.
2681      */
2682     if (0 == canvas->trav_cnt || -1 == curTrav)
2683         return _DtCvSTATUS_NONE;
2684
2685     /*
2686      * if this is a mark, return the client data.
2687      */
2688     if (NULL != ret_data &&
2689                         _DtCvTraversalMark == canvas->trav_lst[curTrav].type)
2690       {
2691         *ret_data = canvas->marks[canvas->trav_lst[curTrav].idx].client_data;
2692         return _DtCvSTATUS_MARK;
2693       }
2694
2695     /*
2696      * otherwise this is a hypertext link
2697      */
2698     if (NULL != ret_info &&
2699                         _DtCvTraversalLink == canvas->trav_lst[curTrav].type)
2700       {
2701         pSeg = canvas->trav_lst[curTrav].seg_ptr;
2702         if (_DtLinkDbGetLinkInfo(canvas->link_data, pSeg->link_idx,
2703                                 canvas->virt_functions.exec_cmd_filter,
2704                                 canvas->client_data, ret_info) == 0)
2705         return _DtCvSTATUS_LINK;
2706       }
2707
2708     return _DtCvSTATUS_BAD;
2709 }
2710
2711
2712 /*****************************************************************************
2713  * Function:    void _DtCanvasGetSpotInfo (_DtCvHandle canvas_handle,
2714  *                                              _DtCvUnit x, _DtCvUnit y);
2715  *
2716  * Parameters:
2717  *              canvas          Specifies the handle for the canvas.
2718  *
2719  * Returns:     _DtCvSTATUS_OK          if a segment was found at x, y.
2720  *              _DtCvSTATUS_NONE        if no segment found at that location.
2721  *
2722  * Purpose:
2723  *
2724  *****************************************************************************/
2725 _DtCvStatus
2726 _DtCanvasGetSpotInfo (
2727     _DtCvHandle    canvas_handle,
2728     _DtCvUnit      x,
2729     _DtCvUnit      y,
2730     _DtCvSegment **ret_seg,
2731     _DtCvUnit     *ret_offx,
2732     _DtCvUnit     *ret_offy,
2733     _DtCvElemType *ret_elem)
2734 {
2735     int                  line;
2736     int                  len;
2737     int                  count;
2738     int                  startChar;
2739     _DtCvUnit            topY;
2740     _DtCvUnit            botY;
2741     _DtCvUnit            startX;
2742     _DtCvUnit            endX;
2743     void                *pChar;
2744     _DtCvValue           junk;
2745     _DtCvStatus          found = _DtCvSTATUS_NONE;
2746     _DtCvSegmentI       *pSeg  = NULL;
2747     _DtCanvasStruct     *canvas   = (_DtCanvasStruct *) canvas_handle;
2748
2749     if (NULL != ret_seg)
2750         *ret_seg = NULL;
2751
2752     botY = 0;
2753     topY = 0;
2754     line = 0;
2755     while (line < canvas->txt_cnt && _DtCvSTATUS_NONE == found)
2756       {
2757         topY   = canvas->txt_lst[line].baseline - canvas->txt_lst[line].ascent;
2758         botY   = canvas->txt_lst[line].baseline + canvas->txt_lst[line].descent;
2759         startX = canvas->txt_lst[line].text_x;
2760
2761         /*
2762          * make sure the requested link is on this line.
2763          */
2764         if (topY <= y && y <= botY && startX <= x &&
2765                                         x <= canvas->txt_lst[line].max_x)
2766           {
2767             int  lnkIndx = -1;
2768             _DtCvValue lstVisible = False;
2769
2770             count     = canvas->txt_lst[line].length;
2771             pSeg      = canvas->txt_lst[line].seg_ptr;
2772             startChar = canvas->txt_lst[line].byte_index;
2773     
2774             while (count > 0 && _DtCvSTATUS_NONE == found)
2775               {
2776                 /*
2777                  * adjust the starting position by the link space
2778                  */
2779                 junk = _DtCvIsSegVisibleLink(pSeg);
2780                 lstVisible = _DtCvModifyXpos (canvas->link_info, pSeg,
2781                             junk, lstVisible, lnkIndx, &startX);
2782                 /*
2783                  * adjust the starting position by the traversal space
2784                  */
2785                 junk = _DtCvIsSegALink(pSeg);
2786                 (void) _DtCvModifyXpos (canvas->traversal_info, pSeg,
2787                             junk, ((_DtCvValue) True), lnkIndx, &startX);
2788
2789                 lnkIndx = pSeg->link_idx;
2790
2791                 /*
2792                  * skip no-op
2793                  */
2794                 if (_DtCvIsSegNoop(pSeg))
2795                     len = 0;
2796                 /*
2797                  * check region
2798                  */
2799                 else if (_DtCvIsSegRegion(pSeg))
2800                   {
2801                     len  = 1;
2802                     endX = startX + _DtCvWidthOfRegionSeg(pSeg);
2803                   }
2804                 else
2805                   {
2806                     /*
2807                      * initialize the pointer to the string
2808                      */
2809                     pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
2810                                         _DtCvIsSegWideChar(pSeg), startChar);
2811     
2812                     /*
2813                      * get the length of the current string.
2814                      * If it is longer than the line count indicates,
2815                      * it must be wrapped to the next line. We are
2816                      * only interested in in the part of the line
2817                      * that is on the line selected.
2818                      */
2819                     len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
2820                     if (len > count)
2821                         len = count;
2822     
2823                     /*
2824                      * calculate the ending pixel postion for
2825                      * this string segment.
2826                      */
2827                     endX = startX + _DtCvGetStringWidth(canvas, pSeg,
2828                                                                 pChar, len);
2829                   }
2830     
2831                 /*
2832                  * test to see if the selected segment was this segment.
2833                  */
2834                 if (x >= startX && x < endX)
2835                     found = _DtCvSTATUS_OK;
2836                 else
2837                   {
2838                     /*
2839                      * go to the next segment.
2840                      */
2841                     pSeg = pSeg->next_disp;
2842     
2843                     /*
2844                      * adjust for the new begining.
2845                      */
2846                     startX    = endX;
2847                     count     = count - len;
2848                     startChar = 0;
2849                   }
2850               }
2851           }
2852         line++;
2853       }
2854
2855     /*
2856      * check to see if we found a segment.
2857      */
2858     if (_DtCvSTATUS_OK == found)
2859       {
2860         *ret_elem = _DtCvREGION_TYPE;
2861         if (_DtCvIsSegString(pSeg))
2862             *ret_elem = _DtCvSTRING_TYPE;
2863
2864         if (NULL != ret_seg)
2865             *ret_seg  = pSeg;
2866         if (NULL != ret_offx)
2867             *ret_offx = x - startX;
2868         if (NULL != ret_offy)
2869             *ret_offy = y - topY;
2870       }
2871
2872     return found;
2873
2874 }  /* End _DtCanvasGetPosition */