6147817b23e7153083e090bb858cf3970cc36afb
[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 "VirtFuncsI.h"
65
66 #ifdef NLS16
67 #endif
68
69 /********    Private Function Declarations    ********/
70 static _DtCvUnit        DrawText(
71                                 _DtCanvasStruct *canvas,
72                                 _DtCvDspLine    *line,
73                                 int              txt_line,
74                                 _DtCvFlags       old_flag,
75                                 _DtCvFlags       new_flag );
76 /********    End Private Function Declarations    ********/
77
78 /*****************************************************************************
79  *              Private Variables
80  *****************************************************************************/
81 static  _DtCanvasStruct DefaultCanvas =
82   {
83         0,              /* int error;                  */
84         0,              /* int txt_cnt;                */
85         0,              /* int txt_max;                */
86         0,              /* int line_cnt;               */
87         0,              /* int line_max;               */
88         0,              /* int mark_cnt;               */
89         0,              /* int mark_max;               */
90         0,              /* int trav_cnt;               */
91         0,              /* int trav_max;               */
92         0,              /* int cur_trav;               */
93         0,              /* search_cnt */
94         0,              /* search_max */
95         0,              /* brk_cnt                     */
96         0,              /* brk_max                     */
97         1,              /* short mb_length;            */
98         0,              /* _DtCvUnit max_x;            */
99         0,              /* _DtCvUnit max_y;            */
100         _DtCvIGNORE_BOUNDARY,   /* _DtCvValue   constraint; */
101         _DtCvFALSE,     /* _DtCvValue   trav_on;            */
102         NULL,           /* _DtCvPointer    client_data;     */
103           {             /* CanvasMetrics metrics;           */
104             0,                  /* _DtCvUnit width;         */
105             0,                  /* _DtCvUnit height;        */
106             0,                  /* _DtCvUnit top_margin;    */
107             0,                  /* _DtCvUnit line_height;   */
108             0,                  /* _DtCvUnit horiz_pad_hint;   */
109           },
110           {             /* _DtCvSpaceMetrics link_info; */
111             0,                  /* _DtCvUnit space_before; */
112             0,                  /* _DtCvUnit space_after;  */
113             0,                  /* _DtCvUnit space_above;  */
114             0,                  /* _DtCvUnit space_below;  */
115           },
116           {             /* _DtCvSpaceMetrics traversal_info; */
117             0,                  /* _DtCvUnit space_before; */
118             0,                  /* _DtCvUnit space_after;  */
119             0,                  /* _DtCvUnit space_above;  */
120             0,                  /* _DtCvUnit space_below;  */
121           },
122           {             /* _DtCvLocale locale; */
123             _DtCvModeWrapNone,  /* _DtCvModeType  line_wrap_mode;    */
124             NULL,               /* const wchar_t *cant_begin_chars;  */
125             NULL,               /* const wchar_t *cant_end_chars;    */
126           },
127         NULL,           /* _DtCvSegment      *element_lst;   */
128         NULL,           /* _DtCvDspLine       *txt_lst;       */
129         NULL,           /* _DtCvLineSeg  *line_lst;       */
130         NULL,           /* _DtCvTraversalInfo *trav_lst;      */
131         NULL,           /* _DtCvLinkDb        link_data; */
132           {             /* CESelection select_start; */
133                 -1,             /* _DtCvUnit x;           */
134                 -1,             /* _DtCvUnit y;           */
135                 -1,             /* int  line_idx;    */
136                 -1,             /* int  char_idx;    */
137           },
138           {             /* CESelection select_end; */
139                 -1,             /* _DtCvUnit x;           */
140                 -1,             /* _DtCvUnit y;           */
141                 -1,             /* int  line_idx;    */
142                 -1,             /* int  char_idx;    */
143           },
144         NULL,           /* _DtCvMarkData        *marks; */
145         NULL,           /* searchs */
146         NULL,           /* pg_breaks */
147         NULL,           /* _DtCvVirtualInfo      virt_functions; */
148   };
149
150 /*****************************************************************************
151  *              Private Functions
152  *****************************************************************************/
153 /*****************************************************************************
154  * Function: RenderSubSet
155  *
156  * Returns:     nothing
157  * Purpose:     Render the items next to an item of text.
158  *
159  *****************************************************************************/
160 static  void
161 RenderSubSet (
162     _DtCanvasStruct     *canvas,
163     _DtCvDspLine        *lines,
164     int                  cnt,
165     _DtCvUnit            y1,
166     _DtCvUnit            y2,
167     _DtCvUnit           *last_y)
168 {
169     int         i;
170     _DtCvUnit   minY;
171     _DtCvUnit   maxY;
172
173     /*
174      * Loop through the list looking for the item(s) next to the text.
175      */
176     for (i = 0; NULL != lines && i < cnt; lines++, i++)
177       {
178         /*
179          * get the minimum and maximum y of the next line
180          */
181         minY = lines->baseline - lines->ascent;
182         maxY = lines->baseline + lines->descent;
183
184         /*
185          * has this line been reviewed yet?
186          * is this line on the 'page'?
187          * Does it hang off the 'page' (and if so is it allowed)?
188          */
189         if (_DtCvIsNotProcessed(*lines) && maxY >= y1 && maxY <= y2)
190           {
191             (void) DrawText (canvas, lines, i, 0, 0);
192
193             /*
194              * indicate that this line has been rendered.
195              */
196             _DtCvSetProcessed(*lines);
197
198             /*
199              * is this the maximum that we've rendered?
200              */
201             if (*last_y < maxY)
202                 *last_y = maxY;
203
204             /*
205              * now render anything next to this!
206              */
207             RenderSubSet(canvas, canvas->txt_lst, cnt, minY, y2, last_y);
208           }
209       }
210 }
211
212 /*****************************************************************************
213  * Function: CheckAround
214  *
215  * Returns:     _DtCvSTATUS_NONE        if no other text is to the side of
216  *                                      this text.
217  *              _DtCvFALSE              if other text is to the side, but the
218  *                                      maximum y position is not violated.
219  *              _DtCvTRUE               if other text is to the side and the
220  *                                      maximum y position is violated.
221  * Purpose:  Find if another line of text intrudes upon this line.
222  *
223  *****************************************************************************/
224 static  _DtCvStatus
225 CheckAround (
226     _DtCvDspLine        *lines,
227     int                  cnt,
228     int                  idx,
229     _DtCvUnit            y2)
230 {
231     int         i    = 0;
232     _DtCvUnit   topY = lines[idx].baseline - lines[idx].ascent;
233     _DtCvUnit   botY = lines[idx].baseline + lines[idx].descent;
234     _DtCvUnit   minY;
235     _DtCvUnit   maxY;
236     _DtCvStatus result = _DtCvSTATUS_NONE;
237
238     /*
239      * set the processed flag so that we don't test something that's
240      * already tested.
241      */
242     _DtCvSetProcessed(lines[idx]);
243
244     /*
245      * go through looking for unprocessed lines to test.
246      */
247     while (i < cnt && _DtCvTRUE != result)
248       {
249         if (_DtCvIsNotProcessed(lines[i]))
250           {
251             /*
252              * calculate the minimum and maximum y positions for the line.
253              */
254             minY = lines[i].baseline - lines[i].ascent;
255             maxY = lines[i].baseline + lines[i].descent;
256
257             /*
258              * Does this line infringe vertically on the test line?
259              */
260             if (maxY > topY && minY < botY &&
261                 _DtCvTRUE == _DtCvCheckInfringement(topY, botY, minY, maxY))
262               {
263                 /*
264                  * indicate that it is not clear to the side.
265                  */
266                 result = _DtCvFALSE;
267
268                 /*
269                  * Does it have something else infringing one it?
270                  * Or does it hang down below the test line?
271                  */
272                 if (maxY > y2 || _DtCvTRUE == CheckAround(lines, cnt, i, y2))
273                     result = _DtCvTRUE;
274               }
275           }
276
277         i++;
278       }
279
280     /*
281      * Clear that this line has be processed. Otherwise, rendering will
282      * think this has been rendered when it hasn't.
283      */
284     _DtCvClearProcessed(lines[idx]);
285
286     return result;
287 }
288
289 /*****************************************************************************
290  * Function: FindChar
291  *
292  *    FindChar calculates the char that is x pixels into the string.
293  *
294  *****************************************************************************/
295 static  int
296 FindChar (
297     _DtCanvasStruct     *canvas,
298     _DtCvSegmentI       *segment,
299     void                *string,
300     int                  max_len,
301     _DtCvUnit            x_pos,
302     _DtCvUnit           *diff)
303 {
304     int     myIndex;
305     _DtCvUnit    myDiff = 0;
306     _DtCvUnit    len;
307     _DtCvUnit    charWidth;
308     _DtCvValue triedBack    = False;
309     _DtCvValue triedForward = False;
310
311     /*
312      * get information about the font used
313      */
314     _DtCvFontMetrics(canvas, _DtCvFontOfStringSeg(segment),
315                                         NULL, NULL, &charWidth, NULL, NULL);
316
317     /*
318      * try to get close to the correct index.
319      */
320     myIndex = x_pos / charWidth;
321     if (myIndex >= max_len)
322         myIndex = max_len - 1;
323     
324     while (!triedBack || !triedForward)
325       {
326         len = _DtCvGetStringWidth(canvas, segment, string, myIndex + 1);
327
328         if (len > x_pos)
329           {
330             myDiff       = len - x_pos;
331             triedForward = True;
332             if (!triedBack && myIndex)
333                 myIndex--;
334             else
335                 triedBack = True;
336           }
337         else if (len < x_pos)
338           {
339             myDiff    = x_pos - len;
340             triedBack = True;
341             myIndex++;
342             if (myIndex >= max_len)
343               {
344                 myIndex--;
345                 triedForward = True;
346               }
347           }
348         else /* len == x_pos */
349           {
350             myIndex++;
351             triedBack    = True;
352             triedForward = True;
353             myDiff       = 0;
354           }
355       }
356
357     if (diff != NULL)
358         *diff = myDiff;
359
360     return (myIndex);
361 }
362
363 /*****************************************************************************
364  * Function: DrawCanvasLines
365  *
366  *****************************************************************************/
367 static void
368 DrawCanvasLines(
369     _DtCanvasStruct     *canvas,
370     _DtCvUnit            x1,
371     _DtCvUnit            y1,
372     _DtCvUnit            x2,
373     _DtCvUnit            y2,
374     _DtCvRenderType      flag,
375     _DtCvUnit           *ret_y,
376     _DtCvUnit           *ret_next)
377 {
378     int    i;
379     _DtCvUnit     newY2 = y2;
380     _DtCvLineSeg *pLS;
381     _DtCvLineInfo lnInfo;
382
383     /*
384      * are there any lines?
385      */
386     if (canvas->line_lst != NULL && canvas->line_cnt &&
387                                 NULL != canvas->virt_functions.render_elem)
388       {
389         /*
390          * find the maximum y of all the lines that fit in the page.
391          * do this only if the flag indicates whole lines.
392          */
393         if (_DtCvRENDER_COMPLETE == flag)
394           {
395             for (i = 0, pLS = canvas->line_lst;
396                                         i < canvas->line_cnt; i++, pLS++)
397               {
398                 /*
399                  * Does this line end off the page?
400                  */
401                 if (pLS->max_y > newY2 && pLS->pos_y < newY2)
402                     newY2 = pLS->pos_y - 1;
403               }
404           }
405
406         /*
407          * check each line to see if it is on the 'page'
408          */
409         for (i = 0, pLS = canvas->line_lst; i < canvas->line_cnt; i++, pLS++)
410           {
411             lnInfo.width = pLS->width;
412             lnInfo.data  = pLS->data;
413             lnInfo.x2    = pLS->pos_x;
414             lnInfo.y2    = pLS->pos_y;
415
416             /*
417              * horizontal or vertial line?
418              */
419             if (_DtCvLINE_HORZ == pLS->dir)
420                 lnInfo.x2 = pLS->max_x;
421             else
422                 lnInfo.y2 = pLS->max_y;
423
424             /*
425              * does it fit on the page? Take into account the rendering type.
426              */
427             if (pLS->max_y >= y1 && pLS->pos_y <= newY2
428                 && lnInfo.x2 >= x1 && pLS->pos_x <= x2
429                 && (_DtCvRENDER_PARTIAL == flag || pLS->max_y <= newY2))
430               {
431                 if (pLS->max_y > *ret_y)
432                     *ret_y = pLS->max_y;
433
434                 (*(canvas->virt_functions.render_elem))(
435                         canvas->client_data, _DtCvLINE_TYPE,
436                         pLS->pos_x, pLS->pos_y, -1, 0, 0,
437                         _DtCvBAD_TYPE, NULL, &lnInfo);
438               }
439             /*
440              * otherwise, would this start the next page?
441              * make sure this is in the horizontal space.
442              */
443             else if (lnInfo.x2 >= x1 && pLS->pos_x <= x2 && pLS->max_y > newY2
444                                 && (-1 == *ret_next || *ret_next > pLS->pos_y))
445                 *ret_next = pLS->pos_y;
446           }
447       }
448 } /* End DrawCanvasLines */
449
450 /******************************************************************************
451  * Function: DrawText
452  *
453  * Parameters:
454  *              canvas          Specifies the canvas on which to render
455  *                              the text.
456  *              line            Specifies the line in the line table.
457  *              start_x         Specifies the starting x position to use
458  *                              for selected text. If greater than the
459  *                              starting position for the segment, determine
460  *                              the closest character to 'start_x' and
461  *                              use it.
462  *              end_x           Specifies the ending x position to use
463  *                              for selected text. If -1, means display
464  *                              the entire set of segments.
465  *              old_flag        Specifies....
466  *              new_flag        Specifies....
467  *
468  * Returns:     max_x           Returns the maximum x unit processed.
469  *
470  * Purpose: DrawText draws text segments on one line in the
471  *          line table.
472  *
473  *****************************************************************************/
474 static _DtCvUnit
475 DrawText(
476     _DtCanvasStruct     *canvas,
477     _DtCvDspLine        *line,
478     int                  txt_line,
479     _DtCvFlags           old_flag,
480     _DtCvFlags           new_flag )
481 {
482     int          len;
483     int          curIdx  = 0;
484     int          lastLnk = -1;
485     int          count   = line->length;
486     int          start   = line->byte_index;
487     _DtCvUnit    xPos;
488     _DtCvUnit    superWidth = 0;
489     _DtCvUnit    superY     = 0;
490     _DtCvUnit    subWidth   = 0;
491     _DtCvUnit    subY       = 0;
492     _DtCvUnit    scriptX    = 0;
493     _DtCvValue   lastWasSuper = False;
494     _DtCvValue   lastWasSub   = False;
495     _DtCvValue   lastLnkVis   = False;
496     _DtCvSegmentI *pSeg;
497
498     xPos = _DtCvGetStartXOfLine(line, &pSeg);
499
500     /*
501      * get the corrected x for links and traversals.
502      */
503     xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos, &lastLnk, &lastLnkVis);
504
505     /*
506      * take into account the if this is a super or sub script - or not.
507      */
508     xPos = _DtCvAdjustForSuperSub(canvas, pSeg, xPos,
509                                         &scriptX, &superWidth, &superY,
510                                         &subWidth, &subY,
511                                         &lastWasSuper, &lastWasSub);
512     /*
513      * now process the line
514      */
515     while (NULL != pSeg && 0 < count)
516       {
517         len = count;
518
519         /*
520          * check for selected and marked text.
521          */
522         _DtCvCheckLineMarks(canvas, txt_line, curIdx, count, xPos,
523                                 (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
524                                 &len, &old_flag, &new_flag);
525
526         /*
527          * if this is the last segment(s) of the (un)selection
528          * set the end flags.
529          */
530         if (len == count)
531           {
532             new_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
533             old_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
534           }
535
536         /*
537          * render the segment length returned by _DtCvCheckLineMarks
538          */
539         xPos = _DtCvDrawSegments(canvas, *line, pSeg, start, len,
540                                 &lastLnk, xPos, xPos,
541                                 &scriptX, &superWidth, &superY, &subWidth,
542                                 &subY, &lastWasSub, &lastWasSuper,
543                                 &lastLnkVis, old_flag, new_flag,
544                                 _DtCvBAD_TYPE, NULL);
545         /*
546          * decrement the count by the length processed
547          */
548         count  -= len;
549         curIdx += len;
550         if (0 < count)
551                 _DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
552                                                 &start, &pSeg);
553       }
554
555     return xPos;
556
557 } /* End DrawText */
558
559 /*****************************************************************************
560  * Function: IsLineSpecial (
561  *
562  * Purpose:     Call a virtual function to draw the traversal indicator
563  *****************************************************************************/
564 static  _DtCvValue
565 IsLineSpecial (
566     _DtCvSelectData     start,
567     _DtCvSelectData     end,
568     _DtCvDspLine        line,
569     int                 line_idx,
570     int                 char_idx,
571     int                 length,
572     _DtCvUnit           dst_x,
573     int                 *ret_len,
574     _DtCvFlags          *ret_flag)
575 {
576     _DtCvUnit  maxY = line.baseline + line.descent;
577     _DtCvUnit  minY = line.baseline - line.ascent;
578     _DtCvFlags flag = 0;
579
580     /*
581      * zero out the return flag (which will be a logical OR of
582      * the mark flags.
583      */
584     if (NULL != ret_flag)
585         *ret_flag = 0;
586
587     /*
588      * initialize the return value to the given inspection length.
589      */
590     *ret_len = length;
591
592     /*
593      * is there anything to look at?
594      */
595     if (start.y == -1 || maxY < start.y || minY >= end.y)
596         return False;
597
598     /*
599      * starts the mark/selection?
600      */
601     if (line_idx == start.line_idx)
602       {
603         /*
604          * does this segment straddle the start of the mark/selection?
605          */
606         if (start.char_idx > char_idx)
607           {
608             /*
609              * draw part(or all) of the segment un-mark/selected.
610              * never return a value larger than the inspection length!
611              */
612             if (start.char_idx < char_idx + length)
613                 *ret_len = start.char_idx - char_idx;
614
615             return False;
616           }
617
618         /*
619          * does this segment start the line? Set the start flag if so.
620          */
621         if (start.char_idx == char_idx)
622             flag |= _DtCvMARK_BEGIN;
623
624         /*
625          * does this line end the mark/selection?
626          */
627         if (line_idx == end.line_idx)
628           {
629             /*
630              * does this line straddle the end?
631              */
632             if (char_idx >= end.char_idx)
633               {
634                 /*
635                  * draw this un mark/selected.
636                  * Its after the mark/selected part.
637                  */
638                 return False;
639               }
640
641             if (char_idx + length > end.char_idx)
642               {
643                 /*
644                  * draw the mark/selected part
645                  */
646                 *ret_len = end.char_idx - char_idx;
647                 flag    |= _DtCvMARK_END;
648               }
649           }
650
651         /*
652          * draw the current *ret_len as mark/selected
653          */
654       }
655
656     /*
657      * does this start the mark/selection?
658      */
659     else if (line_idx == end.line_idx)
660       {
661         /*
662          * does not start the mark/selection.
663          * does end the mark/selection.
664          */
665         if (char_idx >= end.char_idx)
666             return False;
667
668         /*
669          * straddle the end position?
670          */
671         if (char_idx + length > end.char_idx)
672           {
673             *ret_len = end.char_idx - char_idx;
674             flag    |= _DtCvMARK_END;
675           }
676         /*
677          * draw the current *ret_len as mark/selected
678          */
679       }
680
681     /*
682      * start.y != -1
683      * start.y <= maxY && minY < end.y
684      */
685     else if (minY < start.y)
686       {
687         /*
688          * straddles the start y
689          */
690         if (dst_x < start.x)
691             return False;
692
693         /*
694          * dst_x > start.x
695          */
696         if (start.y != end.y)
697           {
698             if (NULL != ret_flag)
699                 *ret_flag = flag;
700             return True;
701           }
702
703         /*
704          * dst_x >= end.x
705          */
706         if (dst_x > end.x)
707             return False;
708       }
709     /*
710      * start.y <= minY and maxY
711      * minY < end.y
712      */
713     else if (end.y <= maxY)
714       {
715         /*
716          * straddles the end y position
717          */
718         if (dst_x >= end.x)
719             return False;
720       }
721     /*
722      * start.y <= minY and maxY
723      * minY && maxY < end.y
724      */
725     if (NULL != ret_flag)
726         *ret_flag = flag;
727
728     return True;
729 }
730
731 /*****************************************************************************
732  * Function: DrawTraversalIndicator (_DtCanvasStruct *canvas, _DtCvValue flag)
733  *
734  * Purpose: (Un)draws the traversal around the currently active link.
735  *****************************************************************************/
736 static  void
737 DrawTraversalIndicator (
738     _DtCanvasStruct     *canvas,
739     _DtCvValue           render,
740     _DtCvValue           draw_flag,
741     _DtCvUnit           *ret_x,
742     _DtCvUnit           *ret_y,
743     _DtCvUnit           *ret_baseline,
744     _DtCvUnit           *ret_height)
745 {
746     int     count;
747     int     len;
748     int     start;
749     int     wrkChr;
750     int     totCnt;
751     int     travIdx = canvas->cur_trav;
752     int     curIdx = 0;
753     int     txtLine   = canvas->trav_lst[travIdx].idx;
754     int     linkIndex;
755     int     lstLnk    = -1;
756
757     _DtCvUnit    height = 0;
758     _DtCvUnit    dstX;
759     _DtCvUnit    tmpWidth;
760     _DtCvUnit    superWidth   = 0;
761     _DtCvUnit    superY       = 0;
762     _DtCvUnit    subWidth     = 0;
763     _DtCvUnit    subY         = 0;
764     _DtCvUnit    scriptX      = 0;
765
766     _DtCvFlags   oldFlag = 0;
767     _DtCvFlags   newFlag = 0;
768
769     _DtCvValue lastWasSub   = False;
770     _DtCvValue lastWasSuper = False;
771     _DtCvValue lstLnkVis    = False;
772
773     _DtCvSegmentI       *pSeg;
774     _DtCvSegmentI       *tmpSeg;
775
776     /*
777      * determine the flags for rendering.
778      */
779     if (draw_flag)
780         newFlag = _DtCvTRAVERSAL_FLAG;
781     else
782         oldFlag = _DtCvTRAVERSAL_FLAG;
783
784     /*
785      * allow traversal to marks.
786      */
787     if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type)
788       {
789         int markIdx = canvas->trav_lst[travIdx].idx;
790         if (True == render)
791           {
792             oldFlag = oldFlag | _DtCvMARK_FLAG
793                               | _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
794             newFlag = newFlag | _DtCvMARK_FLAG
795                               | _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
796
797             if (_DtCvTRUE == canvas->marks[markIdx].on)
798               {
799                 oldFlag |= _DtCvMARK_ON;
800                 newFlag |= _DtCvMARK_ON;
801               }
802
803             _DtCvDrawAreaWithFlags(canvas,
804                                 canvas->marks[markIdx].beg,
805                                 canvas->marks[markIdx].end,
806                                 oldFlag, newFlag,
807                                 _DtCvMARK_TYPE,
808                                 canvas->marks[markIdx].client_data);
809           }
810
811         if (ret_height)
812             *ret_height = canvas->marks[markIdx].end.y -
813                 canvas->marks[markIdx].beg.y +
814                 canvas->txt_lst[canvas->marks[markIdx].end.line_idx].descent +
815                 canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
816
817         /*
818          * set some return variables
819          */
820         if (ret_x)
821             *ret_x = canvas->marks[markIdx].beg.x;
822
823         if (ret_y)
824             *ret_y = canvas->marks[markIdx].beg.y -
825                 canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
826
827         if (ret_baseline)
828             *ret_baseline = canvas->marks[markIdx].beg.y;
829
830         return;
831       }
832
833     /*
834      * get the link index
835      */
836     linkIndex = canvas->trav_lst[travIdx].seg_ptr->link_idx;
837
838     /*
839      * determine the location of the hypertext segment.
840      */
841     pSeg  = canvas->trav_lst[travIdx].seg_ptr;
842     start = canvas->txt_lst[txtLine].byte_index;
843     count = canvas->txt_lst[txtLine].length;
844
845     /*
846      * get the start of the line
847      */
848     dstX  = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
849
850     while (pSeg->link_idx != linkIndex)
851       {
852         /*
853          * get the corrected x
854          */
855         dstX = _DtCvAdvanceXOfLine (canvas, pSeg, dstX, &lstLnk, &lstLnkVis);
856
857         /*
858          * move the text x position base on if this is a super or
859          * sub script - or not.
860          */
861         dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
862                             &superWidth, &superY, &subWidth, &subY,
863                             &lastWasSuper, &lastWasSub);
864
865         /*
866          * get the width of the segment.
867          */
868         _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
869                                                     &len, &tmpWidth, NULL);
870         dstX += tmpWidth;
871
872         /*
873          * update pointers
874          */
875         lstLnk  = pSeg->link_idx;
876         count  -= len;
877         curIdx += len;
878         pSeg    = pSeg->next_disp;
879         start   = 0;
880       }
881
882     /*
883      * set some return variables
884      */
885     if (ret_x)
886         *ret_x = dstX;
887
888     if (ret_y)
889         *ret_y = canvas->txt_lst[txtLine].baseline -
890                                         canvas->txt_lst[txtLine].ascent;
891     if (ret_baseline)
892         *ret_baseline = canvas->txt_lst[txtLine].baseline;
893
894     /*
895      * start drawing the traversals
896      */
897     height = 0;
898     if (True == render)
899       {
900         while (txtLine < canvas->txt_cnt && linkIndex == pSeg->link_idx)
901           {
902             /*
903              * get the corrected x
904              */
905             dstX = _DtCvAdvanceXOfLine (canvas,pSeg, dstX, &lstLnk, &lstLnkVis);
906
907             /*
908              * move the text x position base on if this is a super or
909              * sub script - or not.
910              */
911             dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
912                                 &superWidth, &superY, &subWidth, &subY,
913                                 &lastWasSuper, &lastWasSub);
914
915             /*
916              * now count up the number of bytes to display for
917              * the traversal.
918              */
919             totCnt = count;
920             tmpSeg = pSeg;
921             count  = 0;
922             wrkChr = start;
923             while  (totCnt > 0 && tmpSeg != NULL
924                                         && tmpSeg->link_idx == linkIndex)
925               {
926                 _DtCvGetWidthOfSegment(canvas, tmpSeg, wrkChr,
927                                                 totCnt, &len, NULL, NULL);
928                 totCnt    -= len;
929                 count     += len;
930                 wrkChr     = 0;
931                 tmpSeg     = tmpSeg->next_disp;
932               }
933
934             /*
935              * set the begin flag.
936              */
937             newFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
938             oldFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
939             while (count > 0 && pSeg != NULL && pSeg->link_idx == linkIndex)
940               {
941                 /*
942                  * the original count for the traversal.
943                  */
944                 len = count;
945
946                 /*
947                  * if there is mark/selected text, determine, how much
948                  */
949                 _DtCvCheckLineMarks(canvas, txtLine, curIdx, count, dstX,
950                                         (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
951                                         &len, &oldFlag, &newFlag);
952                 /*
953                  * if this is the last segment(s) of the traversal
954                  * set the end flags.
955                  */
956                 if (len == count)
957                   {
958                     newFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
959                     oldFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
960                   }
961
962                 /*
963                  * render the segments
964                  */
965                 dstX = _DtCvDrawSegments(canvas, canvas->txt_lst[txtLine],
966                             pSeg, start, len, &lstLnk, dstX, dstX,
967                             &scriptX,&superWidth,&superY,&subWidth,&subY,
968                             &lastWasSub, &lastWasSuper,
969                             &lstLnkVis, oldFlag, newFlag,
970                             _DtCvLINK_TYPE, NULL);
971
972                 count  -= len;
973                 curIdx += len;
974                 if (count > 0)
975                   {
976                     _DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
977                                         &start, &pSeg);
978                     newFlag &= ~(_DtCvTRAVERSAL_BEGIN);
979                     oldFlag &= ~(_DtCvTRAVERSAL_BEGIN);
980                   }
981               }
982
983             height += canvas->txt_lst[txtLine].ascent
984                                 + canvas->txt_lst[txtLine].descent;
985             txtLine++;
986             if (txtLine < canvas->txt_cnt)
987               {
988                 start  = canvas->txt_lst[txtLine].byte_index;
989                 count  = canvas->txt_lst[txtLine].length;
990                 curIdx       = 0;
991                 superWidth   = 0;
992                 superY       = 0;
993                 subWidth     = 0;
994                 subY         = 0;
995                 scriptX      = 0;
996                 lstLnk       = -1;
997                 lastWasSuper = False;
998                 lastWasSub   = False;
999                 lstLnkVis    = False;
1000
1001                 /*
1002                  * get the correct x
1003                  */
1004                 dstX = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
1005               }
1006           }
1007       }
1008
1009     if (ret_height)
1010         *ret_height = height;
1011
1012 } /* End DrawTraversalIndicator */
1013
1014 /*****************************************************************************
1015  *              Semi-Public Functions
1016  *****************************************************************************/
1017 /*****************************************************************************
1018  * Function: _DtCvGetSearchLineMetrics (
1019  *
1020  * Purpose:  gets the text line metrics for the search item.
1021  *****************************************************************************/
1022 int
1023 _DtCvGetSearchLineMetrics(_DtCvHandle handle, int idx, _DtCvUnit* baseline,
1024                                 _DtCvUnit* descent, _DtCvUnit* ascent)
1025 {
1026     int ret = 0;
1027     _DtCanvasStruct* canvas = (_DtCanvasStruct*)handle;
1028     _DtCvDspLine* line;
1029
1030     if (idx < 0 || idx >= canvas->search_cnt)
1031         return -1;
1032
1033     line = &(canvas->txt_lst[canvas->searchs[idx].idx]);
1034
1035     *baseline = line->baseline;
1036     *descent  = line->descent;
1037     *ascent   = line->ascent;
1038
1039     return ret;
1040 }
1041
1042 /*****************************************************************************
1043  * Function: _DtCvCheckInfringement (
1044  *
1045  * Purpose:  Checks to see if one object infringes vertically on another
1046  *           object.
1047  *****************************************************************************/
1048 _DtCvStatus
1049 _DtCvCheckInfringement (
1050     _DtCvUnit            tst_top,
1051     _DtCvUnit            tst_bot,
1052     _DtCvUnit            obj_top,
1053     _DtCvUnit            obj_bot)
1054 {
1055     _DtCvStatus  result = False;
1056
1057     /*
1058      * check to see if the object is to the left or right of the test
1059      * object and that it 'infringes' on the vertical space of the test
1060      * object.
1061      *
1062      * I.e.     ----obj_top------
1063      *          |               |   ----tst_top----
1064      *          ----obj_bot------   |             |
1065      *                              ----tst_bot----
1066      *
1067      * I.e.                         ----tst_top----
1068      *          ----obj_top-------  |             |
1069      *          |                |  ----tst_bot----
1070      *          ----obj_bot-------
1071      *
1072      * I.e.     ----obj_top------
1073      *          |               |   ----tst_top----
1074      *          |               |   |             |
1075      *          |               |   ----tst_bot----
1076      *          ----obj_bot------
1077      *
1078      * I.e.                         ----tst_top----
1079      *          ----obj_top-------  |             |
1080      *          |                |  |             |
1081      *          ----obj_bot-------  |             |
1082      *                              ----tst_bot----
1083      */
1084     if ((obj_top <  tst_top && tst_top <  obj_bot)
1085          || (obj_top <  tst_bot && tst_bot <  obj_bot)
1086          || (obj_top <= tst_top && tst_bot <= obj_bot)
1087          || (tst_top <  obj_top && obj_bot <  tst_bot))
1088         result = True;
1089
1090     return result;
1091 }
1092
1093 /*****************************************************************************
1094  * Function: _DtCvCheckLineMarks (
1095  *
1096  * Parameters:
1097  *              canvas          Specifies the canvas to check for
1098  *                              marks and/or selections.
1099  *              line_idx        Specifies the line index into the
1100  *                              list of text lines in the canvas.
1101  *              char_idx        Specifies the starting character index
1102  *                              in the text line.
1103  *              length          Specifies the length of the text line
1104  *                              to consider.
1105  *              dst_x           Specifies the x position of the
1106  *                              starting character in the text line.
1107  *              check_flags     Specifies which type to look for -
1108  *                              selection, marks or both.
1109  *              ret_len         Returns the length of the text line
1110  *                              starting at the starting character
1111  *                              index for which the flags returned
1112  *                              in ret_old and ret_new are valid.
1113  *              ret_old, ret_new
1114  *                              Returns the values in ret_old and ret_new
1115  *                              and may add _DtCvSELECTED_FLAG and/or
1116  *                              _DtCvMARK_FLAG.
1117  *
1118  * Purpose:     Find out how much of the line is (un)marked in some way.
1119  *****************************************************************************/
1120 void
1121 _DtCvCheckLineMarks (
1122     _DtCanvasStruct     *canvas,
1123     int                 line_idx,
1124     int                 char_idx,
1125     int                 length,
1126     _DtCvUnit           dst_x,
1127     _DtCvFlags          check_flags,
1128     int                 *ret_len,
1129     _DtCvFlags          *ret_old,
1130     _DtCvFlags          *ret_new)
1131 {
1132     int         i;
1133     _DtCvFlags  flag = 0;
1134
1135     /*
1136      * check the selection
1137      */
1138     if ((check_flags & _DtCvSELECTED_FLAG) && canvas->select_start.y != -1)
1139       {
1140         _DtCvSelectData  start = canvas->select_start;
1141         _DtCvSelectData  end   = canvas->select_end;
1142
1143         /*
1144          * check to see if we need to switch the selection points
1145          */
1146         if (start.y > end.y || (start.y == end.y && start.x > end.x))
1147           {
1148             end   = canvas->select_start;
1149             start = canvas->select_end;
1150           }
1151
1152         /*
1153          * clear the selected flag
1154          */
1155         *ret_old &= ~(_DtCvSELECTED_FLAG);
1156         *ret_new &= ~(_DtCvSELECTED_FLAG);
1157
1158         if (IsLineSpecial(start, end,
1159                                 canvas->txt_lst[line_idx], line_idx,
1160                                 char_idx, length, dst_x,
1161                                 &length, NULL))
1162           {
1163             /*
1164              * set the selected flag.
1165              */
1166             *ret_old = *ret_old | _DtCvSELECTED_FLAG;
1167             *ret_new = *ret_new | _DtCvSELECTED_FLAG;
1168           }
1169       }
1170
1171     if ((check_flags & _DtCvMARK_FLAG) && 0 < canvas->mark_cnt)
1172       {
1173         /*
1174          * strip the mark flags from the old and new flags
1175          */
1176         *ret_old &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
1177                                                 _DtCvMARK_END | _DtCvMARK_ON);
1178         *ret_new &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
1179                                                 _DtCvMARK_END | _DtCvMARK_ON);
1180
1181         /*
1182          * now add the correct flags into the old/new flags
1183          */
1184         for (i = 0; i < canvas->mark_cnt; i++)
1185           {
1186             if (IsLineSpecial(canvas->marks[i].beg, canvas->marks[i].end,
1187                                 canvas->txt_lst[line_idx], line_idx,
1188                                 char_idx, length, dst_x,
1189                                 &length, &flag))
1190               {
1191                 /*
1192                  * A false return from IsLineSpecial means that 'length'
1193                  * is outside this mark.
1194                  *
1195                  * When true, it means that some part of this mark will
1196                  * be rendered on the call. Therefore set the mark flag
1197                  * and any other flags returned and check for mark 'on'.
1198                  */
1199                 if (_DtCvTRUE == canvas->marks[i].on)
1200                     flag |= _DtCvMARK_ON;
1201
1202                 *ret_old = *ret_old | _DtCvMARK_FLAG | flag;
1203                 *ret_new = *ret_new | _DtCvMARK_FLAG | flag;
1204               }
1205           }
1206       }
1207
1208     /*
1209      * return the next length that is marked/unmarked in someway.
1210      */
1211     *ret_len = length;
1212 }
1213
1214 /******************************************************************************
1215  * Function: _DtCvSkipLineChars
1216  *
1217  * Parameters:
1218  *              canvas          Specifies the canvas on which to render
1219  *                              the text.
1220  *
1221  * Purpose: Given a length, skip ahead that number of 'characters' on
1222  *          the line.
1223  *****************************************************************************/
1224 void
1225 _DtCvSkipLineChars(
1226     _DtCanvasStruct     *canvas,
1227     _DtCvSegmentI       *p_seg,
1228     int                  start,
1229     int                  max_cnt,
1230     int                  use_len,
1231     int                 *ret_start,
1232     _DtCvSegmentI       **ret_seg)
1233 {
1234     int  len;
1235
1236     /*
1237      * not all of the traversal line was displayed because
1238      * part of it is selected. So skip what's been rendered,
1239      * and do it again.
1240      */
1241     while (use_len > 0)
1242       {
1243         /*
1244          * get the byte length of the segment processed.
1245          */
1246         _DtCvGetWidthOfSegment(canvas, p_seg, start, max_cnt, &len, NULL, NULL);
1247         /*
1248          * increment the start index by the number of total
1249          * bytes processed. If this is more that what is in
1250          * the segment, then the if stmt will catch this and
1251          * set the start index to zero.
1252          */
1253         if (len > use_len)
1254           {
1255             len    = use_len;
1256             start += len;
1257           }
1258         else /* if (len <= use_len) */
1259           {
1260             start = 0;
1261             p_seg = p_seg->next_disp;
1262           }
1263
1264         /*
1265          * reduce the total number of bytes
1266          * processed by the number in this segment.
1267          */
1268         use_len -= len;
1269         max_cnt -= len;
1270       }
1271
1272     *ret_start = start;
1273     *ret_seg   = p_seg;
1274 }
1275
1276 /******************************************************************************
1277  * Function: _DtCvClearInternalUse
1278  *
1279  * Init every internal_use pointer on containers to NULL.
1280  *****************************************************************************/
1281 void
1282 _DtCvClearInternalUse(
1283     _DtCvSegmentI       *list,
1284     _DtCvStatus          flag)
1285 {
1286     while (NULL != list)
1287       {
1288         /*
1289          * initialize the internal variables
1290          */
1291         list->internal_use = (void *) -1;
1292
1293         if (_DtCvIsSegContainer(list))
1294             _DtCvClearInternalUse(_DtCvContainerListOfSeg(list), flag);
1295
1296         list = list->next_seg;
1297       }
1298 }
1299
1300 /******************************************************************************
1301  * Function: _DtCvGetCharIdx
1302  *
1303  * Parameters:
1304  *              canvas          Specifies the canvas on which to render
1305  *                              the text.
1306  *              line            Specifies the line in the line table.
1307  *              find_x          Specifies the x position of the character.
1308  *
1309  * Returns:     ??              Returns the idx of the character.
1310  *
1311  * Purpose:
1312  *****************************************************************************/
1313 int
1314 _DtCvGetCharIdx(
1315     _DtCanvasStruct     *canvas,
1316     _DtCvDspLine         line,
1317     _DtCvUnit            find_x)
1318 {
1319     void        *pChar;
1320     _DtCvValue   done         = FALSE;
1321     _DtCvValue   lastLinkVisible = FALSE;
1322     int          count        = line.length;
1323     int          start        = line.byte_index;
1324     int          len    = -1;
1325     int          lnkInd = -1;
1326     _DtCvUnit    segWidth;
1327     _DtCvUnit    xPos;
1328     _DtCvSegmentI   *pSeg;
1329
1330     xPos = _DtCvGetStartXOfLine(&line, &pSeg);
1331
1332     /*
1333      * check to see if the start is in the middle of the line.
1334      * If so, bump the x position and start indexes to the
1335      * correct locations.
1336      */
1337     while (!done && find_x > xPos && count > 0)
1338       {
1339         xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
1340                                                 &lnkInd, &lastLinkVisible);
1341
1342         if (xPos < find_x)
1343           {
1344             /*
1345              * advance the pointer by the width
1346              */
1347             _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
1348                                                         &len, &segWidth, NULL);
1349             if (segWidth + xPos <= find_x)
1350               {
1351                 xPos  += segWidth;
1352                 pSeg   = pSeg->next_disp;
1353                 count -= len;
1354                 start  = 0;
1355               }
1356             else  /* if (xPos < find_x && find_x < xPos + segWidth) */
1357               {
1358                 if (_DtCvIsSegString(pSeg))
1359                   {
1360                     pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
1361                                         _DtCvIsSegWideChar(pSeg), start);
1362                     len   = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
1363
1364                     if (len > count)
1365                         len = count;
1366
1367                     count -= FindChar(canvas, pSeg, pChar, len,
1368                                                         find_x - xPos, NULL);
1369                   }
1370                 done = True;
1371               }
1372           }
1373
1374         len = line.length - count;
1375       }
1376
1377     return len;
1378 }
1379
1380 /*****************************************************************************
1381  * Function: _DtCvGetStartXOfLine
1382  *
1383  * Purpose: Get the starting 'x' of the specified line
1384  *          Does *not* take into account traversal or link info.
1385  *****************************************************************************/
1386 _DtCvUnit
1387 _DtCvGetStartXOfLine (
1388     _DtCvDspLine         *line,
1389     _DtCvSegmentI       **p_seg)
1390 {
1391     *p_seg = line->seg_ptr;
1392
1393     return line->text_x;
1394 }
1395
1396 /*****************************************************************************
1397  * Function: _DtCvAdvanceXOfLine
1398  *
1399  * Purpose: Move the 'x' to after the traversal and link info.
1400  *****************************************************************************/
1401 _DtCvUnit
1402 _DtCvAdvanceXOfLine (
1403     _DtCanvasStruct     *canvas,
1404     _DtCvSegmentI       *p_seg,
1405     _DtCvUnit            x_pos,
1406     int                 *link_idx,
1407     _DtCvValue          *link_flag)
1408 {
1409     _DtCvValue  junk;
1410
1411     /*
1412      * take into account the link before and after space
1413      */
1414     junk = _DtCvIsSegVisibleLink(p_seg);
1415     *link_flag = _DtCvModifyXpos (canvas->link_info, p_seg, junk,
1416                         *link_flag, *link_idx, &x_pos);
1417
1418     /*
1419      * take into account the traversal before and after space
1420      */
1421     junk = _DtCvIsSegALink(p_seg);
1422     (void) _DtCvModifyXpos (canvas->traversal_info, p_seg, junk,
1423                         ((_DtCvValue) True), *link_idx, &x_pos);
1424
1425     *link_idx = p_seg->link_idx;
1426
1427     return x_pos;
1428 }
1429
1430 /******************************************************************************
1431  * Function: _DtCvGetWidthOfSegment
1432  *
1433  *  DetermineWidthOfSegment determines the width of the segment.
1434  *  The segment must have been already initialized with the correct
1435  *  font (for strings), the spc resolve, the graphic loaded, etc.
1436  *
1437  *****************************************************************************/
1438 void
1439 _DtCvGetWidthOfSegment(
1440     _DtCanvasStruct     *canvas,
1441     _DtCvSegmentI       *p_seg,
1442     int                  start,
1443     int                  max_cnt,
1444     int                 *ret_cnt,
1445     _DtCvUnit           *ret_w,
1446     _DtCvValue          *ret_trimmed)
1447 {
1448     void        *pChar;
1449
1450     /*
1451      * return the width of the segment.
1452      */
1453     *ret_cnt = 0;
1454     if (ret_w != NULL)
1455         *ret_w = 0;
1456
1457     if (ret_trimmed != NULL)
1458         *ret_trimmed = False;
1459
1460     if (!(_DtCvIsSegNoop(p_seg)))
1461       {
1462         if (_DtCvIsSegRegion(p_seg))
1463           {
1464             *ret_cnt = 1;
1465             if (ret_w != NULL)
1466                 *ret_w = _DtCvWidthOfRegionSeg(p_seg);
1467           }
1468         else 
1469           {
1470             pChar    = _DtCvStrPtr(_DtCvStringOfStringSeg(p_seg),
1471                                         _DtCvIsSegWideChar(p_seg), start);
1472             *ret_cnt = _DtCvStrLen (pChar, _DtCvIsSegWideChar(p_seg));
1473             if (*ret_cnt > max_cnt)
1474               {
1475                 *ret_cnt = max_cnt;
1476                 if (ret_trimmed != NULL)
1477                     *ret_trimmed = True;
1478               }
1479
1480             /*
1481              * determine the width of the string.
1482              */
1483             if (ret_w != NULL)
1484                 *ret_w = _DtCvGetStringWidth(canvas, p_seg,pChar,*ret_cnt);
1485           }
1486       }
1487 }
1488
1489 /******************************************************************************
1490  * Function: _DtCvModifyXpos
1491  *****************************************************************************/
1492 _DtCvValue
1493 _DtCvModifyXpos (
1494     _DtCvSpaceMetrics    info,
1495     _DtCvSegmentI       *seg,
1496     _DtCvValue           tst_result,
1497     _DtCvValue           cur_flag,
1498     int                  last_idx,
1499     _DtCvUnit           *x)
1500 {
1501     int    addx = 0;
1502
1503     /*
1504      * take into account the link before and after space
1505      */
1506     if (tst_result)
1507       {
1508         /*
1509          * Ignore if the same link
1510          */
1511         if (last_idx != seg->link_idx)
1512           {
1513             /*
1514              * if one link followed by another add the space after.
1515              */
1516             if (last_idx != -1)
1517                 addx = info.space_after;
1518
1519             /*
1520              * add the space before the link
1521              */
1522             addx += info.space_before;
1523           }
1524         cur_flag = True;
1525       }
1526     else
1527       {
1528         if (last_idx != -1 && cur_flag == True)
1529             addx = info.space_after;
1530         cur_flag = False;
1531       }
1532
1533     *x += addx;
1534     return cur_flag;
1535 }
1536
1537 /*****************************************************************************
1538  * Function: _DtCvAdjustForSuperSub
1539  *
1540  * Parameters:
1541  *              canvas          Specifies the canvas.
1542  *              start_x         Specifies the current text x position.
1543  *              script_x        Specifies the current super and sub
1544  *                              scripting x position.  Returns the same
1545  *                              value as start_x if the segment is not a
1546  *                              super or sub script.
1547  *              super_width     Specifies the width of the previously
1548  *                              rendered super script.  Set to 0 if the
1549  *                              next segment is not a super or sub
1550  *                              script.
1551  *              super_y         Specifies the y offset for super
1552  *                              scripts.  Set to a new value if the last
1553  *                              segment was not a super or sub script.
1554  *              sub_width       Specifies the width of the previously
1555  *                              rendered sub script.  Set to 0 if the
1556  *                              next segment is not a super or sub
1557  *                              script.
1558  *              sub_y           Specifies the y offset for sub scripts.
1559  *                              Set to a new value if the last segment
1560  *                              was not a super or sub script.
1561  *              last_was_super  Specifies if the last item was a super
1562  *                              script. Set to False if the segment
1563  *                              is not a super or sub script.
1564  *              last_was_sub    Specifies if the last item was a sub
1565  *                              script. Set to False if the segment
1566  *                              is not a super or sub script.
1567  * Returns: new text x positon.
1568  *
1569  * Purpose: Determines the super and sub scripting positions for text.
1570  *          If the last item was not a script, then the base offset for
1571  *          scripting (script_x) is moved to start_x. If the current
1572  *          item is a string, its scripting y position is determined
1573  *          (super_y and sub_y).  If the new item is a super or sub
1574  *          script, the next text placement (start_x) is moved to after
1575  *          the script_x plus the super or sub script size currently
1576  *          active(super_width and sub_width).  Otherwise, the the flags
1577  *          are set to false and the widths are set to 0.
1578  *
1579  *****************************************************************************/
1580 _DtCvUnit
1581 _DtCvAdjustForSuperSub(
1582     _DtCanvasStruct     *canvas,
1583     _DtCvSegmentI       *pSeg,
1584     _DtCvUnit            start_x,
1585     _DtCvUnit           *script_x,
1586     _DtCvUnit           *super_width,
1587     _DtCvUnit           *super_y,
1588     _DtCvUnit           *sub_width,
1589     _DtCvUnit           *sub_y,
1590     _DtCvValue          *last_was_super,
1591     _DtCvValue          *last_was_sub)
1592 {
1593     /*
1594      * if the last item was not a super or sub script,
1595      * move the script x to the end of the last output.
1596      */
1597     if (!(*last_was_super || *last_was_sub))
1598         *script_x = start_x;
1599
1600     /*
1601      * check for super and sub scripts.
1602      * adjust text x positioning accordingly.
1603      */
1604     if (_DtCvIsSegSuperScript(pSeg))
1605       {
1606         start_x         = *script_x + *super_width;
1607         *last_was_super = True;
1608       }
1609     else if (_DtCvIsSegSubScript(pSeg))
1610       {
1611         start_x       = *script_x + *sub_width;
1612         *last_was_sub = True;
1613       }
1614     else if (*last_was_super || *last_was_sub)
1615       {
1616         *sub_width      = 0;
1617         *super_width    = 0;
1618         *last_was_super = False;
1619         *last_was_sub   = False;
1620       }
1621
1622     /*
1623      * if this wasn't a super or sub script, find out where
1624      * they get placed on this string.
1625      */
1626     if (!(*last_was_super || *last_was_sub))
1627       {
1628         if (_DtCvIsSegString(pSeg))
1629             _DtCvFontMetrics (canvas,_DtCvFontOfStringSeg(pSeg),
1630                                 NULL, NULL, NULL, super_y, sub_y);
1631         else if (_DtCvIsSegRegion(pSeg))
1632           {
1633             *super_y = _DtCvHeightOfRegionSeg(pSeg) * 4 / 10;
1634             *sub_y   = *super_y;
1635           }
1636       }
1637
1638     return start_x;
1639 }
1640
1641 /******************************************************************************
1642  * Function: _DtCvDrawSegments
1643  *
1644  * Parameters:
1645  *              canvas          Specifies the canvas on which to render
1646  *                              the text.
1647  *              line            Specifies the line metrics.
1648  *              p_seg           Specifies the starting segment.
1649  *              start_char      Specifies the starting index in a string
1650  *                              segment. 0 for all others.
1651  *              count           Specifies the number of characters
1652  *                              (including special characters to
1653  *                              render).
1654  *              prev_lnk        Indicates the previous link index.  Used
1655  *                              to calculate extra spacing needed for
1656  *                              traversal and link markup.
1657  *              txt_x           Specifies the starting x of the
1658  *                              segment(s).  This does *NOT* take into
1659  *                              account traversal or link spacing.  This
1660  *                              routine will do that.  This is so
1661  *                              selected links will have correct spacing
1662  *                              indicated.
1663  *              sel_x           Specifies where the selection x position
1664  *                              begins.  Usually it equals txt_x, but
1665  *                              sometimes it will be less than it to
1666  *                              indicate blank space has been selected.
1667  *              super_width     Specifies the last super script x offset.
1668  *              super_y         Specifies the last super script y offset.
1669  *              sub_width               Specifies the last sub script x offset.
1670  *              sub_y           Specifies the last sub script y offset.
1671  *              last_was_sub    Specifies if the last element was a
1672  *                              subscript.
1673  *              last_was_super  Specifies if the last element was a
1674  *                              superscript.
1675  *              last_was_vis    Specifies if the last element was a
1676  *                              visible hypertext link.
1677  *              old_flag        Specifies what the line use to look like.
1678  *              new_flag        Specifies what the line is to look like.
1679  *
1680  * Returns:     txt_x           Returns the maximum x unit processed.
1681  *
1682  * Purpose: _DtCvDrawSegments draws one or more segments based on
1683  *          the count passed in.
1684  *
1685  *          This routine adds CELink to new_flag when rendering segments
1686  *          that are hypertext links.  At the same time it will
1687  *          determine the correct window hint and may place in old_flag
1688  *          and new_flag either _DtCvLINK_POP_UP or _DtCvLINK_NEW_WINDOW.
1689  *
1690  *          This routine strips the _DtCvTRAVERSAL_END from old_flag and
1691  *          new_flag (based on what's in new_flag).  It will restore
1692  *          these flags (if specified) when it renders the last element
1693  *          in the count sequence.
1694  *
1695  *****************************************************************************/
1696 _DtCvUnit
1697 _DtCvDrawSegments(
1698     _DtCanvasStruct     *canvas,
1699     _DtCvDspLine         line,
1700     struct _dtCvSegment *p_seg,
1701     int                  start_char,
1702     int                  count,
1703     int                 *prev_lnk,
1704     _DtCvUnit            txt_x,
1705     _DtCvUnit            sel_x,
1706     _DtCvUnit           *script_x,
1707     _DtCvUnit           *super_width,
1708     _DtCvUnit           *super_y,
1709     _DtCvUnit           *sub_width,
1710     _DtCvUnit           *sub_y,
1711     _DtCvValue          *last_was_sub,
1712     _DtCvValue          *last_was_super,
1713     _DtCvValue          *last_link_vis,
1714     _DtCvFlags           old_flag,
1715     _DtCvFlags           new_flag,
1716     _DtCvElemType        trav_type,
1717     _DtCvPointer         trav_data )
1718 {
1719     int          linkType = 0;
1720     int          len;
1721     short        cropped  = _DtCvFALSE;
1722     short        image_offset = _DtCvFALSE;
1723     _DtCvUnit    segWidth;
1724     _DtCvUnit    yPos;
1725     _DtCvValue   junk;
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 */