Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtHelp / Selection.c
1 /* $XConsortium: Selection.c /main/22 1996/11/12 11:44:48 cde-hp $ */
2 /************************************<+>*************************************
3  ****************************************************************************
4  **
5  **   File:     Selection.c
6  **
7  **   Project:  Cde DtHelp
8  **
9  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
10  **
11  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
12  **  (c) Copyright 1993, 1994 International Business Machines Corp.
13  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
14  **  (c) Copyright 1993, 1994 Novell, Inc.
15  **
16  **
17  ****************************************************************************
18  ************************************<+>*************************************/
19
20 /*
21  * system includes
22  */
23 #include <stdlib.h>
24 #include <string.h>
25
26 /*
27  * Canvas Engine includes
28  */
29 #include "CanvasP.h"
30 #include "CanvasSegP.h"
31
32 /*
33  * private includes
34  */
35 #include "CanvasI.h"
36 #include "CvStringI.h"
37 #include "LayoutUtilI.h"
38 #include "SelectionI.h"
39
40 #ifdef NLS16
41 #endif
42
43 /********    Private Function Declarations    ********/
44 static  void    AdjustSelection (
45                         _DtCanvasStruct *canvas,
46                         _DtCvSelectData  next);
47 static  int     GetSelectedText(
48                         _DtCanvasStruct *canvas,
49                         _DtCvSelectData  start,
50                         _DtCvSelectData  end,
51                         unsigned int         mask,
52                         _DtCvPointer    *ret_data);
53 /********    End Private Function Declarations    ********/
54
55 /********    Private Defines                 ********/
56 #define GROW_SIZE       5
57 /********    End Private Defines             ********/
58
59 /********    Macros                          ********/
60 #define Equal(a,b)              (a.y == b.y && a.x == b.x)
61 #define LessThan(a,b)           ((a.y < b.y) || (a.y == b.y && a.x < b.x))
62 #define GreaterThan(a,b)        ((a.y > b.y) || (a.y == b.y && a.x > b.x))
63 #define LessThanEq(a,b)         (Equal(a,b) || LessThan(a,b))
64 #define GreaterThanEq(a,b)      (Equal(a,b) || GreaterThan(a,b))
65
66 #define InRegion(top,bot,min,max)       ((min) <= (bot) && (top) <= (max))
67
68 /********    End Macros                      ********/
69
70 /********    Private Variable Declarations    ********/
71 static  const _DtCvSelectData   defaultSelect = { -1, -1, -1, -1};
72
73 /********    End Private Variable Declarations    ********/
74
75 /******************************************************************************
76  *                             Private Functions
77  ******************************************************************************/
78 /******************************************************************************
79  * Function: StartXOfLine
80  *
81  * Purpose: Determine the start of a line, takes into consideration
82  *          the traversal and link before values. The 'x' returned is
83  *          exactly where the text/graphic is to be placed on the canvas.
84  *****************************************************************************/
85 static _DtCvUnit
86 StartXOfLine(
87     _DtCanvasStruct     *canvas,
88     _DtCvDspLine         line)
89 {
90     _DtCvValue   lastLinkVisible = FALSE;
91     int          lnkInd = -1;
92     _DtCvUnit    xPos;
93     _DtCvSegmentI   *pSeg;
94
95     xPos = _DtCvGetStartXOfLine(&line, &pSeg);
96     return (_DtCvAdvanceXOfLine( canvas, pSeg, xPos,
97                         &lnkInd, &lastLinkVisible));
98
99 } /* End StartXOfLine */
100
101 /*****************************************************************************
102  * Function: SearchForClosestLine
103  *
104  * Purpose:  Initializes the 'new' structure with information indicating
105  *           what line is closest to the target_y.
106  *              next->y         Set to target_y if no line straddles it.
107  *                              Otherwise, it will be set to the minimum
108  *                              y of all lines straddling the target_y.
109  *              next->x         Set to target_x if no line straddles
110  *                              target_y or if target_x is before the
111  *                              first line straddling target_y.
112  *              next->line_idx  Set to -1 if no line straddles target_y.
113  *                              Otherwise, set to the first line that
114  *                              straddles target_x or is the minimum x
115  *                              that is greater than target_x of all the
116  *                              lines straddling target_x.
117  *              next->char_idx  Set to -1 if no straddles target_y.
118  *                              Otherwise, set to the character that
119  *                              resides at target_x if target_x is in
120  *                              the middle of the line.  Set to zero if
121  *                              target_x is before the line, and set to
122  *                              the line count if target_x is after the
123  *                              line.
124  *
125  *****************************************************************************/
126 static  void
127 SearchForClosestLine (
128     _DtCanvasStruct     *canvas,
129     _DtCvUnit            target_x,
130     _DtCvUnit            target_y,
131     _DtCvSelectData *next)
132 {
133     int          i;
134     int          maxI;
135     _DtCvUnit    lineY;
136     _DtCvUnit    endX;
137     _DtCvUnit    begX;
138     _DtCvUnit    maxX = -1;
139     _DtCvDspLine *lines = canvas->txt_lst;
140
141     *next = defaultSelect;
142     for (i = 0; i < canvas->txt_cnt; i++)
143       {
144         /*
145          * get the maximum y of the line
146          * if it straddles the target y, process it.
147          */
148         lineY = lines[i].baseline + lines[i].descent;
149         if (_DtCvStraddlesPt(target_y,lines[i].baseline-lines[i].ascent,lineY))
150           {
151             /*
152              * Is this the minimum y of all the maximum y values of the
153              * line straddling the target y?
154              */
155             if (next->y  == -1 || next->y > lineY)
156                 next->y = lineY;
157
158             /*
159              * Get the maximum X position of the line.
160              * If this is the maximum X of all the lines straddling
161              * the target y, remember it.
162              */
163             endX = canvas->txt_lst[i].max_x;
164             if (maxX < endX && endX < target_x)
165               {
166                 maxX = endX;
167                 maxI = i;
168               }
169
170             /*
171              * Does this line straddle the x?
172              */
173             begX = StartXOfLine(canvas, lines[i]);
174             if (_DtCvStraddlesPt(target_x, begX, endX))
175               {
176                 next->line_idx = i;
177                 next->char_idx = _DtCvGetCharIdx(canvas,lines[i],target_x);
178               }
179           }
180       }
181
182     /*
183      * remember what the target x was for this line.  If the target x is
184      * less than the start of the line, then the selection process will
185      * highlight the space before the line.  If its in the middle, it
186      * will just highlight starting at the character.  If it's after the
187      * end, the rest will be cut off at the end of the line.
188      */
189     next->x = target_x;
190
191     /*
192      * If we found a line straddling the target y, but it does not
193      * straddle the target_x, check max x for the correct info.
194      */
195     if (next->line_idx == -1 && maxX > -1)
196       {
197         next->line_idx = maxI;
198         next->char_idx = lines[maxI].length;
199       }
200
201     /*
202      * didn't find a line straddling the target_y, set y.
203      */
204     if (next->y == -1)
205         next->y = target_y;
206 }
207
208 /*****************************************************************************
209  * Function: MarkLinesOutsideBoundary
210  *
211  *****************************************************************************/
212 static  void
213 MarkLinesOutsideBoundary (
214     _DtCanvasStruct     *canvas,
215     _DtCvUnit            top_y,
216     _DtCvUnit            top_x,
217     _DtCvUnit            bot_y,
218     _DtCvUnit            bot_x)
219 {
220     int       i;
221     _DtCvUnit      maxY;
222     _DtCvUnit      minY;
223     _DtCvDspLine  *lines = canvas->txt_lst;
224
225     for (i = 0; i < canvas->txt_cnt; i++)
226       {
227         maxY = lines[i].baseline + lines[i].descent;
228         minY = lines[i].baseline - lines[i].ascent;
229
230         /*
231          * is this line outside the boundary?
232          * If so, mark it so it's not processed.
233          */
234         if (maxY < top_y || minY > bot_y )
235             _DtCvSetProcessed(lines[i]);
236
237         else
238           {
239             /*
240              * does it straddle the top?
241              */
242             if (_DtCvStraddlesPt(top_y, minY, maxY))
243               {
244                 /*
245                  * Does it begin before the selection?
246                  * If so, mark it so it's not processed.
247                  */
248                 if (canvas->txt_lst[i].max_x <= top_x)
249                     _DtCvSetProcessed(lines[i]);
250               }
251         
252             /*
253              * does it straddle the bottom?
254              */
255             if (_DtCvStraddlesPt(bot_y, minY, maxY))
256               {
257                 /*
258                  * Does it start after the selection?
259                  * If so, mark it so it's not processed.
260                  */
261                 if (StartXOfLine(canvas, lines[i]) >= bot_x)
262                     _DtCvSetProcessed(lines[i]);
263               }
264           }
265       }
266 }
267
268 /*****************************************************************************
269  * Function: AdjustSelection
270  *
271  *****************************************************************************/
272 static  void
273 AdjustSelection (
274     _DtCanvasStruct     *canvas,
275     _DtCvSelectData next)
276 {
277     _DtCvSelectData  start = canvas->select_start;
278     _DtCvSelectData  end   = canvas->select_end;
279
280     if (!(Equal(next, end)))
281       {
282         if (next.line_idx != -1 && next.line_idx == canvas->select_end.line_idx
283                 &&
284             next.char_idx != -1 && next.char_idx == canvas->select_end.char_idx)
285             return;
286
287         if (GreaterThan(next, end))
288           {
289             if (LessThanEq(start, end))
290                 _DtCvDrawAreaWithFlags (canvas, end, next,
291                                                 0, _DtCvSELECTED_FLAG,
292                                                 _DtCvBAD_TYPE, NULL);
293
294             else if (GreaterThanEq(start, next))
295                 _DtCvDrawAreaWithFlags (canvas, end, next,
296                                                 _DtCvSELECTED_FLAG, 0,
297                                                 _DtCvBAD_TYPE, NULL);
298
299             else /* end < start < next */
300               {
301                 _DtCvDrawAreaWithFlags (canvas, end  , start,
302                                                 _DtCvSELECTED_FLAG, 0,
303                                                 _DtCvBAD_TYPE, NULL);
304                 _DtCvDrawAreaWithFlags (canvas, start, next ,
305                                                 0, _DtCvSELECTED_FLAG,
306                                                 _DtCvBAD_TYPE, NULL);
307               }
308           }
309         else /* if (next < end) */
310           {
311             if (LessThanEq(start, next))
312                 _DtCvDrawAreaWithFlags (canvas, next, end,
313                                                 _DtCvSELECTED_FLAG, 0,
314                                                 _DtCvBAD_TYPE, NULL);
315
316             else if (GreaterThanEq(start, end))
317                 _DtCvDrawAreaWithFlags (canvas, next, end,
318                                                 0, _DtCvSELECTED_FLAG,
319                                                 _DtCvBAD_TYPE, NULL);
320
321             else /* next < start < end */
322               {
323                 _DtCvDrawAreaWithFlags (canvas, start, end  ,
324                                                 _DtCvSELECTED_FLAG, 0,
325                                                 _DtCvBAD_TYPE, NULL);
326                 _DtCvDrawAreaWithFlags (canvas, next , start,
327                                                 0, _DtCvSELECTED_FLAG,
328                                                 _DtCvBAD_TYPE, NULL);
329               }
330           }
331       }
332
333     canvas->select_end = next;
334 }
335
336 /*****************************************************************************
337  * Function: SkipOtherLines
338  *
339  *****************************************************************************/
340 static void
341 SkipOtherLines(
342     _DtCvDspLine *lines,
343     int          max_cnt,
344     int          idx,
345     _DtCvUnit    target_y,
346     int         *ret_idx)
347 {
348     while (idx < max_cnt && _DtCvIsNotProcessed(lines[idx]) &&
349                         lines[idx].baseline - lines[idx].ascent > target_y)
350         idx++;
351
352     *ret_idx = idx;
353 }
354
355 /*****************************************************************************
356  * Function: CheckAndSwitchPoints
357  *
358  *****************************************************************************/
359 static int
360 CheckAndSwitchPoints(
361     _DtCvSelectData *pt1,
362     _DtCvSelectData *pt2)
363 {
364     _DtCvSelectData temp;
365
366     if (pt1->y > pt2->y || (pt1->y == pt2->y && pt1->x >  pt2->x))
367       {
368         temp = *pt2;
369         *pt2 = *pt1;
370         *pt1 = temp;
371       }
372 }
373
374 /*****************************************************************************
375  * Function: AddSegmentToData
376  *
377  *****************************************************************************/
378 static _DtCvUnit
379 AddSegmentToData(
380     _DtCanvasStruct     *canvas,
381     unsigned int         mask,
382     _DtCvUnit            start_x,
383     int                  line_idx,
384     int                  char_idx,
385     int                  copy_cnt,
386     _DtCvFlags           end_flag,
387     _DtCvUnit           *ret_y,
388     _DtCvPointer        *ret_data)
389 {
390     _DtCvDspLine line   = canvas->txt_lst[line_idx];
391     int          result = _DtCvSTATUS_OK;
392     int          count  = line.length;
393     int          start  = line.byte_index;
394     int          lnkInd = -1;
395     int          cnt;
396     int          len;
397     _DtCvUnit    segWidth;
398     _DtCvUnit    xPos  = line.text_x;
399     void        *pChar;
400     _DtCvSegmentI       *pSeg  = line.seg_ptr;
401     _DtCvFlags   flag  = 0;
402     _DtCvValue   done  = False;
403     _DtCvValue   lastLinkVisible = FALSE;
404     _DtCvStringInfo strInfo;
405
406     xPos = _DtCvGetStartXOfLine(&line, &pSeg);
407
408     while (done == False && char_idx)
409       {
410         /*
411          * advance past the link and traversal info
412          */
413         xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
414                                 &lnkInd, &lastLinkVisible);
415
416         /*
417          * advance the pointer by the width
418          */
419         _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
420                                                         &cnt, &segWidth, NULL);
421         if (cnt < char_idx)
422           {
423             xPos     += segWidth;
424             pSeg      = pSeg->next_disp;
425             count    -= cnt;
426             char_idx -= cnt;
427             start     = 0;
428           }
429         else 
430           {
431             _DtCvGetWidthOfSegment(canvas, pSeg, start, char_idx,
432                                                         &cnt, &segWidth, NULL);
433             xPos  += segWidth;
434             start += cnt;
435             count -= cnt;
436             done = True;
437           }
438       }
439
440     if (start_x > xPos)
441         start_x = xPos;
442
443     while (_DtCvSTATUS_OK == result && pSeg != NULL && copy_cnt > 0)
444       {
445         /*
446          * advance past the link and traversal info
447          */
448         xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
449                                 &lnkInd, &lastLinkVisible);
450
451         switch (_DtCvPrimaryTypeOfSeg(pSeg))
452           {
453             case _DtCvSTRING:
454
455                 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
456                                         _DtCvIsSegWideChar(pSeg), start);
457                 len   = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
458
459                 if (len > copy_cnt)
460                     len = copy_cnt;
461
462                 segWidth = _DtCvGetStringWidth(canvas, pSeg, pChar, len);
463                 if (copy_cnt == len)
464                     flag = end_flag;
465
466                 strInfo.string   = pChar;
467                 strInfo.byte_len = len;
468                 strInfo.wc       = _DtCvIsSegWideChar(pSeg);
469                 strInfo.font_ptr = _DtCvFontOfStringSeg(pSeg);
470
471                 if (canvas->virt_functions.build_selection != NULL)
472                     result = (*(canvas->virt_functions.build_selection))(
473                                 canvas->client_data,
474                                 _DtCvSTRING_TYPE,
475                                 mask,
476                                 ret_data,
477                                 xPos - start_x,
478                                 segWidth,
479                                 flag,
480                                 (_DtCvPointer) &strInfo);
481
482                 if (_DtCvSTATUS_OK == result)
483                   {
484                     if (line.baseline + line.descent > *ret_y)
485                     *ret_y  = line.baseline + line.descent;
486                     start_x = xPos + segWidth;
487                   }
488                 else if (_DtCvSTATUS_NONE == result)
489                     result = _DtCvSTATUS_OK;
490
491                 xPos     += segWidth;
492                 copy_cnt -= len;
493                 start     = 0;
494                 break;
495
496             case _DtCvREGION:
497                 if (copy_cnt == 1)
498                     flag = end_flag;
499
500                 if (canvas->virt_functions.build_selection != NULL)
501                     result = (*(canvas->virt_functions.build_selection))(
502                                 canvas->client_data,
503                                 _DtCvREGION_TYPE,
504                                 mask,
505                                 ret_data,
506                                 xPos - start_x,
507                                 _DtCvWidthOfRegionSeg(pSeg),
508                                 flag,
509                                 _DtCvInfoOfRegionSeg(pSeg));
510
511                 if (_DtCvSTATUS_OK == result)
512                   {
513                     if (line.baseline + line.descent > *ret_y)
514                     *ret_y = line.baseline + line.descent;
515                     start_x = xPos + segWidth;
516                   }
517                 else if (_DtCvSTATUS_NONE == result)
518                     result = _DtCvSTATUS_OK;
519
520                 copy_cnt--;
521                 xPos    += _DtCvWidthOfRegionSeg(pSeg);
522                 break;
523           }
524         pSeg = pSeg->next_disp;
525       }
526
527     if (result != _DtCvSTATUS_OK)
528         return -1;
529
530     return start_x;
531 }
532
533 /*****************************************************************************
534  * Function: BuildLine
535  *
536  *****************************************************************************/
537 static int
538 BuildLine(
539     _DtCanvasStruct     *canvas,
540     unsigned int         mask,
541     _DtCvUnit            prev_y,
542     _DtCvUnit            target_x,
543     int                  line_idx,
544     int                  char_idx,
545     int                  copy_cnt,
546     _DtCvFlags           end_flag,
547     _DtCvUnit           *ret_x,
548     _DtCvUnit           *ret_y,
549     _DtCvPointer        *ret_data)
550 {
551     _DtCvUnit            topY;
552     _DtCvUnit            lastY;
553     _DtCvDspLine        *lines = canvas->txt_lst;
554     _DtCvStringInfo      strInfo = { NULL, 0, 1, NULL };
555
556     topY = lines[line_idx].baseline - lines[line_idx].ascent;
557     if (topY > prev_y && canvas->virt_functions.build_selection != NULL)
558       {
559         int   newLines;
560         _DtCvUnit  lineSize = canvas->metrics.line_height / 2;
561         if (lineSize < 1)
562             lineSize = 1;
563
564         newLines = (topY - prev_y) / lineSize;
565         while (newLines > 0)
566           {
567             newLines--;
568             if ((*(canvas->virt_functions.build_selection))(
569                                 canvas->client_data, _DtCvSTRING_TYPE,
570                                 mask, ret_data, 0, 0, _DtCvEND_OF_LINE,
571                                 (_DtCvPointer) &strInfo) != _DtCvSTATUS_OK)
572                 return -1;
573           }
574       }
575
576     *ret_y = 0;
577     *ret_x = AddSegmentToData (canvas, mask, target_x, line_idx, char_idx,
578                                         copy_cnt, end_flag, ret_y, ret_data);
579     _DtCvSetProcessed(lines[line_idx]);
580
581     if (*ret_x == -1)
582         return -1;
583     return 0;
584 }
585
586 /*****************************************************************************
587  * Function: FindMinX
588  *
589  *****************************************************************************/
590 static  int
591 FindMinX (
592     _DtCvDspLine *lines,
593     int          txt_cnt,
594     _DtCvUnit    target_y,
595     int         *ret_line)
596 {
597     int   i;
598     int   cnt    = 0;
599     _DtCvUnit  curMin = -1;
600     _DtCvUnit  curX;
601
602     for (i = 0; i < txt_cnt; i++)
603       {
604         if (_DtCvIsNotProcessed(lines[i]))
605           {
606             if (lines[i].baseline - lines[i].ascent < target_y &&
607                         target_y <= lines[i].baseline + lines[i].descent)
608               {
609                 cnt++;
610                 curX = lines[i].text_x;
611
612                 if (curMin == -1 || curMin > curX)
613                   {
614                     curMin    = curX;
615                     *ret_line = i;
616                   }
617               }
618           }
619       }
620     return cnt;
621 }
622
623 /*****************************************************************************
624  * Function: FindNextMinY
625  *
626  *****************************************************************************/
627 static _DtCvValue
628 FindNextMinY(
629     _DtCvDspLine *lines,
630     int          max_cnt,
631     _DtCvUnit    target_y,
632     _DtCvUnit   *ret_y)
633 {
634     int         i     = 0;
635     _DtCvUnit   maxY;
636     _DtCvValue  found = False;
637
638     while (i < max_cnt)
639      {
640         if (_DtCvIsNotProcessed(lines[i]))
641           {
642             maxY = lines[i].baseline + lines[i].descent;
643             if (target_y == -1 || maxY < target_y)
644               {
645                 found    = True;
646                 target_y = maxY;
647               }
648             SkipOtherLines (lines, max_cnt, i+1, target_y, &i);
649           }
650         else
651             i++;
652      }
653
654     *ret_y = target_y;
655     return found;
656 }
657
658 /*****************************************************************************
659  * Function: GetSelectedText
660  *
661  *****************************************************************************/
662 static int
663 GetSelectedText(
664     _DtCanvasStruct     *canvas,
665     _DtCvSelectData next,
666     _DtCvSelectData end,
667     unsigned int         mask,
668     _DtCvPointer        *ret_data)
669 {
670     _DtCvUnit   maxY;
671     _DtCvUnit   botY;
672     _DtCvUnit   lastY;
673     int    i;
674     int    lineCnt  = 0;
675     int    junk;
676     int    result   = 0;
677     int    cpyCnt   = 0;
678     int    txtCnt   = canvas->txt_cnt;
679     _DtCvFlags endFlag;
680     _DtCvValue  processing = True;
681     _DtCvDspLine   *lines = canvas->txt_lst;
682
683     for (i = 0; i < txtCnt; i++)
684         _DtCvClearProcessed(lines[i]);
685
686     MarkLinesOutsideBoundary(canvas, next.y, next.x, end.y, end.x);
687
688     maxY = next.y;
689     if (next.line_idx == -1)
690       {
691         /*
692          * find the first selected line
693          */
694         if (FindNextMinY(lines, txtCnt, -1, &next.y) == False)
695             return 0;
696
697         next.x  = 0;
698         lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
699         next.char_idx = 0;
700       }
701     else
702         lineCnt = FindMinX(lines, txtCnt, next.y, &junk);
703
704     while (processing == True && result == 0)
705       {
706         /*
707          * process the next line of text.
708          */
709         do
710           {
711             endFlag = 0;
712             cpyCnt  = lines[next.line_idx].length - next.char_idx;
713             if (next.line_idx == end.line_idx)
714                 cpyCnt = cpyCnt - lines[next.line_idx].length + end.char_idx;
715             else if (lineCnt == 1)
716                 endFlag = _DtCvEND_OF_LINE;
717
718             result  = BuildLine(canvas, mask, maxY, next.x,
719                                         next.line_idx, next.char_idx,
720                                         cpyCnt, endFlag,
721                                         &next.x, &botY, ret_data);
722
723             if (botY > maxY)
724                 maxY = botY;
725
726             next.char_idx = 0;
727             lineCnt       = FindMinX(lines, txtCnt, next.y, &next.line_idx);
728
729           } while (result == 0 && lineCnt > 0);
730
731         if (result == 0)
732           {
733             next.x = 0;
734             processing = FindNextMinY(lines, txtCnt, -1, &next.y);
735             if (processing == True)
736                 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
737           }
738       }
739
740     return result;
741
742 } /* End GetSelectedText */
743
744 /*****************************************************************************
745  * Function:    GetSegsInArea()
746  *
747  * Purpose:     Retrieve the segments making up the selection.
748  *
749  *****************************************************************************/
750 static _DtCvStatus
751 GetSegsInArea (
752     _DtCanvasStruct     *canvas,
753     _DtCvSelectData       *beg,
754     _DtCvSelectData       *end,
755     _DtCvSegPts         ***ret_segs,
756     _DtCvUnit             *ret_y1,
757     _DtCvUnit             *ret_y2)
758 {
759     int                  cnt;
760     int                  count;
761     int                  start;
762     int                  length;
763     int                  lineCnt;
764     int                  result = 0;
765     _DtCvValue           processing = True;
766     _DtCvUnit            minY;
767     _DtCvUnit            maxY;
768     _DtCvUnit            botY;
769     _DtCvSelectData      next;
770     _DtCvSegPts         *newPt;
771     _DtCvSegmentI       *pSeg;
772     _DtCvDspLine        *lines = canvas->txt_lst;
773
774     *ret_segs = NULL;
775
776     if (beg->x == -1)
777         return _DtCvSTATUS_NONE;
778
779     /*
780      * make sure the selection points are in the correct order.
781      */
782     CheckAndSwitchPoints(beg, end);
783
784     /*
785      * clear the processed bit
786      */
787     for (cnt = 0; cnt < canvas->txt_cnt; cnt++)
788         _DtCvClearProcessed(lines[cnt]);
789
790     /*
791      * initialize the working structure
792      * mark all the lines outside the selection regiion as invalid
793      */
794     next = *beg;
795     MarkLinesOutsideBoundary(canvas, next.y, next.x, end->y, end->x);
796
797     /*
798      * start the minimum and maximum Y at this location.
799      */
800     minY = next.y;
801     maxY = end->y;
802
803     /*
804      * is there a line at this location?
805      */
806     if (next.line_idx == -1)
807       {
808         /*
809          * find the first selected line within the region.
810          */
811         if (FindNextMinY(lines, canvas->txt_cnt, -1, &next.y) == False)
812             processing = False;         /* empty of any text */
813         else
814           {
815             /*
816              * now find the first line that is on this 'line' and
817              * the number of lines.
818              */
819             next.x  = 0;
820             lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &next.line_idx);
821             next.char_idx = 0;
822           }
823       }
824     else /* find the number of lines on this 'line' */
825         lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &cnt);
826
827     /*
828      * loop will there are segments to process
829      */
830     while (processing == True && result == 0)
831       {
832         /*
833          * process the next line of text.
834          */
835         while (result == 0 && lineCnt > 0)
836           {
837             /*
838              * for each segment in this line (that is selected)
839              * create a segment point for it.
840              */
841             length = lines[next.line_idx].length;
842             start  = lines[next.line_idx].byte_index;
843
844             /*
845              * if this is the last line, shorten the length
846              * by the ending index.
847              */
848             if (next.line_idx == end->line_idx)
849                 length = end->char_idx;
850
851             /*
852              * move through the line's segments until we
853              * hit the segment starting the selection
854              */
855             pSeg = lines[next.line_idx].seg_ptr;
856             count = next.char_idx;
857             while (NULL != pSeg && 0 < count)
858               {
859                 /*
860                  * get the byte count of this segment
861                  */
862                 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
863                                         &cnt, NULL, NULL);
864
865                 /*
866                  * is the byte count of this segment larger than
867                  * the starting index of the selection? If not,
868                  * the selection is after this segment.
869                  */
870                 if (count >= cnt)
871                   {
872                     start          = 0;
873                     length        -= cnt;
874                     pSeg           = pSeg->next_disp;
875                   }
876                 else
877                   {
878                     length        -= count;
879                     start          = start + count;
880                   }
881                 count -= cnt;
882               }
883
884             while (0 == result && NULL != pSeg && 0 < length)
885               {
886                 /*
887                  * start with error condition. If the malloc works
888                  * the error result gets reset to valid.
889                  */
890                 result = -1;
891                 newPt = (_DtCvSegPts *) malloc (sizeof(_DtCvSegPts));
892                 if (NULL != newPt)
893                   {
894                     /*
895                      * indicate everything is okay.
896                      */
897                     result = 0;
898
899                     /*
900                      * get the width of this segment
901                      */
902                     _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
903                                                         &cnt, NULL, NULL);
904
905                     /*
906                      * now set the segment point information and add it to the
907                      * array of segment points.
908                      */
909                     newPt->offset  = start;
910                     newPt->len     = cnt;
911                     newPt->segment = pSeg;
912
913                     *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray(
914                                                         (void **) *ret_segs,
915                                                         (void  *)  newPt);
916                     if (NULL == *ret_segs)
917                         result = -1;
918
919                     pSeg    = pSeg->next_disp;
920                     length -= cnt;
921                     start   = 0;
922                   }
923               }
924
925             /*
926              * does this line extend below the selection y?
927              * if so, report it as the maximum y.
928              */
929             botY = lines[next.line_idx].baseline + lines[next.line_idx].descent;
930             if (botY > maxY)
931                 maxY = botY;
932
933             /*
934              * indicate this line has been processed.
935              */
936             _DtCvSetProcessed(lines[next.line_idx]);
937
938             /*
939              * get the next line
940              */
941             next.char_idx = 0;
942             lineCnt       = FindMinX(lines, canvas->txt_cnt, next.y,
943                                                         &next.line_idx);
944           }
945
946         if (result == 0)
947           {
948             next.x = 0;
949             processing = FindNextMinY(lines,canvas->txt_cnt, -1, &next.y);
950             if (processing == True)
951                 lineCnt = FindMinX(lines,canvas->txt_cnt,next.y,&next.line_idx);
952           }
953       }
954
955     /*
956      * if no errors, add a null to the array
957      */
958     if (0 != result)
959       {
960         *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray((void **) *ret_segs,
961                                                         (void  *) NULL);
962         if (NULL == *ret_segs)
963             result = -1; 
964       }
965
966     /*
967      * if errors, free the segment points and return a bad status.
968      */
969     if (0 != result)
970       {
971         if (NULL != *ret_segs)
972           {
973             for (lineCnt = 0; NULL != (*ret_segs)[lineCnt]; lineCnt++)
974                 free((*ret_segs)[lineCnt]);
975             free(*ret_segs);
976           }
977         return _DtCvSTATUS_BAD;
978       }
979
980     if (NULL != ret_y1)
981         *ret_y1 = minY;
982     
983     if (NULL != ret_y2)
984         *ret_y2 = minY;
985
986     return _DtCvSTATUS_OK;
987 }
988
989 /******************************************************************************
990  *                             Semi-Public Functions
991  ******************************************************************************/
992 /*****************************************************************************
993  * Function: _DtCvDrawAreaWithFlags
994  *
995  *****************************************************************************/
996 void
997 _DtCvDrawAreaWithFlags (
998     _DtCanvasStruct     *canvas,
999     _DtCvSelectData      start,
1000     _DtCvSelectData      end,
1001     _DtCvFlags           old_flags,
1002     _DtCvFlags           new_flags,
1003     _DtCvElemType        trav_type,
1004     _DtCvPointer         trav_data)
1005 {
1006     int    i;
1007     int    len;
1008     int    count;
1009     int    startChar;
1010     int    lnkInd;
1011     _DtCvUnit   dstX;
1012     _DtCvUnit   topY;
1013     _DtCvUnit   botY;
1014     _DtCvUnit   superWidth;
1015     _DtCvUnit   subWidth;
1016     _DtCvUnit   superY;
1017     _DtCvUnit   subY;
1018     _DtCvUnit   scriptX;
1019     _DtCvUnit   segWidth;
1020     _DtCvSegmentI  *pSeg;
1021     _DtCvValue   lstLinkVis;
1022     _DtCvValue   lstWasSuper;
1023     _DtCvValue   lstWasSub;
1024     _DtCvValue   trimmed;
1025     _DtCvFlags   flagMask = old_flags | new_flags;
1026     _DtCvFlags   endFlag  = flagMask & _DtCvTRAVERSAL_END;
1027
1028     _DtCvDspLine   *lines = canvas->txt_lst;
1029
1030     /*
1031      * now use the flagMask to determine what else to look for.
1032      * I.e. if flagMask has _DtCvMARK_FLAG set, then it becomes
1033      * set to _DtCvSELECTED_FLAG and visa versa.
1034      */
1035     flagMask ^= (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG);
1036
1037     /*
1038      * strip the end flag from the other flags
1039      */
1040     new_flags &= ~(_DtCvTRAVERSAL_END);
1041     old_flags &= ~(_DtCvTRAVERSAL_END);
1042
1043     if (Equal(start, end))
1044         return;
1045
1046     for (i = 0; i < canvas->txt_cnt; i++)
1047       {
1048         topY  = lines[i].baseline - lines[i].ascent;
1049         botY  = lines[i].baseline + lines[i].descent;
1050
1051         if (InRegion(topY, botY, start.y, end.y))
1052           {
1053             /*
1054              * get the start of the text.
1055              */
1056             lstLinkVis  = False;
1057             lstWasSuper = False;
1058             lstWasSub   = False;
1059             lnkInd      = -1;
1060             dstX        = _DtCvGetStartXOfLine(&(lines[i]), &pSeg);
1061             startChar   = lines[i].byte_index;
1062             count       = lines[i].length;
1063
1064             while (pSeg != NULL && _DtCvIsSegNoop(pSeg))
1065               {
1066                 startChar  = 0;
1067                 pSeg       = pSeg->next_disp;
1068               }
1069
1070             /*
1071              * advance the starting point
1072              */
1073             dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1074                                         &lnkInd, &lstLinkVis);
1075             /*
1076              * take into account super/sub scripting
1077              */
1078             dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
1079                                         &superWidth, &superY, &subWidth, &subY,
1080                                         &lstWasSuper, &lstWasSub);
1081
1082             /*
1083              * set this flag so that the first pass of 'while (cnt > 0)'
1084              * doesn't do it again.
1085              */
1086             trimmed = True;
1087
1088             if (_DtCvStraddlesPt(start.y, topY, botY))
1089               {
1090                 /*
1091                  * skip this item?
1092                  * I.E. is this line before the start or after the end?
1093                  */
1094                 if (canvas->txt_lst[i].max_x < start.x ||
1095                                         end.y == start.y && end.x <= dstX )
1096                     continue;
1097
1098                 /*
1099                  * does this line start the mark/selection?
1100                  */
1101                 if (i == start.line_idx && start.x >= dstX)
1102                   {
1103                     int cnt = start.char_idx;
1104
1105                     while (cnt > 0)
1106                       {
1107                         if (trimmed == False)
1108                           {
1109                             /*
1110                              * advance the starting point
1111                              */
1112                             dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1113                                         &lnkInd, &lstLinkVis);
1114                             /*
1115                              * take into account super/sub scripting
1116                              */
1117                             dstX = _DtCvAdjustForSuperSub(canvas,
1118                                         pSeg, dstX, &scriptX,
1119                                         &superWidth, &superY, &subWidth, &subY,
1120                                         &lstWasSuper, &lstWasSub);
1121                           }
1122
1123                         /*
1124                          * take into account the length of the segment
1125                          */
1126                         _DtCvGetWidthOfSegment(canvas, pSeg,
1127                                         startChar , cnt,
1128                                         &len, &segWidth, &trimmed);
1129
1130                         dstX       += segWidth;
1131                         startChar  += len;
1132                         if (trimmed == False)
1133                           {
1134                             startChar  = 0;
1135                             pSeg       = pSeg->next_disp;
1136                           }
1137
1138                         trimmed = False;
1139
1140                         cnt -= len;
1141
1142                       }
1143
1144                     count -= start.char_idx;
1145                   }
1146
1147                 /*
1148                  * otherwise this line is after the line that starts
1149                  * the mark/selection. Stick with its start x.
1150                  */
1151               }
1152
1153             /*
1154              * does this straddle the end point?
1155              */
1156             if (_DtCvStraddlesPt(end.y, topY, botY))
1157               {
1158                 /*
1159                  * does this start after the end of the mark/selection?
1160                  * if so, skip.
1161                  */
1162                 if (end.x <= dstX)
1163                     continue;
1164
1165                 /*
1166                  * Does this segment end after the end of the mark/selection?
1167                  * If so, trim how much gets highlighted.
1168                  */
1169                 if (canvas->txt_lst[i].max_x > end.x)
1170                     count -= (lines[i].length - end.char_idx);
1171               }
1172
1173             /*
1174              * while there is something to draw (un)mark/selected.
1175              */
1176             old_flags = old_flags | _DtCvMARK_BEGIN;
1177             new_flags = new_flags | _DtCvMARK_BEGIN;
1178             while (count > 0)
1179               {
1180                 /*
1181                  * the original count to render
1182                  */
1183                 len = count;
1184
1185                 /*
1186                  * check for other marks and selection.
1187                  */
1188                 _DtCvCheckLineMarks(canvas, i, startChar - lines[i].byte_index,
1189                                                 count, dstX, flagMask,
1190                                                 &len, &old_flags, &new_flags);
1191
1192                 /*
1193                  * if this is the last segment(s) of the (un)mark/selection
1194                  * set the end flags.
1195                  */
1196                 if (len == count)
1197                   {
1198                     new_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1199                     old_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1200                   }
1201
1202                 /*
1203                  * draw the segments that are marked/unmarked.
1204                  */
1205                 dstX = _DtCvDrawSegments(canvas, lines[i],
1206                                         pSeg, startChar , len, &lnkInd,
1207                                         dstX, dstX, &scriptX,
1208                                         &superWidth, &superY, &subWidth, &subY,
1209                                         &lstWasSub, &lstWasSuper,
1210                                         &lstLinkVis, old_flags, new_flags,
1211                                         trav_type, trav_data);
1212                 /*
1213                  * modify the count by the length processed
1214                  */
1215                 count  -= len;
1216
1217                 /*
1218                  * did this do the entire length? If not, set the
1219                  * indexes ahead and do again.
1220                  */
1221                 if (count > 0)
1222                     _DtCvSkipLineChars(canvas, pSeg, startChar , count + len,
1223                                                 len, &startChar , &pSeg);
1224
1225                 /*
1226                  * strip the any begin flags.
1227                  */
1228                 _DtCvRemoveBeginFlags(old_flags);
1229                 _DtCvRemoveBeginFlags(new_flags);
1230               }
1231           }
1232       }
1233 }
1234
1235 /*****************************************************************************
1236  * Function:    _DtCanvasGetSelectionPoints()
1237  *
1238  * Purpose:     Retrieve the segments making up the selection.
1239  *
1240  *****************************************************************************/
1241 _DtCvStatus
1242 _DtCvGetMarkSegs (
1243     _DtCanvasStruct     *canvas,
1244     _DtCvPointInfo      ***ret_info)
1245 {
1246     int                   i;
1247
1248     *ret_info = NULL;
1249
1250     for (i = 0; i < canvas->mark_cnt; i++)
1251       {
1252         _DtCvPointInfo  *nxtInfo;
1253
1254         /*
1255          * allocate mark information structure
1256          */
1257         nxtInfo = (_DtCvPointInfo *) malloc (sizeof(_DtCvPointInfo));
1258         if (NULL == nxtInfo)
1259             return _DtCvSTATUS_BAD;
1260
1261         nxtInfo->client_data = canvas->marks[i].client_data;
1262
1263         if (_DtCvSTATUS_BAD == GetSegsInArea(canvas, &(canvas->marks[i].beg),
1264                                                 &(canvas->marks[i].end),
1265                                                 &(nxtInfo->segs),
1266                                                 NULL, NULL))
1267             return _DtCvSTATUS_BAD;
1268
1269         *ret_info = (_DtCvPointInfo **) _DtCvAddPtrToArray((void **) *ret_info,
1270                                                         (void *) nxtInfo);
1271         if (NULL == *ret_info)
1272             return _DtCvSTATUS_BAD;
1273           }
1274
1275     return _DtCvSTATUS_OK;
1276 }
1277
1278 /******************************************************************************
1279  *                             Public Functions
1280  ******************************************************************************/
1281 /*****************************************************************************
1282  * Function:    _DtCanvasGetSelection()
1283  *
1284  * Purpose:     Indicate the end point for a selection.
1285  *
1286  *****************************************************************************/
1287 _DtCvStatus
1288 _DtCanvasGetSelection (
1289     _DtCvHandle          canvas_handle,
1290     unsigned int         mask,
1291     _DtCvPointer        *ret_select)
1292 {
1293     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
1294
1295     *ret_select = NULL;
1296     return(GetSelectedText(canvas, canvas->select_start, canvas->select_end,
1297                                                         mask, ret_select));
1298 }
1299
1300 /*****************************************************************************
1301  * Function:    _DtCanvasProcessSelection()
1302  *
1303  * Purpose:     Indicate an new point for a selection.
1304  *
1305  *****************************************************************************/
1306 void
1307 _DtCanvasProcessSelection (
1308     _DtCvHandle         canvas_handle,
1309     _DtCvUnit           x,
1310     _DtCvUnit           y,
1311     _DtCvSelectMode     mode)
1312 {
1313     int                  i;
1314     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
1315     _DtCvSelectData      temp;
1316
1317     switch (mode)
1318           {
1319         case _DtCvSELECTION_CLEAR:
1320                 CheckAndSwitchPoints(&(canvas->select_start),
1321                                                         &(canvas->select_end));
1322
1323         case _DtCvSELECTION_START:
1324                 _DtCvDrawAreaWithFlags(canvas, canvas->select_start,
1325                                 canvas->select_end,
1326                                 _DtCvSELECTED_FLAG, 0,
1327                                 _DtCvBAD_TYPE, NULL);
1328
1329                 canvas->select_start = defaultSelect;
1330                 if (mode == _DtCvSELECTION_START)
1331                     SearchForClosestLine(canvas, x, y, &(canvas->select_start));
1332
1333                 canvas->select_end   = canvas->select_start;
1334                 break;
1335
1336         case _DtCvSELECTION_END:
1337         case _DtCvSELECTION_UPDATE:
1338                 SearchForClosestLine(canvas, x, y, &temp);
1339
1340                 AdjustSelection (canvas, temp);
1341                 if (mode == _DtCvSELECTION_END)
1342                     CheckAndSwitchPoints(&(canvas->select_start),
1343                                                         &(canvas->select_end));
1344                 break;
1345       }
1346 }
1347
1348 /*****************************************************************************
1349  * Function:    _DtCanvasGetSelectionPoints()
1350  *
1351  * Purpose:     Retrieve the segments making up the selection.
1352  *
1353  *****************************************************************************/
1354 _DtCvStatus
1355 _DtCanvasGetSelectionPoints (
1356     _DtCvHandle            canvas_handle,
1357     _DtCvSegPts         ***ret_segs,
1358     _DtCvUnit             *ret_y1,
1359     _DtCvUnit             *ret_y2)
1360 {
1361     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
1362
1363     return (GetSegsInArea(canvas, &(canvas->select_start),
1364                         &(canvas->select_end), ret_segs, ret_y1, ret_y2));
1365 }
1366
1367 /*****************************************************************************
1368  * Function:    _DtCanvasActivatePts()
1369  *
1370  * Purpose:     Activate the points given.
1371  *
1372  *****************************************************************************/
1373 _DtCvStatus
1374 _DtCanvasActivatePts (
1375     _DtCvHandle          canvas_handle,
1376     unsigned int         mask,
1377     _DtCvPointInfo      *info,
1378     _DtCvUnit           *ret_y1,
1379     _DtCvUnit           *ret_y2)
1380 {
1381     int                  markIdx;
1382     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
1383     _DtCvSelectData      startSel = defaultSelect;
1384     _DtCvSelectData      endSel   = defaultSelect;
1385     _DtCvFlags           flag;
1386     _DtCvSegmentI       *firstSeg;
1387
1388 #define REQUIRE_SEGS \
1389                 (_DtCvACTIVATE_MARK | _DtCvACTIVATE_SELECTION)
1390     /*
1391      * check to see if there is anything to do
1392      */
1393     if (0 == mask)
1394         return _DtCvSTATUS_NONE;
1395
1396     if ((mask & _DtCvACTIVATE_MARK) && (mask & _DtCvDEACTIVATE))
1397         return _DtCvSTATUS_BAD;
1398
1399     /*
1400      * Convert the segments into starting and ending positions.
1401      */
1402     if (((mask & _DtCvDEACTIVATE) && NULL == info->client_data)
1403                 || (mask & REQUIRE_SEGS))
1404       {
1405         if (NULL == info || NULL == info->segs ||
1406                 _DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, info->segs,
1407                                                 &startSel, &endSel,
1408                                                 ret_y1, ret_y2, &firstSeg))
1409             return _DtCvSTATUS_BAD;
1410       }
1411
1412     /*
1413      * Activate as a selection
1414      */
1415     if (mask & _DtCvACTIVATE_SELECTION)
1416       {
1417         _DtCanvasProcessSelection (canvas_handle, 0, 0, _DtCvSELECTION_CLEAR);
1418
1419         canvas->select_start = startSel;
1420         canvas->select_end   = endSel;
1421
1422         _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1423                                                 0, _DtCvSELECTED_FLAG,
1424                                                 _DtCvBAD_TYPE, NULL);
1425       }
1426
1427     /*
1428      * Activate as a mark
1429      */
1430     if (mask & _DtCvACTIVATE_MARK)
1431       {
1432         int             travIdx;
1433         _DtCvUnit       x;
1434         _DtCvUnit       y;
1435         _DtCvUnit       width;
1436         _DtCvUnit       height;
1437
1438         markIdx = _DtCvAddToMarkList(canvas, info->client_data,
1439                                 _DtCvIsMarkMaskOn(mask), &startSel, &endSel);
1440         if (-1 == markIdx)
1441             return _DtCvSTATUS_BAD;
1442
1443         /*
1444          * now put the mark in the traversal list and merge it into the
1445          * proper place.
1446          */
1447         travIdx = _DtCvGetNextTravEntry(canvas);
1448         if (-1 == travIdx
1449                 || 0 != _DtCvSetTravEntryInfo(canvas, travIdx,
1450                                                 _DtCvTraversalMark, firstSeg,
1451                                                 markIdx, _DtCvTRUE)
1452                 || 0 != _DtCvCalcMarkPos(canvas, markIdx,
1453                                                 &x, &y, &width, &height)
1454                 || 0 != _DtCvSetTravEntryPos(canvas, travIdx,
1455                                                 x, y, width, height))
1456             return _DtCvSTATUS_BAD;
1457
1458         _DtCvSortTraversalList(canvas, _DtCvTRUE);
1459
1460         /*
1461          * draw these segments marked.
1462          */
1463         flag = _DtCvMARK_FLAG;
1464         if (_DtCvTRUE == canvas->marks[markIdx].on)
1465             flag |= _DtCvMARK_ON;
1466
1467         _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1468                                                         0, flag,
1469                                                         _DtCvBAD_TYPE, NULL);
1470       }
1471
1472     /*
1473      * Clear the mark flag.
1474      */
1475     else if (mask & _DtCvDEACTIVATE)
1476       {
1477         int     travIdx;
1478
1479         /*
1480          * is there anything to deacivate?
1481          */
1482         if (NULL == canvas->marks || 0 == canvas->mark_cnt)
1483             return _DtCvSTATUS_BAD;
1484
1485         /*
1486          * was client data specified? If so, then look for it and ignore
1487          * the segment data.
1488          */
1489         markIdx = 0;
1490         if (NULL != info->client_data)
1491           {
1492             while (markIdx < canvas->mark_cnt &&
1493                    canvas->marks[markIdx].client_data != info->client_data)
1494                 markIdx++;
1495
1496             /*
1497              * initialize the selection points
1498              */
1499             if (markIdx < canvas->mark_cnt)
1500               {
1501                 startSel = canvas->marks[markIdx].beg;
1502                 endSel   = canvas->marks[markIdx].end;
1503               }
1504           }
1505         /*
1506          * look for the marked set using the segments.
1507          */
1508         else
1509           {
1510             while (markIdx < canvas->mark_cnt
1511                    && startSel.line_idx != canvas->marks[markIdx].beg.line_idx
1512                    && startSel.char_idx != canvas->marks[markIdx].beg.char_idx
1513                    && endSel.line_idx != canvas->marks[markIdx].end.line_idx
1514                    && endSel.line_idx != canvas->marks[markIdx].end.char_idx)
1515                 markIdx++;
1516           }
1517
1518         if (markIdx >= canvas->mark_cnt)
1519             return _DtCvSTATUS_BAD;
1520
1521         /*
1522          * draw these segments unmarked.
1523          */
1524         flag = _DtCvMARK_FLAG;
1525         if (_DtCvTRUE == canvas->marks[markIdx].on)
1526             flag |= _DtCvMARK_ON;
1527
1528         canvas->marks[markIdx].on = _DtCvFALSE;
1529         _DtCvDrawAreaWithFlags (canvas, startSel, endSel, flag, 0,
1530                                                 _DtCvBAD_TYPE, NULL);
1531
1532         /*
1533          * remove the mark from the traversal list
1534          *
1535          * first find the traversal entry of the mark and adjust any
1536          * traversal mark index values to reflect that the mark
1537          * list is about to shrink by 1.
1538          */
1539         for (travIdx = 0; _DtCvTraversalMark != canvas->trav_lst[travIdx].type
1540                         || markIdx != canvas->trav_lst[travIdx].idx; travIdx++)
1541           {
1542             /*
1543              * is this mark after the one being removed?
1544              * if so, decrease its index because it's about to move.
1545              */
1546             if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1547                                         markIdx < canvas->trav_lst[travIdx].idx)
1548                 canvas->trav_lst[travIdx].idx--;
1549           }
1550
1551         /*
1552          * move the list of traversal entries to eliminate the mark entry.
1553          */
1554         while (travIdx + 1 < canvas->trav_cnt)
1555           {
1556             canvas->trav_lst[travIdx] = canvas->trav_lst[travIdx + 1];
1557
1558             /*
1559              * is this a mark after the one being removed?
1560              * if so, decrease it's index because it's about to move.
1561              */
1562             if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1563                                         markIdx < canvas->trav_lst[travIdx].idx)
1564                 canvas->trav_lst[travIdx].idx--;
1565
1566             travIdx++;
1567           }
1568
1569         /*
1570          * update the traversal count and back up to the previous traversal
1571          * if the mark was at the end of the traversal list.
1572          */
1573         canvas->trav_cnt--;
1574         if (canvas->cur_trav >= canvas->trav_cnt)
1575             canvas->cur_trav--;
1576
1577         /*
1578          * move the list of marks up
1579          */
1580         while (markIdx + 1 < canvas->mark_cnt)
1581           {
1582             canvas->marks[markIdx] = canvas->marks[markIdx + 1];
1583             markIdx++;
1584           }
1585
1586         canvas->mark_cnt--;
1587       }
1588     else if ((_DtCvACTIVATE_MARK_ON | _DtCvACTIVATE_MARK_OFF) & mask)
1589       {
1590         markIdx = 0;
1591         if (NULL != info && NULL != info->client_data)
1592           {
1593             while (markIdx < canvas->mark_cnt &&
1594                    canvas->marks[markIdx].client_data != info->client_data)
1595                 markIdx++;
1596
1597             /*
1598              * was a mark with this client data found?
1599              */
1600             if (markIdx >= canvas->mark_cnt)
1601                 return _DtCvSTATUS_BAD;
1602           }
1603         else
1604           {
1605             /*
1606              * are there any traversals? Is the current one sitting on a mark?
1607              */
1608             if (0 == canvas->trav_cnt || -1 == canvas->cur_trav ||
1609                 _DtCvTraversalMark != canvas->trav_lst[canvas->cur_trav].type)
1610                 return _DtCvSTATUS_BAD;
1611
1612             /*
1613              * get the mark index
1614              */
1615             markIdx = canvas->trav_lst[canvas->cur_trav].idx;
1616           }
1617
1618         /*
1619          * is this different than what it is set at now? If not, do nothing.
1620          */
1621         if (_DtCvIsMarkMaskOn(mask) == canvas->marks[markIdx].on)
1622             return _DtCvSTATUS_NONE;
1623
1624         /*
1625          * set to mask value.
1626          */
1627         canvas->marks[markIdx].on = _DtCvIsMarkMaskOn(mask);
1628
1629         /*
1630          * set the flags correctly.
1631          */
1632         flag = _DtCvMARK_FLAG;
1633         if (_DtCvTRUE == canvas->marks[markIdx].on)
1634             flag |= _DtCvMARK_ON;
1635         if (_DtCvTRUE == canvas->trav_on &&
1636                         markIdx == canvas->trav_lst[canvas->cur_trav].idx)
1637             flag |= _DtCvTRAVERSAL_FLAG;
1638
1639         /*
1640          * draw the mark opposite what it was
1641          */
1642         _DtCvDrawAreaWithFlags (canvas, canvas->marks[markIdx].beg,
1643                                 canvas->marks[markIdx].end,
1644                                 (flag ^ _DtCvMARK_ON), flag,
1645                                 _DtCvBAD_TYPE, NULL);
1646       }
1647
1648     return _DtCvSTATUS_OK;
1649 }
1650
1651 /*****************************************************************************
1652  * Function:    _DtCanvasGetMarkPositions()
1653  *
1654  * Purpose:     Return the position in the canvas of the marks.
1655  *
1656  *****************************************************************************/
1657 _DtCvStatus
1658 _DtCanvasGetMarkPositions (
1659     _DtCvHandle             canvas_handle,
1660     _DtCvMarkPos         ***ret_pos)
1661 {
1662     int  i;
1663     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
1664     _DtCvMarkPos        *nextPos;
1665     _DtCvMarkData       *markLst = canvas->marks;
1666
1667     *ret_pos = NULL;
1668
1669     if (0 == canvas->mark_cnt)
1670         return _DtCvSTATUS_NONE;
1671
1672     for (i = 0; i < canvas->mark_cnt; i++, markLst++)
1673       {
1674         /*
1675          * malloc memory for the information
1676          */
1677         nextPos = (_DtCvMarkPos *) malloc (sizeof(_DtCvMarkPos));
1678         if (NULL == nextPos)
1679             return _DtCvSTATUS_BAD;
1680
1681         /*
1682          * client data and baselines
1683          */
1684         nextPos->client_data = markLst->client_data;
1685         nextPos->baseline1   = canvas->txt_lst[markLst->beg.line_idx].baseline;
1686         nextPos->baseline2   = canvas->txt_lst[markLst->end.line_idx].baseline;
1687
1688         /*
1689          * top left corner
1690          */
1691         nextPos->x1 = markLst->beg.x;
1692         nextPos->y1 = nextPos->baseline1 -
1693                                 canvas->txt_lst[markLst->beg.line_idx].ascent;
1694
1695         /*
1696          * bottom right corner
1697          */
1698         nextPos->x2 = markLst->end.x;
1699         nextPos->y2 = nextPos->baseline2 +
1700                                 canvas->txt_lst[markLst->end.line_idx].descent;
1701
1702         *ret_pos = (_DtCvMarkPos **) _DtCvAddPtrToArray((void **) *ret_pos,
1703                                                         (void *) nextPos);
1704         if (NULL == *ret_pos)
1705             return _DtCvSTATUS_BAD;
1706       }
1707
1708     return _DtCvSTATUS_OK;
1709 }