2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $TOG: Canvas.c /main/40 1999/10/14 13:17:22 mgreess $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 ** Project: Cde Help System
31 ** Description: UI independent layer for the help system. These
32 ** routines manage the information within a 'canvas'.
33 ** The 'canvas' routines call UI dependent code to
34 ** render the information.
36 ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
38 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
39 ** (c) Copyright 1993, 1994 International Business Machines Corp.
40 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
41 ** (c) Copyright 1993, 1994 Novell, Inc.
42 ****************************************************************************
43 ************************************<+>*************************************/
52 * Canvas Engine includes
55 #include "CanvasSegP.h"
61 #include "CvStringI.h"
63 #include "LayoutUtilI.h"
64 #include "SelectionI.h"
65 #include "VirtFuncsI.h"
70 /******** Private Function Declarations ********/
71 static _DtCvUnit DrawText(
72 _DtCanvasStruct *canvas,
76 _DtCvFlags new_flag );
77 /******** End Private Function Declarations ********/
79 /*****************************************************************************
81 *****************************************************************************/
82 static _DtCanvasStruct DefaultCanvas =
87 0, /* int line_cnt; */
88 0, /* int line_max; */
89 0, /* int mark_cnt; */
90 0, /* int mark_max; */
91 0, /* int trav_cnt; */
92 0, /* int trav_max; */
93 0, /* int cur_trav; */
98 1, /* short mb_length; */
99 0, /* _DtCvUnit max_x; */
100 0, /* _DtCvUnit max_y; */
101 _DtCvIGNORE_BOUNDARY, /* _DtCvValue constraint; */
102 _DtCvFALSE, /* _DtCvValue trav_on; */
103 NULL, /* _DtCvPointer client_data; */
104 { /* CanvasMetrics metrics; */
105 0, /* _DtCvUnit width; */
106 0, /* _DtCvUnit height; */
107 0, /* _DtCvUnit top_margin; */
108 0, /* _DtCvUnit line_height; */
109 0, /* _DtCvUnit horiz_pad_hint; */
111 { /* _DtCvSpaceMetrics link_info; */
112 0, /* _DtCvUnit space_before; */
113 0, /* _DtCvUnit space_after; */
114 0, /* _DtCvUnit space_above; */
115 0, /* _DtCvUnit space_below; */
117 { /* _DtCvSpaceMetrics traversal_info; */
118 0, /* _DtCvUnit space_before; */
119 0, /* _DtCvUnit space_after; */
120 0, /* _DtCvUnit space_above; */
121 0, /* _DtCvUnit space_below; */
123 { /* _DtCvLocale locale; */
124 _DtCvModeWrapNone, /* _DtCvModeType line_wrap_mode; */
125 NULL, /* const wchar_t *cant_begin_chars; */
126 NULL, /* const wchar_t *cant_end_chars; */
128 NULL, /* _DtCvSegment *element_lst; */
129 NULL, /* _DtCvDspLine *txt_lst; */
130 NULL, /* _DtCvLineSeg *line_lst; */
131 NULL, /* _DtCvTraversalInfo *trav_lst; */
132 NULL, /* _DtCvLinkDb link_data; */
133 { /* CESelection select_start; */
134 -1, /* _DtCvUnit x; */
135 -1, /* _DtCvUnit y; */
136 -1, /* int line_idx; */
137 -1, /* int char_idx; */
139 { /* CESelection select_end; */
140 -1, /* _DtCvUnit x; */
141 -1, /* _DtCvUnit y; */
142 -1, /* int line_idx; */
143 -1, /* int char_idx; */
145 NULL, /* _DtCvMarkData *marks; */
147 NULL, /* pg_breaks */
148 { NULL }, /* _DtCvVirtualInfo virt_functions; */
151 /*****************************************************************************
153 *****************************************************************************/
154 /*****************************************************************************
155 * Function: RenderSubSet
158 * Purpose: Render the items next to an item of text.
160 *****************************************************************************/
163 _DtCanvasStruct *canvas,
175 * Loop through the list looking for the item(s) next to the text.
177 for (i = 0; NULL != lines && i < cnt; lines++, i++)
180 * get the minimum and maximum y of the next line
182 minY = lines->baseline - lines->ascent;
183 maxY = lines->baseline + lines->descent;
186 * has this line been reviewed yet?
187 * is this line on the 'page'?
188 * Does it hang off the 'page' (and if so is it allowed)?
190 if (_DtCvIsNotProcessed(*lines) && maxY >= y1 && maxY <= y2)
192 (void) DrawText (canvas, lines, i, 0, 0);
195 * indicate that this line has been rendered.
197 _DtCvSetProcessed(*lines);
200 * is this the maximum that we've rendered?
206 * now render anything next to this!
208 RenderSubSet(canvas, canvas->txt_lst, cnt, minY, y2, last_y);
213 /*****************************************************************************
214 * Function: CheckAround
216 * Returns: _DtCvSTATUS_NONE if no other text is to the side of
218 * _DtCvFALSE if other text is to the side, but the
219 * maximum y position is not violated.
220 * _DtCvTRUE if other text is to the side and the
221 * maximum y position is violated.
222 * Purpose: Find if another line of text intrudes upon this line.
224 *****************************************************************************/
233 _DtCvUnit topY = lines[idx].baseline - lines[idx].ascent;
234 _DtCvUnit botY = lines[idx].baseline + lines[idx].descent;
237 _DtCvStatus result = _DtCvSTATUS_NONE;
240 * set the processed flag so that we don't test something that's
243 _DtCvSetProcessed(lines[idx]);
246 * go through looking for unprocessed lines to test.
248 while (i < cnt && _DtCvTRUE != result)
250 if (_DtCvIsNotProcessed(lines[i]))
253 * calculate the minimum and maximum y positions for the line.
255 minY = lines[i].baseline - lines[i].ascent;
256 maxY = lines[i].baseline + lines[i].descent;
259 * Does this line infringe vertically on the test line?
261 if (maxY > topY && minY < botY &&
262 _DtCvTRUE == _DtCvCheckInfringement(topY, botY, minY, maxY))
265 * indicate that it is not clear to the side.
270 * Does it have something else infringing one it?
271 * Or does it hang down below the test line?
273 if (maxY > y2 || _DtCvTRUE == CheckAround(lines, cnt, i, y2))
282 * Clear that this line has be processed. Otherwise, rendering will
283 * think this has been rendered when it hasn't.
285 _DtCvClearProcessed(lines[idx]);
290 /*****************************************************************************
293 * FindChar calculates the char that is x pixels into the string.
295 *****************************************************************************/
298 _DtCanvasStruct *canvas,
299 _DtCvSegmentI *segment,
306 _DtCvUnit myDiff = 0;
309 _DtCvValue triedBack = False;
310 _DtCvValue triedForward = False;
313 * get information about the font used
315 _DtCvFontMetrics(canvas, _DtCvFontOfStringSeg(segment),
316 NULL, NULL, &charWidth, NULL, NULL);
319 * try to get close to the correct index.
321 myIndex = x_pos / charWidth;
322 if (myIndex >= max_len)
323 myIndex = max_len - 1;
325 while (!triedBack || !triedForward)
327 len = _DtCvGetStringWidth(canvas, segment, string, myIndex + 1);
331 myDiff = len - x_pos;
333 if (!triedBack && myIndex)
338 else if (len < x_pos)
340 myDiff = x_pos - len;
343 if (myIndex >= max_len)
349 else /* len == x_pos */
364 /*****************************************************************************
365 * Function: DrawCanvasLines
367 *****************************************************************************/
370 _DtCanvasStruct *canvas,
375 _DtCvRenderType flag,
380 _DtCvUnit newY2 = y2;
382 _DtCvLineInfo lnInfo;
385 * are there any lines?
387 if (canvas->line_lst != NULL && canvas->line_cnt &&
388 NULL != canvas->virt_functions.render_elem)
391 * find the maximum y of all the lines that fit in the page.
392 * do this only if the flag indicates whole lines.
394 if (_DtCvRENDER_COMPLETE == flag)
396 for (i = 0, pLS = canvas->line_lst;
397 i < canvas->line_cnt; i++, pLS++)
400 * Does this line end off the page?
402 if (pLS->max_y > newY2 && pLS->pos_y < newY2)
403 newY2 = pLS->pos_y - 1;
408 * check each line to see if it is on the 'page'
410 for (i = 0, pLS = canvas->line_lst; i < canvas->line_cnt; i++, pLS++)
412 lnInfo.width = pLS->width;
413 lnInfo.data = pLS->data;
414 lnInfo.x2 = pLS->pos_x;
415 lnInfo.y2 = pLS->pos_y;
418 * horizontal or vertial line?
420 if (_DtCvLINE_HORZ == pLS->dir)
421 lnInfo.x2 = pLS->max_x;
423 lnInfo.y2 = pLS->max_y;
426 * does it fit on the page? Take into account the rendering type.
428 if (pLS->max_y >= y1 && pLS->pos_y <= newY2
429 && lnInfo.x2 >= x1 && pLS->pos_x <= x2
430 && (_DtCvRENDER_PARTIAL == flag || pLS->max_y <= newY2))
432 if (pLS->max_y > *ret_y)
435 (*(canvas->virt_functions.render_elem))(
436 canvas->client_data, _DtCvLINE_TYPE,
437 pLS->pos_x, pLS->pos_y, -1, 0, 0,
438 _DtCvBAD_TYPE, NULL, &lnInfo);
441 * otherwise, would this start the next page?
442 * make sure this is in the horizontal space.
444 else if (lnInfo.x2 >= x1 && pLS->pos_x <= x2 && pLS->max_y > newY2
445 && (-1 == *ret_next || *ret_next > pLS->pos_y))
446 *ret_next = pLS->pos_y;
449 } /* End DrawCanvasLines */
451 /******************************************************************************
455 * canvas Specifies the canvas on which to render
457 * line Specifies the line in the line table.
458 * start_x Specifies the starting x position to use
459 * for selected text. If greater than the
460 * starting position for the segment, determine
461 * the closest character to 'start_x' and
463 * end_x Specifies the ending x position to use
464 * for selected text. If -1, means display
465 * the entire set of segments.
466 * old_flag Specifies....
467 * new_flag Specifies....
469 * Returns: max_x Returns the maximum x unit processed.
471 * Purpose: DrawText draws text segments on one line in the
474 *****************************************************************************/
477 _DtCanvasStruct *canvas,
481 _DtCvFlags new_flag )
486 int count = line->length;
487 int start = line->byte_index;
489 _DtCvUnit superWidth = 0;
490 _DtCvUnit superY = 0;
491 _DtCvUnit subWidth = 0;
493 _DtCvUnit scriptX = 0;
494 _DtCvValue lastWasSuper = False;
495 _DtCvValue lastWasSub = False;
496 _DtCvValue lastLnkVis = False;
499 xPos = _DtCvGetStartXOfLine(line, &pSeg);
502 * get the corrected x for links and traversals.
504 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos, &lastLnk, &lastLnkVis);
507 * take into account the if this is a super or sub script - or not.
509 xPos = _DtCvAdjustForSuperSub(canvas, pSeg, xPos,
510 &scriptX, &superWidth, &superY,
512 &lastWasSuper, &lastWasSub);
514 * now process the line
516 while (NULL != pSeg && 0 < count)
521 * check for selected and marked text.
523 _DtCvCheckLineMarks(canvas, txt_line, curIdx, count, xPos,
524 (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
525 &len, &old_flag, &new_flag);
528 * if this is the last segment(s) of the (un)selection
533 new_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
534 old_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
538 * render the segment length returned by _DtCvCheckLineMarks
540 xPos = _DtCvDrawSegments(canvas, *line, pSeg, start, len,
541 &lastLnk, xPos, xPos,
542 &scriptX, &superWidth, &superY, &subWidth,
543 &subY, &lastWasSub, &lastWasSuper,
544 &lastLnkVis, old_flag, new_flag,
545 _DtCvBAD_TYPE, NULL);
547 * decrement the count by the length processed
552 _DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
560 /*****************************************************************************
561 * Function: IsLineSpecial (
563 * Purpose: Call a virtual function to draw the traversal indicator
564 *****************************************************************************/
567 _DtCvSelectData start,
575 _DtCvFlags *ret_flag)
577 _DtCvUnit maxY = line.baseline + line.descent;
578 _DtCvUnit minY = line.baseline - line.ascent;
582 * zero out the return flag (which will be a logical OR of
585 if (NULL != ret_flag)
589 * initialize the return value to the given inspection length.
594 * is there anything to look at?
596 if (start.y == -1 || maxY < start.y || minY >= end.y)
600 * starts the mark/selection?
602 if (line_idx == start.line_idx)
605 * does this segment straddle the start of the mark/selection?
607 if (start.char_idx > char_idx)
610 * draw part(or all) of the segment un-mark/selected.
611 * never return a value larger than the inspection length!
613 if (start.char_idx < char_idx + length)
614 *ret_len = start.char_idx - char_idx;
620 * does this segment start the line? Set the start flag if so.
622 if (start.char_idx == char_idx)
623 flag |= _DtCvMARK_BEGIN;
626 * does this line end the mark/selection?
628 if (line_idx == end.line_idx)
631 * does this line straddle the end?
633 if (char_idx >= end.char_idx)
636 * draw this un mark/selected.
637 * Its after the mark/selected part.
642 if (char_idx + length > end.char_idx)
645 * draw the mark/selected part
647 *ret_len = end.char_idx - char_idx;
648 flag |= _DtCvMARK_END;
653 * draw the current *ret_len as mark/selected
658 * does this start the mark/selection?
660 else if (line_idx == end.line_idx)
663 * does not start the mark/selection.
664 * does end the mark/selection.
666 if (char_idx >= end.char_idx)
670 * straddle the end position?
672 if (char_idx + length > end.char_idx)
674 *ret_len = end.char_idx - char_idx;
675 flag |= _DtCvMARK_END;
678 * draw the current *ret_len as mark/selected
684 * start.y <= maxY && minY < end.y
686 else if (minY < start.y)
689 * straddles the start y
697 if (start.y != end.y)
699 if (NULL != ret_flag)
711 * start.y <= minY and maxY
714 else if (end.y <= maxY)
717 * straddles the end y position
723 * start.y <= minY and maxY
724 * minY && maxY < end.y
726 if (NULL != ret_flag)
732 /*****************************************************************************
733 * Function: DrawTraversalIndicator (_DtCanvasStruct *canvas, _DtCvValue flag)
735 * Purpose: (Un)draws the traversal around the currently active link.
736 *****************************************************************************/
738 DrawTraversalIndicator (
739 _DtCanvasStruct *canvas,
741 _DtCvValue draw_flag,
744 _DtCvUnit *ret_baseline,
745 _DtCvUnit *ret_height)
752 int travIdx = canvas->cur_trav;
754 int txtLine = canvas->trav_lst[travIdx].idx;
758 _DtCvUnit height = 0;
761 _DtCvUnit superWidth = 0;
762 _DtCvUnit superY = 0;
763 _DtCvUnit subWidth = 0;
765 _DtCvUnit scriptX = 0;
767 _DtCvFlags oldFlag = 0;
768 _DtCvFlags newFlag = 0;
770 _DtCvValue lastWasSub = False;
771 _DtCvValue lastWasSuper = False;
772 _DtCvValue lstLnkVis = False;
775 _DtCvSegmentI *tmpSeg;
778 * determine the flags for rendering.
781 newFlag = _DtCvTRAVERSAL_FLAG;
783 oldFlag = _DtCvTRAVERSAL_FLAG;
786 * allow traversal to marks.
788 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type)
790 int markIdx = canvas->trav_lst[travIdx].idx;
793 oldFlag = oldFlag | _DtCvMARK_FLAG
794 | _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
795 newFlag = newFlag | _DtCvMARK_FLAG
796 | _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
798 if (_DtCvTRUE == canvas->marks[markIdx].on)
800 oldFlag |= _DtCvMARK_ON;
801 newFlag |= _DtCvMARK_ON;
804 _DtCvDrawAreaWithFlags(canvas,
805 canvas->marks[markIdx].beg,
806 canvas->marks[markIdx].end,
809 canvas->marks[markIdx].client_data);
813 *ret_height = canvas->marks[markIdx].end.y -
814 canvas->marks[markIdx].beg.y +
815 canvas->txt_lst[canvas->marks[markIdx].end.line_idx].descent +
816 canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
819 * set some return variables
822 *ret_x = canvas->marks[markIdx].beg.x;
825 *ret_y = canvas->marks[markIdx].beg.y -
826 canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
829 *ret_baseline = canvas->marks[markIdx].beg.y;
837 linkIndex = canvas->trav_lst[travIdx].seg_ptr->link_idx;
840 * determine the location of the hypertext segment.
842 pSeg = canvas->trav_lst[travIdx].seg_ptr;
843 start = canvas->txt_lst[txtLine].byte_index;
844 count = canvas->txt_lst[txtLine].length;
847 * get the start of the line
849 dstX = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
851 while (pSeg->link_idx != linkIndex)
854 * get the corrected x
856 dstX = _DtCvAdvanceXOfLine (canvas, pSeg, dstX, &lstLnk, &lstLnkVis);
859 * move the text x position base on if this is a super or
860 * sub script - or not.
862 dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
863 &superWidth, &superY, &subWidth, &subY,
864 &lastWasSuper, &lastWasSub);
867 * get the width of the segment.
869 _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
870 &len, &tmpWidth, NULL);
876 lstLnk = pSeg->link_idx;
879 pSeg = pSeg->next_disp;
884 * set some return variables
890 *ret_y = canvas->txt_lst[txtLine].baseline -
891 canvas->txt_lst[txtLine].ascent;
893 *ret_baseline = canvas->txt_lst[txtLine].baseline;
896 * start drawing the traversals
901 while (txtLine < canvas->txt_cnt && linkIndex == pSeg->link_idx)
904 * get the corrected x
906 dstX = _DtCvAdvanceXOfLine (canvas,pSeg, dstX, &lstLnk, &lstLnkVis);
909 * move the text x position base on if this is a super or
910 * sub script - or not.
912 dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
913 &superWidth, &superY, &subWidth, &subY,
914 &lastWasSuper, &lastWasSub);
917 * now count up the number of bytes to display for
924 while (totCnt > 0 && tmpSeg != NULL
925 && tmpSeg->link_idx == linkIndex)
927 _DtCvGetWidthOfSegment(canvas, tmpSeg, wrkChr,
928 totCnt, &len, NULL, NULL);
932 tmpSeg = tmpSeg->next_disp;
936 * set the begin flag.
938 newFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
939 oldFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
940 while (count > 0 && pSeg != NULL && pSeg->link_idx == linkIndex)
943 * the original count for the traversal.
948 * if there is mark/selected text, determine, how much
950 _DtCvCheckLineMarks(canvas, txtLine, curIdx, count, dstX,
951 (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
952 &len, &oldFlag, &newFlag);
954 * if this is the last segment(s) of the traversal
959 newFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
960 oldFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
964 * render the segments
966 dstX = _DtCvDrawSegments(canvas, canvas->txt_lst[txtLine],
967 pSeg, start, len, &lstLnk, dstX, dstX,
968 &scriptX,&superWidth,&superY,&subWidth,&subY,
969 &lastWasSub, &lastWasSuper,
970 &lstLnkVis, oldFlag, newFlag,
971 _DtCvLINK_TYPE, NULL);
977 _DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
979 newFlag &= ~(_DtCvTRAVERSAL_BEGIN);
980 oldFlag &= ~(_DtCvTRAVERSAL_BEGIN);
984 height += canvas->txt_lst[txtLine].ascent
985 + canvas->txt_lst[txtLine].descent;
987 if (txtLine < canvas->txt_cnt)
989 start = canvas->txt_lst[txtLine].byte_index;
990 count = canvas->txt_lst[txtLine].length;
998 lastWasSuper = False;
1005 dstX = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
1011 *ret_height = height;
1013 } /* End DrawTraversalIndicator */
1015 /*****************************************************************************
1016 * Semi-Public Functions
1017 *****************************************************************************/
1018 /*****************************************************************************
1019 * Function: _DtCvGetSearchLineMetrics (
1021 * Purpose: gets the text line metrics for the search item.
1022 *****************************************************************************/
1024 _DtCvGetSearchLineMetrics(_DtCvHandle handle, int idx, _DtCvUnit* baseline,
1025 _DtCvUnit* descent, _DtCvUnit* ascent)
1028 _DtCanvasStruct* canvas = (_DtCanvasStruct*)handle;
1031 if (idx < 0 || idx >= canvas->search_cnt)
1034 line = &(canvas->txt_lst[canvas->searchs[idx].idx]);
1036 *baseline = line->baseline;
1037 *descent = line->descent;
1038 *ascent = line->ascent;
1043 /*****************************************************************************
1044 * Function: _DtCvCheckInfringement (
1046 * Purpose: Checks to see if one object infringes vertically on another
1048 *****************************************************************************/
1050 _DtCvCheckInfringement (
1056 _DtCvStatus result = False;
1059 * check to see if the object is to the left or right of the test
1060 * object and that it 'infringes' on the vertical space of the test
1063 * I.e. ----obj_top------
1064 * | | ----tst_top----
1065 * ----obj_bot------ | |
1068 * I.e. ----tst_top----
1069 * ----obj_top------- | |
1070 * | | ----tst_bot----
1071 * ----obj_bot-------
1073 * I.e. ----obj_top------
1074 * | | ----tst_top----
1076 * | | ----tst_bot----
1079 * I.e. ----tst_top----
1080 * ----obj_top------- | |
1082 * ----obj_bot------- | |
1085 if ((obj_top < tst_top && tst_top < obj_bot)
1086 || (obj_top < tst_bot && tst_bot < obj_bot)
1087 || (obj_top <= tst_top && tst_bot <= obj_bot)
1088 || (tst_top < obj_top && obj_bot < tst_bot))
1094 /*****************************************************************************
1095 * Function: _DtCvCheckLineMarks (
1098 * canvas Specifies the canvas to check for
1099 * marks and/or selections.
1100 * line_idx Specifies the line index into the
1101 * list of text lines in the canvas.
1102 * char_idx Specifies the starting character index
1104 * length Specifies the length of the text line
1106 * dst_x Specifies the x position of the
1107 * starting character in the text line.
1108 * check_flags Specifies which type to look for -
1109 * selection, marks or both.
1110 * ret_len Returns the length of the text line
1111 * starting at the starting character
1112 * index for which the flags returned
1113 * in ret_old and ret_new are valid.
1115 * Returns the values in ret_old and ret_new
1116 * and may add _DtCvSELECTED_FLAG and/or
1119 * Purpose: Find out how much of the line is (un)marked in some way.
1120 *****************************************************************************/
1122 _DtCvCheckLineMarks (
1123 _DtCanvasStruct *canvas,
1128 _DtCvFlags check_flags,
1130 _DtCvFlags *ret_old,
1131 _DtCvFlags *ret_new)
1134 _DtCvFlags flag = 0;
1137 * check the selection
1139 if ((check_flags & _DtCvSELECTED_FLAG) && canvas->select_start.y != -1)
1141 _DtCvSelectData start = canvas->select_start;
1142 _DtCvSelectData end = canvas->select_end;
1145 * check to see if we need to switch the selection points
1147 if (start.y > end.y || (start.y == end.y && start.x > end.x))
1149 end = canvas->select_start;
1150 start = canvas->select_end;
1154 * clear the selected flag
1156 *ret_old &= ~(_DtCvSELECTED_FLAG);
1157 *ret_new &= ~(_DtCvSELECTED_FLAG);
1159 if (IsLineSpecial(start, end,
1160 canvas->txt_lst[line_idx], line_idx,
1161 char_idx, length, dst_x,
1165 * set the selected flag.
1167 *ret_old = *ret_old | _DtCvSELECTED_FLAG;
1168 *ret_new = *ret_new | _DtCvSELECTED_FLAG;
1172 if ((check_flags & _DtCvMARK_FLAG) && 0 < canvas->mark_cnt)
1175 * strip the mark flags from the old and new flags
1177 *ret_old &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
1178 _DtCvMARK_END | _DtCvMARK_ON);
1179 *ret_new &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
1180 _DtCvMARK_END | _DtCvMARK_ON);
1183 * now add the correct flags into the old/new flags
1185 for (i = 0; i < canvas->mark_cnt; i++)
1187 if (IsLineSpecial(canvas->marks[i].beg, canvas->marks[i].end,
1188 canvas->txt_lst[line_idx], line_idx,
1189 char_idx, length, dst_x,
1193 * A false return from IsLineSpecial means that 'length'
1194 * is outside this mark.
1196 * When true, it means that some part of this mark will
1197 * be rendered on the call. Therefore set the mark flag
1198 * and any other flags returned and check for mark 'on'.
1200 if (_DtCvTRUE == canvas->marks[i].on)
1201 flag |= _DtCvMARK_ON;
1203 *ret_old = *ret_old | _DtCvMARK_FLAG | flag;
1204 *ret_new = *ret_new | _DtCvMARK_FLAG | flag;
1210 * return the next length that is marked/unmarked in someway.
1215 /******************************************************************************
1216 * Function: _DtCvSkipLineChars
1219 * canvas Specifies the canvas on which to render
1222 * Purpose: Given a length, skip ahead that number of 'characters' on
1224 *****************************************************************************/
1227 _DtCanvasStruct *canvas,
1228 _DtCvSegmentI *p_seg,
1233 _DtCvSegmentI **ret_seg)
1238 * not all of the traversal line was displayed because
1239 * part of it is selected. So skip what's been rendered,
1245 * get the byte length of the segment processed.
1247 _DtCvGetWidthOfSegment(canvas, p_seg, start, max_cnt, &len, NULL, NULL);
1249 * increment the start index by the number of total
1250 * bytes processed. If this is more that what is in
1251 * the segment, then the if stmt will catch this and
1252 * set the start index to zero.
1259 else /* if (len <= use_len) */
1262 p_seg = p_seg->next_disp;
1266 * reduce the total number of bytes
1267 * processed by the number in this segment.
1277 /******************************************************************************
1278 * Function: _DtCvClearInternalUse
1280 * Init every internal_use pointer on containers to NULL.
1281 *****************************************************************************/
1283 _DtCvClearInternalUse(
1284 _DtCvSegmentI *list,
1287 while (NULL != list)
1290 * initialize the internal variables
1292 list->internal_use = (void *) -1;
1294 if (_DtCvIsSegContainer(list))
1295 _DtCvClearInternalUse(_DtCvContainerListOfSeg(list), flag);
1297 list = list->next_seg;
1301 /******************************************************************************
1302 * Function: _DtCvGetCharIdx
1305 * canvas Specifies the canvas on which to render
1307 * line Specifies the line in the line table.
1308 * find_x Specifies the x position of the character.
1310 * Returns: ?? Returns the idx of the character.
1313 *****************************************************************************/
1316 _DtCanvasStruct *canvas,
1321 _DtCvValue done = FALSE;
1322 _DtCvValue lastLinkVisible = FALSE;
1323 int count = line.length;
1324 int start = line.byte_index;
1329 _DtCvSegmentI *pSeg;
1331 xPos = _DtCvGetStartXOfLine(&line, &pSeg);
1334 * check to see if the start is in the middle of the line.
1335 * If so, bump the x position and start indexes to the
1336 * correct locations.
1338 while (!done && find_x > xPos && count > 0)
1340 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
1341 &lnkInd, &lastLinkVisible);
1346 * advance the pointer by the width
1348 _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
1349 &len, &segWidth, NULL);
1350 if (segWidth + xPos <= find_x)
1353 pSeg = pSeg->next_disp;
1357 else /* if (xPos < find_x && find_x < xPos + segWidth) */
1359 if (_DtCvIsSegString(pSeg))
1361 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
1362 _DtCvIsSegWideChar(pSeg), start);
1363 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
1368 count -= FindChar(canvas, pSeg, pChar, len,
1369 find_x - xPos, NULL);
1375 len = line.length - count;
1381 /*****************************************************************************
1382 * Function: _DtCvGetStartXOfLine
1384 * Purpose: Get the starting 'x' of the specified line
1385 * Does *not* take into account traversal or link info.
1386 *****************************************************************************/
1388 _DtCvGetStartXOfLine (
1390 _DtCvSegmentI **p_seg)
1392 *p_seg = line->seg_ptr;
1394 return line->text_x;
1397 /*****************************************************************************
1398 * Function: _DtCvAdvanceXOfLine
1400 * Purpose: Move the 'x' to after the traversal and link info.
1401 *****************************************************************************/
1403 _DtCvAdvanceXOfLine (
1404 _DtCanvasStruct *canvas,
1405 _DtCvSegmentI *p_seg,
1408 _DtCvValue *link_flag)
1413 * take into account the link before and after space
1415 junk = _DtCvIsSegVisibleLink(p_seg);
1416 *link_flag = _DtCvModifyXpos (canvas->link_info, p_seg, junk,
1417 *link_flag, *link_idx, &x_pos);
1420 * take into account the traversal before and after space
1422 junk = _DtCvIsSegALink(p_seg);
1423 (void) _DtCvModifyXpos (canvas->traversal_info, p_seg, junk,
1424 ((_DtCvValue) True), *link_idx, &x_pos);
1426 *link_idx = p_seg->link_idx;
1431 /******************************************************************************
1432 * Function: _DtCvGetWidthOfSegment
1434 * DetermineWidthOfSegment determines the width of the segment.
1435 * The segment must have been already initialized with the correct
1436 * font (for strings), the spc resolve, the graphic loaded, etc.
1438 *****************************************************************************/
1440 _DtCvGetWidthOfSegment(
1441 _DtCanvasStruct *canvas,
1442 _DtCvSegmentI *p_seg,
1447 _DtCvValue *ret_trimmed)
1452 * return the width of the segment.
1458 if (ret_trimmed != NULL)
1459 *ret_trimmed = False;
1461 if (!(_DtCvIsSegNoop(p_seg)))
1463 if (_DtCvIsSegRegion(p_seg))
1467 *ret_w = _DtCvWidthOfRegionSeg(p_seg);
1471 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(p_seg),
1472 _DtCvIsSegWideChar(p_seg), start);
1473 *ret_cnt = _DtCvStrLen (pChar, _DtCvIsSegWideChar(p_seg));
1474 if (*ret_cnt > max_cnt)
1477 if (ret_trimmed != NULL)
1478 *ret_trimmed = True;
1482 * determine the width of the string.
1485 *ret_w = _DtCvGetStringWidth(canvas, p_seg,pChar,*ret_cnt);
1490 /******************************************************************************
1491 * Function: _DtCvModifyXpos
1492 *****************************************************************************/
1495 _DtCvSpaceMetrics info,
1497 _DtCvValue tst_result,
1498 _DtCvValue cur_flag,
1505 * take into account the link before and after space
1510 * Ignore if the same link
1512 if (last_idx != seg->link_idx)
1515 * if one link followed by another add the space after.
1518 addx = info.space_after;
1521 * add the space before the link
1523 addx += info.space_before;
1529 if (last_idx != -1 && cur_flag == True)
1530 addx = info.space_after;
1538 /*****************************************************************************
1539 * Function: _DtCvAdjustForSuperSub
1542 * canvas Specifies the canvas.
1543 * start_x Specifies the current text x position.
1544 * script_x Specifies the current super and sub
1545 * scripting x position. Returns the same
1546 * value as start_x if the segment is not a
1547 * super or sub script.
1548 * super_width Specifies the width of the previously
1549 * rendered super script. Set to 0 if the
1550 * next segment is not a super or sub
1552 * super_y Specifies the y offset for super
1553 * scripts. Set to a new value if the last
1554 * segment was not a super or sub script.
1555 * sub_width Specifies the width of the previously
1556 * rendered sub script. Set to 0 if the
1557 * next segment is not a super or sub
1559 * sub_y Specifies the y offset for sub scripts.
1560 * Set to a new value if the last segment
1561 * was not a super or sub script.
1562 * last_was_super Specifies if the last item was a super
1563 * script. Set to False if the segment
1564 * is not a super or sub script.
1565 * last_was_sub Specifies if the last item was a sub
1566 * script. Set to False if the segment
1567 * is not a super or sub script.
1568 * Returns: new text x positon.
1570 * Purpose: Determines the super and sub scripting positions for text.
1571 * If the last item was not a script, then the base offset for
1572 * scripting (script_x) is moved to start_x. If the current
1573 * item is a string, its scripting y position is determined
1574 * (super_y and sub_y). If the new item is a super or sub
1575 * script, the next text placement (start_x) is moved to after
1576 * the script_x plus the super or sub script size currently
1577 * active(super_width and sub_width). Otherwise, the the flags
1578 * are set to false and the widths are set to 0.
1580 *****************************************************************************/
1582 _DtCvAdjustForSuperSub(
1583 _DtCanvasStruct *canvas,
1584 _DtCvSegmentI *pSeg,
1586 _DtCvUnit *script_x,
1587 _DtCvUnit *super_width,
1589 _DtCvUnit *sub_width,
1591 _DtCvValue *last_was_super,
1592 _DtCvValue *last_was_sub)
1595 * if the last item was not a super or sub script,
1596 * move the script x to the end of the last output.
1598 if (!(*last_was_super || *last_was_sub))
1599 *script_x = start_x;
1602 * check for super and sub scripts.
1603 * adjust text x positioning accordingly.
1605 if (_DtCvIsSegSuperScript(pSeg))
1607 start_x = *script_x + *super_width;
1608 *last_was_super = True;
1610 else if (_DtCvIsSegSubScript(pSeg))
1612 start_x = *script_x + *sub_width;
1613 *last_was_sub = True;
1615 else if (*last_was_super || *last_was_sub)
1619 *last_was_super = False;
1620 *last_was_sub = False;
1624 * if this wasn't a super or sub script, find out where
1625 * they get placed on this string.
1627 if (!(*last_was_super || *last_was_sub))
1629 if (_DtCvIsSegString(pSeg))
1630 _DtCvFontMetrics (canvas,_DtCvFontOfStringSeg(pSeg),
1631 NULL, NULL, NULL, super_y, sub_y);
1632 else if (_DtCvIsSegRegion(pSeg))
1634 *super_y = _DtCvHeightOfRegionSeg(pSeg) * 4 / 10;
1642 /******************************************************************************
1643 * Function: _DtCvDrawSegments
1646 * canvas Specifies the canvas on which to render
1648 * line Specifies the line metrics.
1649 * p_seg Specifies the starting segment.
1650 * start_char Specifies the starting index in a string
1651 * segment. 0 for all others.
1652 * count Specifies the number of characters
1653 * (including special characters to
1655 * prev_lnk Indicates the previous link index. Used
1656 * to calculate extra spacing needed for
1657 * traversal and link markup.
1658 * txt_x Specifies the starting x of the
1659 * segment(s). This does *NOT* take into
1660 * account traversal or link spacing. This
1661 * routine will do that. This is so
1662 * selected links will have correct spacing
1664 * sel_x Specifies where the selection x position
1665 * begins. Usually it equals txt_x, but
1666 * sometimes it will be less than it to
1667 * indicate blank space has been selected.
1668 * super_width Specifies the last super script x offset.
1669 * super_y Specifies the last super script y offset.
1670 * sub_width Specifies the last sub script x offset.
1671 * sub_y Specifies the last sub script y offset.
1672 * last_was_sub Specifies if the last element was a
1674 * last_was_super Specifies if the last element was a
1676 * last_was_vis Specifies if the last element was a
1677 * visible hypertext link.
1678 * old_flag Specifies what the line use to look like.
1679 * new_flag Specifies what the line is to look like.
1681 * Returns: txt_x Returns the maximum x unit processed.
1683 * Purpose: _DtCvDrawSegments draws one or more segments based on
1684 * the count passed in.
1686 * This routine adds CELink to new_flag when rendering segments
1687 * that are hypertext links. At the same time it will
1688 * determine the correct window hint and may place in old_flag
1689 * and new_flag either _DtCvLINK_POP_UP or _DtCvLINK_NEW_WINDOW.
1691 * This routine strips the _DtCvTRAVERSAL_END from old_flag and
1692 * new_flag (based on what's in new_flag). It will restore
1693 * these flags (if specified) when it renders the last element
1694 * in the count sequence.
1696 *****************************************************************************/
1699 _DtCanvasStruct *canvas,
1701 struct _dtCvSegment *p_seg,
1707 _DtCvUnit *script_x,
1708 _DtCvUnit *super_width,
1710 _DtCvUnit *sub_width,
1712 _DtCvValue *last_was_sub,
1713 _DtCvValue *last_was_super,
1714 _DtCvValue *last_link_vis,
1715 _DtCvFlags old_flag,
1716 _DtCvFlags new_flag,
1717 _DtCvElemType trav_type,
1718 _DtCvPointer trav_data )
1722 short cropped = _DtCvFALSE;
1723 short image_offset = _DtCvFALSE;
1727 _DtCvFlags saveEnd = new_flag &
1728 (_DtCvTRAVERSAL_END | _DtCvLINK_END | _DtCvMARK_END);
1729 _DtCvElemType elemType;
1730 _DtCvRenderInfo posInfo;
1731 _DtCvStringInfo strInfo;
1734 * skip any leading no-op lines
1736 while (p_seg != NULL && _DtCvIsSegNoop(p_seg))
1739 p_seg = p_seg->next_disp;
1743 * strip the any end info from the flags.
1744 * it will be put back on with the last element that makes up the count.
1746 old_flag &= ~saveEnd;
1747 new_flag &= ~saveEnd;
1750 * now process the segments included in 'count'
1752 while (p_seg != NULL && count > 0)
1755 * reset the baseline.
1756 * when processing super or sub scripts, this gets changed.
1758 yPos = line.baseline;
1761 * take into account the visible link and traversal info.
1763 txt_x = _DtCvAdvanceXOfLine(canvas, p_seg, txt_x,
1764 prev_lnk, last_link_vis);
1767 * check for super and sub scripts.
1768 * adjust text x positioning accordingly.
1770 txt_x = _DtCvAdjustForSuperSub(canvas, p_seg, txt_x,
1771 script_x, super_width, super_y,
1773 last_was_super, last_was_sub);
1778 * set visible link indicator flags
1780 _DtCvClearLinkFlags(old_flag);
1781 _DtCvClearLinkFlags(new_flag);
1784 * is this a visible link?
1786 if (_DtCvIsSegVisibleLink(p_seg))
1789 * visible link - set the flags.
1791 new_flag |= _DtCvLINK_FLAG;
1792 old_flag |= _DtCvLINK_FLAG;
1795 * is this the start of a new link? If so, set the begin flag.
1797 if (*prev_lnk != p_seg->link_idx)
1799 new_flag |= _DtCvLINK_BEGIN;
1800 old_flag |= _DtCvLINK_BEGIN;
1804 * get the link type and set the window hint.
1806 linkType = _DtLinkDbGetLinkType(canvas->link_data,p_seg->link_idx);
1807 switch (_DtLinkDbGetHint(canvas->link_data, p_seg->link_idx))
1809 case _DtCvWindowHint_PopupWindow:
1810 new_flag |= _DtCvLINK_POP_UP;
1811 old_flag |= _DtCvLINK_POP_UP;
1813 case _DtCvWindowHint_NewWindow:
1814 new_flag |= _DtCvLINK_NEW_WINDOW;
1815 old_flag |= _DtCvLINK_NEW_WINDOW;
1821 * rememeber this link index.
1823 *prev_lnk = p_seg->link_idx;
1826 * set the search flag
1828 _DtCvClearSearchFlags(old_flag);
1829 _DtCvClearSearchFlags(new_flag);
1831 old_flag |= (p_seg->type & _DtCvSEARCH_FLAG);
1832 new_flag |= (p_seg->type & _DtCvSEARCH_FLAG);
1834 if (0 == start_char)
1836 _DtCvSetSearchBegin(old_flag, p_seg);
1837 _DtCvSetSearchBegin(new_flag, p_seg);
1841 old_flag &= ~_DtCvAPP_FLAG2;
1842 new_flag &= ~_DtCvAPP_FLAG2;
1843 old_flag |= p_seg->type & _DtCvAPP_FLAG2;
1844 new_flag |= p_seg->type & _DtCvAPP_FLAG2;
1846 old_flag &= ~(_DtCvAPP_FLAG3 | _DtCvAPP_FLAG4);
1847 new_flag &= ~(_DtCvAPP_FLAG3 | _DtCvAPP_FLAG4);
1850 * init some variables
1856 * adjust the yPos for sub/superscripts.
1858 if (_DtCvIsSegSuperScript(p_seg))
1860 else if (_DtCvIsSegSubScript(p_seg))
1864 switch (_DtCvPrimaryTypeOfSeg(p_seg))
1870 elemType = _DtCvSTRING_TYPE;
1873 * get the string and its length.
1875 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(p_seg),
1876 _DtCvIsSegWideChar(p_seg), start_char);
1877 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(p_seg));
1880 * if length of the string is longer than we want to
1886 cropped = _DtCvTRUE;
1890 * initialize the string structure.
1892 strInfo.string = pChar;
1893 strInfo.byte_len = len;
1894 strInfo.wc = _DtCvIsSegWideChar(p_seg);
1895 strInfo.font_ptr = _DtCvFontOfStringSeg(p_seg);
1896 strInfo.csd = p_seg->client_use;
1899 * now get the width of the string to update the x positions
1901 segWidth = _DtCvGetStringWidth(canvas, p_seg, pChar, len);
1904 * attach the string information to the position info.
1906 posInfo.info = &strInfo;
1909 * reset starting index.
1916 * set the type, length and width
1918 elemType = _DtCvREGION_TYPE;
1920 segWidth = _DtCvWidthOfRegionSeg(p_seg);
1923 * attach the region information to the position info.
1925 posInfo.info = _DtCvInfoOfRegionSeg(p_seg);
1931 * do we have valid information?
1936 * now set up the position information
1938 posInfo.box_x = sel_x;
1939 posInfo.box_y = line.baseline - line.ascent;
1940 posInfo.box_height = line.ascent + line.descent + 1;
1941 posInfo.box_width = segWidth;
1944 * if this is the last segment to be rendered,
1945 * restore the end flags.
1949 new_flag |= saveEnd;
1950 old_flag |= saveEnd;
1955 * if the item (string) was not cropped, set the Search end
1958 if (_DtCvFALSE == cropped)
1960 _DtCvSetSearchEnd(old_flag, p_seg);
1961 _DtCvSetSearchEnd(new_flag, p_seg);
1963 if (new_flag & _DtCvSEARCH_END && new_flag & _DtCvAPP_FLAG2 &&
1964 !(new_flag & _DtCvSELECTED_FLAG)) {
1965 new_flag |= _DtCvAPP_FLAG4;
1969 if (image_offset == _DtCvTRUE) {
1970 old_flag |= _DtCvAPP_FLAG3;
1971 new_flag |= _DtCvAPP_FLAG3;
1972 image_offset = _DtCvFALSE;
1976 * render the element
1978 if (NULL != canvas->virt_functions.render_elem)
1979 (*(canvas->virt_functions.render_elem))(
1980 canvas->client_data, elemType,
1982 linkType, old_flag, new_flag,
1983 trav_type, trav_data, &posInfo);
1985 if (cropped == _DtCvFALSE && new_flag & _DtCvSEARCH_END
1986 && new_flag & _DtCvAPP_FLAG2
1987 && !(new_flag & _DtCvSELECTED_FLAG))
1988 image_offset = _DtCvTRUE;
1992 * strip the any begin flags.
1994 _DtCvRemoveBeginFlags(old_flag);
1995 _DtCvRemoveBeginFlags(new_flag);
1998 * take into account subscripting and superscripting.
2000 if (_DtCvIsSegSuperScript(p_seg))
2001 *super_width += segWidth;
2002 else if (_DtCvIsSegSubScript(p_seg))
2003 *sub_width += segWidth;
2006 * adjust the pointers
2012 p_seg = p_seg->next_disp;
2017 } /* End _DtCvDrawSegments */
2019 /*****************************************************************************
2021 *****************************************************************************/
2022 /*****************************************************************************
2023 * Function: _DtCvHandle _DtCanvasCreate (_DtCvVirtualInfo virt_info);
2026 * virt_info Specifies the virtual functions to attach
2027 * to the created canvas.
2029 * Returns: A handle to the canvas or NULL if an error occurs.
2031 * Purpose: Create a canvas and attach the appropriate virtual functions
2033 *****************************************************************************/
2036 _DtCvVirtualInfo virt_info,
2037 _DtCvPointer client_data)
2039 _DtCanvasStruct *newCanvas;
2041 newCanvas = (_DtCanvasStruct *) malloc (sizeof (_DtCanvasStruct));
2042 if (newCanvas == NULL)
2045 *newCanvas = DefaultCanvas;
2046 newCanvas->virt_functions = virt_info;
2047 newCanvas->client_data = client_data;
2048 newCanvas->mb_length = MB_CUR_MAX;
2053 _DtCanvasLoadMetrics((_DtCvHandle)newCanvas);
2055 return ((_DtCvHandle)(newCanvas));
2057 } /* End _DtCanvasCreate */
2059 void _DtCanvasLoadMetrics(_DtCvHandle handle)
2061 _DtCanvasStruct *canvas = (_DtCanvasStruct*)handle;
2062 (*(canvas->virt_functions.get_metrics))(canvas->client_data,
2063 _DtCvCANVAS_TYPE, &(canvas->metrics));
2064 (*(canvas->virt_functions.get_metrics))(canvas->client_data,
2065 _DtCvLINK_TYPE, &(canvas->link_info));
2066 (*(canvas->virt_functions.get_metrics))(canvas->client_data,
2067 _DtCvTRAVERSAL_TYPE, &(canvas->traversal_info));
2069 (*(canvas->virt_functions.get_metrics))(canvas->client_data,
2070 _DtCvLOCALE_TYPE, &(canvas->locale));
2073 /*****************************************************************************
2074 * Function: void _DtCanvasClean (_DtCvHandle canvas_handle);
2077 * canvas Specifies the handle for the canvas.
2079 * Returns: A handle to the canvas or NULL if an error occurs.
2081 * Purpose: Create a canvas and attach the appropriate virtual functions
2083 *****************************************************************************/
2085 _DtCanvasClean (_DtCvHandle canvas_handle)
2087 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
2090 * clean the selection
2092 _DtCanvasProcessSelection (canvas_handle, 0, 0, _DtCvSELECTION_CLEAR);
2097 canvas->txt_cnt = 0;
2098 canvas->line_cnt = 0;
2099 canvas->mark_cnt = 0;
2100 canvas->trav_cnt = 0;
2101 canvas->search_cnt = 0;
2102 canvas->brk_cnt = 0;
2105 * reset some indicators
2108 canvas->cur_trav = -1;
2111 * free the internal use structures.
2113 _DtCvClearInternalUse(canvas->element_lst, _DtCvTRUE);
2114 canvas->element_lst = NULL;
2115 canvas->link_data = NULL;
2117 } /* End _DtCanvasClean */
2119 /*****************************************************************************
2120 * Function: void _DtCanvasDestroy (_DtCvHandle canvas_handle);
2123 * canvas Specifies the handle for the canvas.
2125 * Returns: A handle to the canvas or NULL if an error occurs.
2127 * Purpose: Create a canvas and attach the appropriate virtual functions
2129 *****************************************************************************/
2131 _DtCanvasDestroy (_DtCvHandle canvas_handle)
2133 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
2135 _DtCanvasClean (canvas_handle);
2137 if (NULL != canvas->txt_lst)
2138 free ((void *) canvas->txt_lst);
2139 if (NULL != canvas->line_lst)
2140 free ((void *) canvas->line_lst);
2141 if (NULL != canvas->trav_lst)
2142 free ((void *) canvas->trav_lst);
2143 if (NULL != canvas->marks)
2144 free ((void*) canvas->marks);
2145 if (NULL != canvas->searchs)
2146 free ((void*) canvas->searchs);
2147 if (NULL != canvas->pg_breaks)
2148 free ((void*) canvas->pg_breaks);
2150 free ((void *) canvas);
2153 } /* End _DtCanvasDestroy */
2155 /*****************************************************************************
2156 * Function: void _DtCanvasRender (_DtCvHandle canvas_handle);
2159 * canvas Specifies the handle for the canvas.
2161 * Returns: A handle to the canvas or NULL if an error occurs.
2165 *****************************************************************************/
2168 _DtCvHandle canvas_handle,
2173 _DtCvRenderType flag,
2174 _DtCvValue pg_break,
2179 _DtCvUnit lastY = 0;
2180 _DtCvUnit nextY = -1;
2183 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
2184 _DtCvDspLine *lines;
2188 * check the list of page breaks, it may constrain y2
2190 if (_DtCvTRUE == pg_break && 0 != canvas->brk_cnt)
2193 while (y1 > canvas->pg_breaks[i]) i++;
2195 if (i < canvas->brk_cnt && y2 > canvas->pg_breaks[i])
2196 y2 = canvas->pg_breaks[i];
2200 * Draw the lines first, they may constrain y2
2202 DrawCanvasLines (canvas, x1, y1, x2, y2, flag, &lastY, &nextY);
2204 if (-1 != nextY && y2 > nextY)
2208 * clear the processed flag from all the text lines.
2210 for (i = 0; i < canvas->txt_cnt; i++)
2211 _DtCvClearProcessed(canvas->txt_lst[i]);
2213 for (lines = canvas->txt_lst, i = 0;
2214 NULL != lines && i < canvas->txt_cnt; lines++, i++)
2217 * get the minimum and maximum y of the next line
2219 minY = lines->baseline - lines->ascent;
2220 maxY = lines->baseline + lines->descent;
2223 * is this line on the 'page'?
2224 * Does it hang off the 'page' (and if so is it allowed)?
2226 sideCk = _DtCvSTATUS_NONE;
2227 if (_DtCvIsNotProcessed(*lines) && maxY >= y1 && minY <= y2 &&
2228 (_DtCvRENDER_PARTIAL == flag ||
2230 _DtCvTRUE != (sideCk = CheckAround(canvas->txt_lst, canvas->txt_cnt, i, y2)))))
2232 (void) DrawText (canvas, lines, i, 0, 0);
2235 * indicate that this line has been rendered.
2237 _DtCvSetProcessed(*lines);
2240 * if doing complete printing, get any other lines that exist
2241 * next to this one, but don't fit the [y1,y2] pair. This will
2242 * catch scrolling problems using _DtCvRENDER_COMPLETE.
2244 * The previous CheckAround() call will have set sideCk to
2245 * _DtCvFALSE if there are other items to the side, but these
2246 * items did not violate the maximum y.
2248 * sideCk will be _DtCvSTATUS_NONE if there is nothing to the
2249 * side for _DtCvRENDER_COMPLETE or if flag is _DtCvRENDER_PARTIAL.
2251 if (_DtCvFALSE == sideCk)
2252 RenderSubSet(canvas, canvas->txt_lst, canvas->txt_cnt,
2253 minY, maxY, &lastY);
2256 * is this the maximum that we've rendered?
2262 * otherwise, would this 'start' the next 'page'?
2264 * a) the render type is _DtCvRENDER_PARTIAL but the top of the
2265 * text(minY) is beyound y2 (and so would maxY).
2266 * b) the render type is _DtCvRENDER_COMPLETE and the line is
2267 * split across a page boundary (maxY greater than y2).
2268 * c) the render type is _DtCvRENDER_COMPLETE and there is text
2269 * to the side of this text and it is split across a page
2270 * boundary (sideCk == _DtCvTRUE).
2272 else if ((-1 == nextY || nextY > minY) &&
2273 (maxY > y2 || _DtCvTRUE == sideCk))
2278 * if doing _DtCvRENDER_PARTIAL, lastY will end up larger than
2279 * actually rendered. So set it back.
2285 * return the values if the user asked for them.
2293 } /* End _DtCanvasRender */
2295 /*****************************************************************************
2296 * Function: void _DtCanvasMoveTraversal ()
2299 * canvas Specifies the handle for the canvas.
2301 * Returns: A handle to the canvas or NULL if an error occurs.
2305 *****************************************************************************/
2307 _DtCanvasMoveTraversal (
2308 _DtCvHandle canvas_handle,
2309 _DtCvTraversalCmd cmd,
2315 _DtCvUnit *ret_baseline,
2316 _DtCvUnit *ret_height)
2319 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
2321 if (0 == canvas->trav_cnt)
2322 return _DtCvSTATUS_NONE;
2324 newIndex = canvas->cur_trav;
2330 case _DtCvTRAVERSAL_TOP:
2334 case _DtCvTRAVERSAL_NEXT:
2336 if (newIndex >= canvas->trav_cnt)
2344 case _DtCvTRAVERSAL_PREV:
2350 newIndex = canvas->trav_cnt - 1;
2354 case _DtCvTRAVERSAL_BOTTOM:
2355 newIndex = canvas->trav_cnt - 1;
2358 case _DtCvTRAVERSAL_ID:
2359 case _DtCvTRAVERSAL_MARK:
2364 _DtCvValue found = False;
2367 while (False == found && newIndex < canvas->trav_cnt)
2369 if (_DtCvTRAVERSAL_ID == cmd &&
2370 _DtCvTraversalLink ==
2371 canvas->trav_lst[newIndex].type)
2373 idx = canvas->trav_lst[newIndex].seg_ptr->link_idx;
2374 lnkId = _DtLinkDbGetLinkSpec(canvas->link_data,
2377 if (_DtCvStrCaseCmpLatin1(lnkId, rid) == 0)
2380 else if (_DtCvTRAVERSAL_MARK == cmd &&
2381 _DtCvTraversalMark == canvas->trav_lst[newIndex].type)
2383 idx = canvas->trav_lst[newIndex].idx;
2384 if (rid == canvas->marks[idx].client_data)
2393 return _DtCvSTATUS_BAD;
2399 * turn off the old traversal
2401 if (cmd == _DtCvTRAVERSAL_OFF)
2403 if (-1 != canvas->cur_trav)
2404 DrawTraversalIndicator (canvas, render, False,
2405 NULL, NULL, NULL, NULL);
2406 canvas->trav_on = _DtCvFALSE;
2409 * turn off the old traversal and turn on the new one.
2411 else if (newIndex != canvas->cur_trav)
2413 if (-1 != canvas->cur_trav)
2414 DrawTraversalIndicator (canvas, render, False,
2415 NULL, NULL, NULL, NULL);
2417 canvas->cur_trav = newIndex;
2418 DrawTraversalIndicator (canvas, render, True,
2419 ret_x, ret_y, ret_baseline, ret_height);
2420 canvas->trav_on = _DtCvTRUE;
2421 return _DtCvSTATUS_OK;
2424 * Other wise turn on the traversal
2426 else if (cmd == _DtCvTRAVERSAL_ON && -1 != canvas->cur_trav)
2428 DrawTraversalIndicator (canvas, render, True,
2429 ret_x, ret_y, ret_baseline, ret_height);
2430 canvas->trav_on = _DtCvTRUE;
2431 return _DtCvSTATUS_OK;
2434 return _DtCvSTATUS_NONE;
2437 /*****************************************************************************
2438 * Function: void _DtCanvasGetPosLink (_DtCvHandle canvas_handle,
2439 * _DtCvUnit x, _DtCvUnit y);
2442 * canvas Specifies the handle for the canvas.
2444 * Returns: A handle to the canvas or NULL if an error occurs.
2448 *****************************************************************************/
2450 _DtCanvasGetPosLink (
2451 _DtCvHandle canvas_handle,
2456 _DtCvLinkInfo *ret_info)
2469 _DtCvStatus found = _DtCvSTATUS_NONE;
2470 _DtCvSegmentI *pSeg = NULL;
2471 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
2472 _DtCvTraversalInfo *lnkSegs = canvas->trav_lst;
2474 if (0 == canvas->trav_cnt)
2475 return _DtCvSTATUS_NONE;
2480 while (line < canvas->txt_cnt && _DtCvSTATUS_NONE == found)
2482 topY = canvas->txt_lst[line].baseline - canvas->txt_lst[line].ascent;
2483 botY = canvas->txt_lst[line].baseline + canvas->txt_lst[line].descent;
2484 startX = canvas->txt_lst[line].text_x;
2487 * make sure the requested link is on this line.
2489 if (topY <= y1 && y1 <= botY && startX <= x1 &&
2490 x1 <= canvas->txt_lst[line].max_x)
2493 _DtCvValue lstVisible = False;
2495 count = canvas->txt_lst[line].length;
2496 pSeg = canvas->txt_lst[line].seg_ptr;
2497 startChar = canvas->txt_lst[line].byte_index;
2499 while (count > 0 && _DtCvSTATUS_NONE == found)
2502 * adjust the starting position by the link space
2504 junk = _DtCvIsSegVisibleLink(pSeg);
2505 lstVisible = _DtCvModifyXpos (canvas->link_info, pSeg,
2506 junk, lstVisible, lnkIndx, &startX);
2508 * adjust the starting position by the traversal space
2510 junk = _DtCvIsSegALink(pSeg);
2511 (void) _DtCvModifyXpos (canvas->traversal_info, pSeg,
2512 junk, ((_DtCvValue) True), lnkIndx, &startX);
2514 lnkIndx = pSeg->link_idx;
2519 if (_DtCvIsSegNoop(pSeg))
2524 else if (_DtCvIsSegRegion(pSeg))
2527 endX = startX + _DtCvWidthOfRegionSeg(pSeg);
2532 * initialize the pointer to the string
2534 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
2535 _DtCvIsSegWideChar(pSeg), startChar);
2538 * get the length of the current string.
2539 * If it is longer than the line count indicates,
2540 * it must be wrapped to the next line. We are
2541 * only interested in in the part of the line
2542 * that is on the line selected.
2544 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
2549 * calculate the ending pixel postion for
2550 * this string segment.
2552 endX = startX + _DtCvGetStringWidth(canvas, pSeg,
2557 * test to see if the selected segment was this segment.
2559 if (x1 >= startX && x1 < endX && x2 >= startX && x2 < endX)
2561 found = _DtCvSTATUS_OK;
2563 * Find the hypertext entry.
2566 while (travIdx < canvas->trav_cnt
2567 && _DtCvTraversalLink == lnkSegs->type
2568 && lnkSegs->seg_ptr->link_idx != pSeg->link_idx)
2577 * go to the next segment.
2579 pSeg = pSeg->next_disp;
2582 * adjust for the new begining.
2585 count = count - len;
2594 * check to see if we found a segment and
2595 * see if it is a hypertext segment
2597 if (_DtCvSTATUS_OK == found)
2599 found = _DtCvSTATUS_NONE;
2600 if (_DtCvIsSegALink(pSeg) &&
2601 _DtLinkDbGetLinkInfo(canvas->link_data, pSeg->link_idx,
2602 canvas->virt_functions.exec_cmd_filter,
2603 canvas->client_data, ret_info) == 0)
2605 ret_info->offset_x = x1 - startX;
2606 ret_info->offset_y = y1 - topY;
2607 found = _DtCvSTATUS_OK;
2613 } /* End _DtCanvasGetPosLink */
2615 /*****************************************************************************
2616 * Function: void _DtCanvasGetCurLink ()
2619 * canvas Specifies the handle for the canvas.
2621 * Returns: A handle to the canvas or NULL if an error occurs.
2625 *****************************************************************************/
2627 _DtCanvasGetCurLink (
2628 _DtCvHandle canvas_handle,
2629 _DtCvLinkInfo *ret_info)
2631 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
2632 _DtCvSegmentI *pSeg;
2633 int curTrav = canvas->cur_trav;
2636 * if there isn't any traversal entry or it is a mark, return nothing.
2638 if (0 == canvas->trav_cnt || -1 == curTrav ||
2639 _DtCvTraversalMark == canvas->trav_lst[curTrav].type)
2640 return _DtCvSTATUS_NONE;
2643 * otherwise this is a hypertext link
2645 if (NULL != ret_info &&
2646 _DtCvTraversalLink == canvas->trav_lst[curTrav].type)
2648 pSeg = canvas->trav_lst[curTrav].seg_ptr;
2649 if (_DtLinkDbGetLinkInfo(canvas->link_data, pSeg->link_idx,
2650 canvas->virt_functions.exec_cmd_filter,
2651 canvas->client_data, ret_info) == 0)
2652 return _DtCvSTATUS_OK;
2655 return _DtCvSTATUS_BAD;
2658 /*****************************************************************************
2659 * Function: void _DtCanvasGetCurTraversal ()
2662 * canvas Specifies the handle for the canvas.
2664 * Returns: A handle to the canvas or NULL if an error occurs.
2668 *****************************************************************************/
2670 _DtCanvasGetCurTraversal (
2671 _DtCvHandle canvas_handle,
2672 _DtCvLinkInfo *ret_info,
2673 _DtCvPointer *ret_data)
2675 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
2676 _DtCvSegmentI *pSeg;
2677 int curTrav = canvas->cur_trav;
2680 * if there isn't any traversal entry, return nothing.
2682 if (0 == canvas->trav_cnt || -1 == curTrav)
2683 return _DtCvSTATUS_NONE;
2686 * if this is a mark, return the client data.
2688 if (NULL != ret_data &&
2689 _DtCvTraversalMark == canvas->trav_lst[curTrav].type)
2691 *ret_data = canvas->marks[canvas->trav_lst[curTrav].idx].client_data;
2692 return _DtCvSTATUS_MARK;
2696 * otherwise this is a hypertext link
2698 if (NULL != ret_info &&
2699 _DtCvTraversalLink == canvas->trav_lst[curTrav].type)
2701 pSeg = canvas->trav_lst[curTrav].seg_ptr;
2702 if (_DtLinkDbGetLinkInfo(canvas->link_data, pSeg->link_idx,
2703 canvas->virt_functions.exec_cmd_filter,
2704 canvas->client_data, ret_info) == 0)
2705 return _DtCvSTATUS_LINK;
2708 return _DtCvSTATUS_BAD;
2712 /*****************************************************************************
2713 * Function: void _DtCanvasGetSpotInfo (_DtCvHandle canvas_handle,
2714 * _DtCvUnit x, _DtCvUnit y);
2717 * canvas Specifies the handle for the canvas.
2719 * Returns: _DtCvSTATUS_OK if a segment was found at x, y.
2720 * _DtCvSTATUS_NONE if no segment found at that location.
2724 *****************************************************************************/
2726 _DtCanvasGetSpotInfo (
2727 _DtCvHandle canvas_handle,
2730 _DtCvSegment **ret_seg,
2731 _DtCvUnit *ret_offx,
2732 _DtCvUnit *ret_offy,
2733 _DtCvElemType *ret_elem)
2745 _DtCvStatus found = _DtCvSTATUS_NONE;
2746 _DtCvSegmentI *pSeg = NULL;
2747 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
2749 if (NULL != ret_seg)
2755 while (line < canvas->txt_cnt && _DtCvSTATUS_NONE == found)
2757 topY = canvas->txt_lst[line].baseline - canvas->txt_lst[line].ascent;
2758 botY = canvas->txt_lst[line].baseline + canvas->txt_lst[line].descent;
2759 startX = canvas->txt_lst[line].text_x;
2762 * make sure the requested link is on this line.
2764 if (topY <= y && y <= botY && startX <= x &&
2765 x <= canvas->txt_lst[line].max_x)
2768 _DtCvValue lstVisible = False;
2770 count = canvas->txt_lst[line].length;
2771 pSeg = canvas->txt_lst[line].seg_ptr;
2772 startChar = canvas->txt_lst[line].byte_index;
2774 while (count > 0 && _DtCvSTATUS_NONE == found)
2777 * adjust the starting position by the link space
2779 junk = _DtCvIsSegVisibleLink(pSeg);
2780 lstVisible = _DtCvModifyXpos (canvas->link_info, pSeg,
2781 junk, lstVisible, lnkIndx, &startX);
2783 * adjust the starting position by the traversal space
2785 junk = _DtCvIsSegALink(pSeg);
2786 (void) _DtCvModifyXpos (canvas->traversal_info, pSeg,
2787 junk, ((_DtCvValue) True), lnkIndx, &startX);
2789 lnkIndx = pSeg->link_idx;
2794 if (_DtCvIsSegNoop(pSeg))
2799 else if (_DtCvIsSegRegion(pSeg))
2802 endX = startX + _DtCvWidthOfRegionSeg(pSeg);
2807 * initialize the pointer to the string
2809 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
2810 _DtCvIsSegWideChar(pSeg), startChar);
2813 * get the length of the current string.
2814 * If it is longer than the line count indicates,
2815 * it must be wrapped to the next line. We are
2816 * only interested in in the part of the line
2817 * that is on the line selected.
2819 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
2824 * calculate the ending pixel postion for
2825 * this string segment.
2827 endX = startX + _DtCvGetStringWidth(canvas, pSeg,
2832 * test to see if the selected segment was this segment.
2834 if (x >= startX && x < endX)
2835 found = _DtCvSTATUS_OK;
2839 * go to the next segment.
2841 pSeg = pSeg->next_disp;
2844 * adjust for the new begining.
2847 count = count - len;
2856 * check to see if we found a segment.
2858 if (_DtCvSTATUS_OK == found)
2860 *ret_elem = _DtCvREGION_TYPE;
2861 if (_DtCvIsSegString(pSeg))
2862 *ret_elem = _DtCvSTRING_TYPE;
2864 if (NULL != ret_seg)
2866 if (NULL != ret_offx)
2867 *ret_offx = x - startX;
2868 if (NULL != ret_offy)
2869 *ret_offy = y - topY;
2874 } /* End _DtCanvasGetPosition */