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