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