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 "VirtFuncsI.h"
69 /******** Private Function Declarations ********/
70 static _DtCvUnit DrawText(
71 _DtCanvasStruct *canvas,
75 _DtCvFlags new_flag );
76 /******** End Private Function Declarations ********/
78 /*****************************************************************************
80 *****************************************************************************/
81 static _DtCanvasStruct DefaultCanvas =
86 0, /* int line_cnt; */
87 0, /* int line_max; */
88 0, /* int mark_cnt; */
89 0, /* int mark_max; */
90 0, /* int trav_cnt; */
91 0, /* int trav_max; */
92 0, /* int cur_trav; */
97 1, /* short mb_length; */
98 0, /* _DtCvUnit max_x; */
99 0, /* _DtCvUnit max_y; */
100 _DtCvIGNORE_BOUNDARY, /* _DtCvValue constraint; */
101 _DtCvFALSE, /* _DtCvValue trav_on; */
102 NULL, /* _DtCvPointer client_data; */
103 { /* CanvasMetrics metrics; */
104 0, /* _DtCvUnit width; */
105 0, /* _DtCvUnit height; */
106 0, /* _DtCvUnit top_margin; */
107 0, /* _DtCvUnit line_height; */
108 0, /* _DtCvUnit horiz_pad_hint; */
110 { /* _DtCvSpaceMetrics link_info; */
111 0, /* _DtCvUnit space_before; */
112 0, /* _DtCvUnit space_after; */
113 0, /* _DtCvUnit space_above; */
114 0, /* _DtCvUnit space_below; */
116 { /* _DtCvSpaceMetrics traversal_info; */
117 0, /* _DtCvUnit space_before; */
118 0, /* _DtCvUnit space_after; */
119 0, /* _DtCvUnit space_above; */
120 0, /* _DtCvUnit space_below; */
122 { /* _DtCvLocale locale; */
123 _DtCvModeWrapNone, /* _DtCvModeType line_wrap_mode; */
124 NULL, /* const wchar_t *cant_begin_chars; */
125 NULL, /* const wchar_t *cant_end_chars; */
127 NULL, /* _DtCvSegment *element_lst; */
128 NULL, /* _DtCvDspLine *txt_lst; */
129 NULL, /* _DtCvLineSeg *line_lst; */
130 NULL, /* _DtCvTraversalInfo *trav_lst; */
131 NULL, /* _DtCvLinkDb link_data; */
132 { /* CESelection select_start; */
133 -1, /* _DtCvUnit x; */
134 -1, /* _DtCvUnit y; */
135 -1, /* int line_idx; */
136 -1, /* int char_idx; */
138 { /* CESelection select_end; */
139 -1, /* _DtCvUnit x; */
140 -1, /* _DtCvUnit y; */
141 -1, /* int line_idx; */
142 -1, /* int char_idx; */
144 NULL, /* _DtCvMarkData *marks; */
146 NULL, /* pg_breaks */
147 NULL, /* _DtCvVirtualInfo virt_functions; */
150 /*****************************************************************************
152 *****************************************************************************/
153 /*****************************************************************************
154 * Function: RenderSubSet
157 * Purpose: Render the items next to an item of text.
159 *****************************************************************************/
162 _DtCanvasStruct *canvas,
174 * Loop through the list looking for the item(s) next to the text.
176 for (i = 0; NULL != lines && i < cnt; lines++, i++)
179 * get the minimum and maximum y of the next line
181 minY = lines->baseline - lines->ascent;
182 maxY = lines->baseline + lines->descent;
185 * has this line been reviewed yet?
186 * is this line on the 'page'?
187 * Does it hang off the 'page' (and if so is it allowed)?
189 if (_DtCvIsNotProcessed(*lines) && maxY >= y1 && maxY <= y2)
191 (void) DrawText (canvas, lines, i, 0, 0);
194 * indicate that this line has been rendered.
196 _DtCvSetProcessed(*lines);
199 * is this the maximum that we've rendered?
205 * now render anything next to this!
207 RenderSubSet(canvas, canvas->txt_lst, cnt, minY, y2, last_y);
212 /*****************************************************************************
213 * Function: CheckAround
215 * Returns: _DtCvSTATUS_NONE if no other text is to the side of
217 * _DtCvFALSE if other text is to the side, but the
218 * maximum y position is not violated.
219 * _DtCvTRUE if other text is to the side and the
220 * maximum y position is violated.
221 * Purpose: Find if another line of text intrudes upon this line.
223 *****************************************************************************/
232 _DtCvUnit topY = lines[idx].baseline - lines[idx].ascent;
233 _DtCvUnit botY = lines[idx].baseline + lines[idx].descent;
236 _DtCvStatus result = _DtCvSTATUS_NONE;
239 * set the processed flag so that we don't test something that's
242 _DtCvSetProcessed(lines[idx]);
245 * go through looking for unprocessed lines to test.
247 while (i < cnt && _DtCvTRUE != result)
249 if (_DtCvIsNotProcessed(lines[i]))
252 * calculate the minimum and maximum y positions for the line.
254 minY = lines[i].baseline - lines[i].ascent;
255 maxY = lines[i].baseline + lines[i].descent;
258 * Does this line infringe vertically on the test line?
260 if (maxY > topY && minY < botY &&
261 _DtCvTRUE == _DtCvCheckInfringement(topY, botY, minY, maxY))
264 * indicate that it is not clear to the side.
269 * Does it have something else infringing one it?
270 * Or does it hang down below the test line?
272 if (maxY > y2 || _DtCvTRUE == CheckAround(lines, cnt, i, y2))
281 * Clear that this line has be processed. Otherwise, rendering will
282 * think this has been rendered when it hasn't.
284 _DtCvClearProcessed(lines[idx]);
289 /*****************************************************************************
292 * FindChar calculates the char that is x pixels into the string.
294 *****************************************************************************/
297 _DtCanvasStruct *canvas,
298 _DtCvSegmentI *segment,
305 _DtCvUnit myDiff = 0;
308 _DtCvValue triedBack = False;
309 _DtCvValue triedForward = False;
312 * get information about the font used
314 _DtCvFontMetrics(canvas, _DtCvFontOfStringSeg(segment),
315 NULL, NULL, &charWidth, NULL, NULL);
318 * try to get close to the correct index.
320 myIndex = x_pos / charWidth;
321 if (myIndex >= max_len)
322 myIndex = max_len - 1;
324 while (!triedBack || !triedForward)
326 len = _DtCvGetStringWidth(canvas, segment, string, myIndex + 1);
330 myDiff = len - x_pos;
332 if (!triedBack && myIndex)
337 else if (len < x_pos)
339 myDiff = x_pos - len;
342 if (myIndex >= max_len)
348 else /* len == x_pos */
363 /*****************************************************************************
364 * Function: DrawCanvasLines
366 *****************************************************************************/
369 _DtCanvasStruct *canvas,
374 _DtCvRenderType flag,
379 _DtCvUnit newY2 = y2;
381 _DtCvLineInfo lnInfo;
384 * are there any lines?
386 if (canvas->line_lst != NULL && canvas->line_cnt &&
387 NULL != canvas->virt_functions.render_elem)
390 * find the maximum y of all the lines that fit in the page.
391 * do this only if the flag indicates whole lines.
393 if (_DtCvRENDER_COMPLETE == flag)
395 for (i = 0, pLS = canvas->line_lst;
396 i < canvas->line_cnt; i++, pLS++)
399 * Does this line end off the page?
401 if (pLS->max_y > newY2 && pLS->pos_y < newY2)
402 newY2 = pLS->pos_y - 1;
407 * check each line to see if it is on the 'page'
409 for (i = 0, pLS = canvas->line_lst; i < canvas->line_cnt; i++, pLS++)
411 lnInfo.width = pLS->width;
412 lnInfo.data = pLS->data;
413 lnInfo.x2 = pLS->pos_x;
414 lnInfo.y2 = pLS->pos_y;
417 * horizontal or vertial line?
419 if (_DtCvLINE_HORZ == pLS->dir)
420 lnInfo.x2 = pLS->max_x;
422 lnInfo.y2 = pLS->max_y;
425 * does it fit on the page? Take into account the rendering type.
427 if (pLS->max_y >= y1 && pLS->pos_y <= newY2
428 && lnInfo.x2 >= x1 && pLS->pos_x <= x2
429 && (_DtCvRENDER_PARTIAL == flag || pLS->max_y <= newY2))
431 if (pLS->max_y > *ret_y)
434 (*(canvas->virt_functions.render_elem))(
435 canvas->client_data, _DtCvLINE_TYPE,
436 pLS->pos_x, pLS->pos_y, -1, 0, 0,
437 _DtCvBAD_TYPE, NULL, &lnInfo);
440 * otherwise, would this start the next page?
441 * make sure this is in the horizontal space.
443 else if (lnInfo.x2 >= x1 && pLS->pos_x <= x2 && pLS->max_y > newY2
444 && (-1 == *ret_next || *ret_next > pLS->pos_y))
445 *ret_next = pLS->pos_y;
448 } /* End DrawCanvasLines */
450 /******************************************************************************
454 * canvas Specifies the canvas on which to render
456 * line Specifies the line in the line table.
457 * start_x Specifies the starting x position to use
458 * for selected text. If greater than the
459 * starting position for the segment, determine
460 * the closest character to 'start_x' and
462 * end_x Specifies the ending x position to use
463 * for selected text. If -1, means display
464 * the entire set of segments.
465 * old_flag Specifies....
466 * new_flag Specifies....
468 * Returns: max_x Returns the maximum x unit processed.
470 * Purpose: DrawText draws text segments on one line in the
473 *****************************************************************************/
476 _DtCanvasStruct *canvas,
480 _DtCvFlags new_flag )
485 int count = line->length;
486 int start = line->byte_index;
488 _DtCvUnit superWidth = 0;
489 _DtCvUnit superY = 0;
490 _DtCvUnit subWidth = 0;
492 _DtCvUnit scriptX = 0;
493 _DtCvValue lastWasSuper = False;
494 _DtCvValue lastWasSub = False;
495 _DtCvValue lastLnkVis = False;
498 xPos = _DtCvGetStartXOfLine(line, &pSeg);
501 * get the corrected x for links and traversals.
503 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos, &lastLnk, &lastLnkVis);
506 * take into account the if this is a super or sub script - or not.
508 xPos = _DtCvAdjustForSuperSub(canvas, pSeg, xPos,
509 &scriptX, &superWidth, &superY,
511 &lastWasSuper, &lastWasSub);
513 * now process the line
515 while (NULL != pSeg && 0 < count)
520 * check for selected and marked text.
522 _DtCvCheckLineMarks(canvas, txt_line, curIdx, count, xPos,
523 (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
524 &len, &old_flag, &new_flag);
527 * if this is the last segment(s) of the (un)selection
532 new_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
533 old_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
537 * render the segment length returned by _DtCvCheckLineMarks
539 xPos = _DtCvDrawSegments(canvas, *line, pSeg, start, len,
540 &lastLnk, xPos, xPos,
541 &scriptX, &superWidth, &superY, &subWidth,
542 &subY, &lastWasSub, &lastWasSuper,
543 &lastLnkVis, old_flag, new_flag,
544 _DtCvBAD_TYPE, NULL);
546 * decrement the count by the length processed
551 _DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
559 /*****************************************************************************
560 * Function: IsLineSpecial (
562 * Purpose: Call a virtual function to draw the traversal indicator
563 *****************************************************************************/
566 _DtCvSelectData start,
574 _DtCvFlags *ret_flag)
576 _DtCvUnit maxY = line.baseline + line.descent;
577 _DtCvUnit minY = line.baseline - line.ascent;
581 * zero out the return flag (which will be a logical OR of
584 if (NULL != ret_flag)
588 * initialize the return value to the given inspection length.
593 * is there anything to look at?
595 if (start.y == -1 || maxY < start.y || minY >= end.y)
599 * starts the mark/selection?
601 if (line_idx == start.line_idx)
604 * does this segment straddle the start of the mark/selection?
606 if (start.char_idx > char_idx)
609 * draw part(or all) of the segment un-mark/selected.
610 * never return a value larger than the inspection length!
612 if (start.char_idx < char_idx + length)
613 *ret_len = start.char_idx - char_idx;
619 * does this segment start the line? Set the start flag if so.
621 if (start.char_idx == char_idx)
622 flag |= _DtCvMARK_BEGIN;
625 * does this line end the mark/selection?
627 if (line_idx == end.line_idx)
630 * does this line straddle the end?
632 if (char_idx >= end.char_idx)
635 * draw this un mark/selected.
636 * Its after the mark/selected part.
641 if (char_idx + length > end.char_idx)
644 * draw the mark/selected part
646 *ret_len = end.char_idx - char_idx;
647 flag |= _DtCvMARK_END;
652 * draw the current *ret_len as mark/selected
657 * does this start the mark/selection?
659 else if (line_idx == end.line_idx)
662 * does not start the mark/selection.
663 * does end the mark/selection.
665 if (char_idx >= end.char_idx)
669 * straddle the end position?
671 if (char_idx + length > end.char_idx)
673 *ret_len = end.char_idx - char_idx;
674 flag |= _DtCvMARK_END;
677 * draw the current *ret_len as mark/selected
683 * start.y <= maxY && minY < end.y
685 else if (minY < start.y)
688 * straddles the start y
696 if (start.y != end.y)
698 if (NULL != ret_flag)
710 * start.y <= minY and maxY
713 else if (end.y <= maxY)
716 * straddles the end y position
722 * start.y <= minY and maxY
723 * minY && maxY < end.y
725 if (NULL != ret_flag)
731 /*****************************************************************************
732 * Function: DrawTraversalIndicator (_DtCanvasStruct *canvas, _DtCvValue flag)
734 * Purpose: (Un)draws the traversal around the currently active link.
735 *****************************************************************************/
737 DrawTraversalIndicator (
738 _DtCanvasStruct *canvas,
740 _DtCvValue draw_flag,
743 _DtCvUnit *ret_baseline,
744 _DtCvUnit *ret_height)
751 int travIdx = canvas->cur_trav;
753 int txtLine = canvas->trav_lst[travIdx].idx;
757 _DtCvUnit height = 0;
760 _DtCvUnit superWidth = 0;
761 _DtCvUnit superY = 0;
762 _DtCvUnit subWidth = 0;
764 _DtCvUnit scriptX = 0;
766 _DtCvFlags oldFlag = 0;
767 _DtCvFlags newFlag = 0;
769 _DtCvValue lastWasSub = False;
770 _DtCvValue lastWasSuper = False;
771 _DtCvValue lstLnkVis = False;
774 _DtCvSegmentI *tmpSeg;
777 * determine the flags for rendering.
780 newFlag = _DtCvTRAVERSAL_FLAG;
782 oldFlag = _DtCvTRAVERSAL_FLAG;
785 * allow traversal to marks.
787 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type)
789 int markIdx = canvas->trav_lst[travIdx].idx;
792 oldFlag = oldFlag | _DtCvMARK_FLAG
793 | _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
794 newFlag = newFlag | _DtCvMARK_FLAG
795 | _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
797 if (_DtCvTRUE == canvas->marks[markIdx].on)
799 oldFlag |= _DtCvMARK_ON;
800 newFlag |= _DtCvMARK_ON;
803 _DtCvDrawAreaWithFlags(canvas,
804 canvas->marks[markIdx].beg,
805 canvas->marks[markIdx].end,
808 canvas->marks[markIdx].client_data);
812 *ret_height = canvas->marks[markIdx].end.y -
813 canvas->marks[markIdx].beg.y +
814 canvas->txt_lst[canvas->marks[markIdx].end.line_idx].descent +
815 canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
818 * set some return variables
821 *ret_x = canvas->marks[markIdx].beg.x;
824 *ret_y = canvas->marks[markIdx].beg.y -
825 canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
828 *ret_baseline = canvas->marks[markIdx].beg.y;
836 linkIndex = canvas->trav_lst[travIdx].seg_ptr->link_idx;
839 * determine the location of the hypertext segment.
841 pSeg = canvas->trav_lst[travIdx].seg_ptr;
842 start = canvas->txt_lst[txtLine].byte_index;
843 count = canvas->txt_lst[txtLine].length;
846 * get the start of the line
848 dstX = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
850 while (pSeg->link_idx != linkIndex)
853 * get the corrected x
855 dstX = _DtCvAdvanceXOfLine (canvas, pSeg, dstX, &lstLnk, &lstLnkVis);
858 * move the text x position base on if this is a super or
859 * sub script - or not.
861 dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
862 &superWidth, &superY, &subWidth, &subY,
863 &lastWasSuper, &lastWasSub);
866 * get the width of the segment.
868 _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
869 &len, &tmpWidth, NULL);
875 lstLnk = pSeg->link_idx;
878 pSeg = pSeg->next_disp;
883 * set some return variables
889 *ret_y = canvas->txt_lst[txtLine].baseline -
890 canvas->txt_lst[txtLine].ascent;
892 *ret_baseline = canvas->txt_lst[txtLine].baseline;
895 * start drawing the traversals
900 while (txtLine < canvas->txt_cnt && linkIndex == pSeg->link_idx)
903 * get the corrected x
905 dstX = _DtCvAdvanceXOfLine (canvas,pSeg, dstX, &lstLnk, &lstLnkVis);
908 * move the text x position base on if this is a super or
909 * sub script - or not.
911 dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
912 &superWidth, &superY, &subWidth, &subY,
913 &lastWasSuper, &lastWasSub);
916 * now count up the number of bytes to display for
923 while (totCnt > 0 && tmpSeg != NULL
924 && tmpSeg->link_idx == linkIndex)
926 _DtCvGetWidthOfSegment(canvas, tmpSeg, wrkChr,
927 totCnt, &len, NULL, NULL);
931 tmpSeg = tmpSeg->next_disp;
935 * set the begin flag.
937 newFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
938 oldFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
939 while (count > 0 && pSeg != NULL && pSeg->link_idx == linkIndex)
942 * the original count for the traversal.
947 * if there is mark/selected text, determine, how much
949 _DtCvCheckLineMarks(canvas, txtLine, curIdx, count, dstX,
950 (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
951 &len, &oldFlag, &newFlag);
953 * if this is the last segment(s) of the traversal
958 newFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
959 oldFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
963 * render the segments
965 dstX = _DtCvDrawSegments(canvas, canvas->txt_lst[txtLine],
966 pSeg, start, len, &lstLnk, dstX, dstX,
967 &scriptX,&superWidth,&superY,&subWidth,&subY,
968 &lastWasSub, &lastWasSuper,
969 &lstLnkVis, oldFlag, newFlag,
970 _DtCvLINK_TYPE, NULL);
976 _DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
978 newFlag &= ~(_DtCvTRAVERSAL_BEGIN);
979 oldFlag &= ~(_DtCvTRAVERSAL_BEGIN);
983 height += canvas->txt_lst[txtLine].ascent
984 + canvas->txt_lst[txtLine].descent;
986 if (txtLine < canvas->txt_cnt)
988 start = canvas->txt_lst[txtLine].byte_index;
989 count = canvas->txt_lst[txtLine].length;
997 lastWasSuper = False;
1004 dstX = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
1010 *ret_height = height;
1012 } /* End DrawTraversalIndicator */
1014 /*****************************************************************************
1015 * Semi-Public Functions
1016 *****************************************************************************/
1017 /*****************************************************************************
1018 * Function: _DtCvGetSearchLineMetrics (
1020 * Purpose: gets the text line metrics for the search item.
1021 *****************************************************************************/
1023 _DtCvGetSearchLineMetrics(_DtCvHandle handle, int idx, _DtCvUnit* baseline,
1024 _DtCvUnit* descent, _DtCvUnit* ascent)
1027 _DtCanvasStruct* canvas = (_DtCanvasStruct*)handle;
1030 if (idx < 0 || idx >= canvas->search_cnt)
1033 line = &(canvas->txt_lst[canvas->searchs[idx].idx]);
1035 *baseline = line->baseline;
1036 *descent = line->descent;
1037 *ascent = line->ascent;
1042 /*****************************************************************************
1043 * Function: _DtCvCheckInfringement (
1045 * Purpose: Checks to see if one object infringes vertically on another
1047 *****************************************************************************/
1049 _DtCvCheckInfringement (
1055 _DtCvStatus result = False;
1058 * check to see if the object is to the left or right of the test
1059 * object and that it 'infringes' on the vertical space of the test
1062 * I.e. ----obj_top------
1063 * | | ----tst_top----
1064 * ----obj_bot------ | |
1067 * I.e. ----tst_top----
1068 * ----obj_top------- | |
1069 * | | ----tst_bot----
1070 * ----obj_bot-------
1072 * I.e. ----obj_top------
1073 * | | ----tst_top----
1075 * | | ----tst_bot----
1078 * I.e. ----tst_top----
1079 * ----obj_top------- | |
1081 * ----obj_bot------- | |
1084 if ((obj_top < tst_top && tst_top < obj_bot)
1085 || (obj_top < tst_bot && tst_bot < obj_bot)
1086 || (obj_top <= tst_top && tst_bot <= obj_bot)
1087 || (tst_top < obj_top && obj_bot < tst_bot))
1093 /*****************************************************************************
1094 * Function: _DtCvCheckLineMarks (
1097 * canvas Specifies the canvas to check for
1098 * marks and/or selections.
1099 * line_idx Specifies the line index into the
1100 * list of text lines in the canvas.
1101 * char_idx Specifies the starting character index
1103 * length Specifies the length of the text line
1105 * dst_x Specifies the x position of the
1106 * starting character in the text line.
1107 * check_flags Specifies which type to look for -
1108 * selection, marks or both.
1109 * ret_len Returns the length of the text line
1110 * starting at the starting character
1111 * index for which the flags returned
1112 * in ret_old and ret_new are valid.
1114 * Returns the values in ret_old and ret_new
1115 * and may add _DtCvSELECTED_FLAG and/or
1118 * Purpose: Find out how much of the line is (un)marked in some way.
1119 *****************************************************************************/
1121 _DtCvCheckLineMarks (
1122 _DtCanvasStruct *canvas,
1127 _DtCvFlags check_flags,
1129 _DtCvFlags *ret_old,
1130 _DtCvFlags *ret_new)
1133 _DtCvFlags flag = 0;
1136 * check the selection
1138 if ((check_flags & _DtCvSELECTED_FLAG) && canvas->select_start.y != -1)
1140 _DtCvSelectData start = canvas->select_start;
1141 _DtCvSelectData end = canvas->select_end;
1144 * check to see if we need to switch the selection points
1146 if (start.y > end.y || (start.y == end.y && start.x > end.x))
1148 end = canvas->select_start;
1149 start = canvas->select_end;
1153 * clear the selected flag
1155 *ret_old &= ~(_DtCvSELECTED_FLAG);
1156 *ret_new &= ~(_DtCvSELECTED_FLAG);
1158 if (IsLineSpecial(start, end,
1159 canvas->txt_lst[line_idx], line_idx,
1160 char_idx, length, dst_x,
1164 * set the selected flag.
1166 *ret_old = *ret_old | _DtCvSELECTED_FLAG;
1167 *ret_new = *ret_new | _DtCvSELECTED_FLAG;
1171 if ((check_flags & _DtCvMARK_FLAG) && 0 < canvas->mark_cnt)
1174 * strip the mark flags from the old and new flags
1176 *ret_old &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
1177 _DtCvMARK_END | _DtCvMARK_ON);
1178 *ret_new &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
1179 _DtCvMARK_END | _DtCvMARK_ON);
1182 * now add the correct flags into the old/new flags
1184 for (i = 0; i < canvas->mark_cnt; i++)
1186 if (IsLineSpecial(canvas->marks[i].beg, canvas->marks[i].end,
1187 canvas->txt_lst[line_idx], line_idx,
1188 char_idx, length, dst_x,
1192 * A false return from IsLineSpecial means that 'length'
1193 * is outside this mark.
1195 * When true, it means that some part of this mark will
1196 * be rendered on the call. Therefore set the mark flag
1197 * and any other flags returned and check for mark 'on'.
1199 if (_DtCvTRUE == canvas->marks[i].on)
1200 flag |= _DtCvMARK_ON;
1202 *ret_old = *ret_old | _DtCvMARK_FLAG | flag;
1203 *ret_new = *ret_new | _DtCvMARK_FLAG | flag;
1209 * return the next length that is marked/unmarked in someway.
1214 /******************************************************************************
1215 * Function: _DtCvSkipLineChars
1218 * canvas Specifies the canvas on which to render
1221 * Purpose: Given a length, skip ahead that number of 'characters' on
1223 *****************************************************************************/
1226 _DtCanvasStruct *canvas,
1227 _DtCvSegmentI *p_seg,
1232 _DtCvSegmentI **ret_seg)
1237 * not all of the traversal line was displayed because
1238 * part of it is selected. So skip what's been rendered,
1244 * get the byte length of the segment processed.
1246 _DtCvGetWidthOfSegment(canvas, p_seg, start, max_cnt, &len, NULL, NULL);
1248 * increment the start index by the number of total
1249 * bytes processed. If this is more that what is in
1250 * the segment, then the if stmt will catch this and
1251 * set the start index to zero.
1258 else /* if (len <= use_len) */
1261 p_seg = p_seg->next_disp;
1265 * reduce the total number of bytes
1266 * processed by the number in this segment.
1276 /******************************************************************************
1277 * Function: _DtCvClearInternalUse
1279 * Init every internal_use pointer on containers to NULL.
1280 *****************************************************************************/
1282 _DtCvClearInternalUse(
1283 _DtCvSegmentI *list,
1286 while (NULL != list)
1289 * initialize the internal variables
1291 list->internal_use = (void *) -1;
1293 if (_DtCvIsSegContainer(list))
1294 _DtCvClearInternalUse(_DtCvContainerListOfSeg(list), flag);
1296 list = list->next_seg;
1300 /******************************************************************************
1301 * Function: _DtCvGetCharIdx
1304 * canvas Specifies the canvas on which to render
1306 * line Specifies the line in the line table.
1307 * find_x Specifies the x position of the character.
1309 * Returns: ?? Returns the idx of the character.
1312 *****************************************************************************/
1315 _DtCanvasStruct *canvas,
1320 _DtCvValue done = FALSE;
1321 _DtCvValue lastLinkVisible = FALSE;
1322 int count = line.length;
1323 int start = line.byte_index;
1328 _DtCvSegmentI *pSeg;
1330 xPos = _DtCvGetStartXOfLine(&line, &pSeg);
1333 * check to see if the start is in the middle of the line.
1334 * If so, bump the x position and start indexes to the
1335 * correct locations.
1337 while (!done && find_x > xPos && count > 0)
1339 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
1340 &lnkInd, &lastLinkVisible);
1345 * advance the pointer by the width
1347 _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
1348 &len, &segWidth, NULL);
1349 if (segWidth + xPos <= find_x)
1352 pSeg = pSeg->next_disp;
1356 else /* if (xPos < find_x && find_x < xPos + segWidth) */
1358 if (_DtCvIsSegString(pSeg))
1360 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
1361 _DtCvIsSegWideChar(pSeg), start);
1362 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
1367 count -= FindChar(canvas, pSeg, pChar, len,
1368 find_x - xPos, NULL);
1374 len = line.length - count;
1380 /*****************************************************************************
1381 * Function: _DtCvGetStartXOfLine
1383 * Purpose: Get the starting 'x' of the specified line
1384 * Does *not* take into account traversal or link info.
1385 *****************************************************************************/
1387 _DtCvGetStartXOfLine (
1389 _DtCvSegmentI **p_seg)
1391 *p_seg = line->seg_ptr;
1393 return line->text_x;
1396 /*****************************************************************************
1397 * Function: _DtCvAdvanceXOfLine
1399 * Purpose: Move the 'x' to after the traversal and link info.
1400 *****************************************************************************/
1402 _DtCvAdvanceXOfLine (
1403 _DtCanvasStruct *canvas,
1404 _DtCvSegmentI *p_seg,
1407 _DtCvValue *link_flag)
1412 * take into account the link before and after space
1414 junk = _DtCvIsSegVisibleLink(p_seg);
1415 *link_flag = _DtCvModifyXpos (canvas->link_info, p_seg, junk,
1416 *link_flag, *link_idx, &x_pos);
1419 * take into account the traversal before and after space
1421 junk = _DtCvIsSegALink(p_seg);
1422 (void) _DtCvModifyXpos (canvas->traversal_info, p_seg, junk,
1423 ((_DtCvValue) True), *link_idx, &x_pos);
1425 *link_idx = p_seg->link_idx;
1430 /******************************************************************************
1431 * Function: _DtCvGetWidthOfSegment
1433 * DetermineWidthOfSegment determines the width of the segment.
1434 * The segment must have been already initialized with the correct
1435 * font (for strings), the spc resolve, the graphic loaded, etc.
1437 *****************************************************************************/
1439 _DtCvGetWidthOfSegment(
1440 _DtCanvasStruct *canvas,
1441 _DtCvSegmentI *p_seg,
1446 _DtCvValue *ret_trimmed)
1451 * return the width of the segment.
1457 if (ret_trimmed != NULL)
1458 *ret_trimmed = False;
1460 if (!(_DtCvIsSegNoop(p_seg)))
1462 if (_DtCvIsSegRegion(p_seg))
1466 *ret_w = _DtCvWidthOfRegionSeg(p_seg);
1470 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(p_seg),
1471 _DtCvIsSegWideChar(p_seg), start);
1472 *ret_cnt = _DtCvStrLen (pChar, _DtCvIsSegWideChar(p_seg));
1473 if (*ret_cnt > max_cnt)
1476 if (ret_trimmed != NULL)
1477 *ret_trimmed = True;
1481 * determine the width of the string.
1484 *ret_w = _DtCvGetStringWidth(canvas, p_seg,pChar,*ret_cnt);
1489 /******************************************************************************
1490 * Function: _DtCvModifyXpos
1491 *****************************************************************************/
1494 _DtCvSpaceMetrics info,
1496 _DtCvValue tst_result,
1497 _DtCvValue cur_flag,
1504 * take into account the link before and after space
1509 * Ignore if the same link
1511 if (last_idx != seg->link_idx)
1514 * if one link followed by another add the space after.
1517 addx = info.space_after;
1520 * add the space before the link
1522 addx += info.space_before;
1528 if (last_idx != -1 && cur_flag == True)
1529 addx = info.space_after;
1537 /*****************************************************************************
1538 * Function: _DtCvAdjustForSuperSub
1541 * canvas Specifies the canvas.
1542 * start_x Specifies the current text x position.
1543 * script_x Specifies the current super and sub
1544 * scripting x position. Returns the same
1545 * value as start_x if the segment is not a
1546 * super or sub script.
1547 * super_width Specifies the width of the previously
1548 * rendered super script. Set to 0 if the
1549 * next segment is not a super or sub
1551 * super_y Specifies the y offset for super
1552 * scripts. Set to a new value if the last
1553 * segment was not a super or sub script.
1554 * sub_width Specifies the width of the previously
1555 * rendered sub script. Set to 0 if the
1556 * next segment is not a super or sub
1558 * sub_y Specifies the y offset for sub scripts.
1559 * Set to a new value if the last segment
1560 * was not a super or sub script.
1561 * last_was_super Specifies if the last item was a super
1562 * script. Set to False if the segment
1563 * is not a super or sub script.
1564 * last_was_sub Specifies if the last item was a sub
1565 * script. Set to False if the segment
1566 * is not a super or sub script.
1567 * Returns: new text x positon.
1569 * Purpose: Determines the super and sub scripting positions for text.
1570 * If the last item was not a script, then the base offset for
1571 * scripting (script_x) is moved to start_x. If the current
1572 * item is a string, its scripting y position is determined
1573 * (super_y and sub_y). If the new item is a super or sub
1574 * script, the next text placement (start_x) is moved to after
1575 * the script_x plus the super or sub script size currently
1576 * active(super_width and sub_width). Otherwise, the the flags
1577 * are set to false and the widths are set to 0.
1579 *****************************************************************************/
1581 _DtCvAdjustForSuperSub(
1582 _DtCanvasStruct *canvas,
1583 _DtCvSegmentI *pSeg,
1585 _DtCvUnit *script_x,
1586 _DtCvUnit *super_width,
1588 _DtCvUnit *sub_width,
1590 _DtCvValue *last_was_super,
1591 _DtCvValue *last_was_sub)
1594 * if the last item was not a super or sub script,
1595 * move the script x to the end of the last output.
1597 if (!(*last_was_super || *last_was_sub))
1598 *script_x = start_x;
1601 * check for super and sub scripts.
1602 * adjust text x positioning accordingly.
1604 if (_DtCvIsSegSuperScript(pSeg))
1606 start_x = *script_x + *super_width;
1607 *last_was_super = True;
1609 else if (_DtCvIsSegSubScript(pSeg))
1611 start_x = *script_x + *sub_width;
1612 *last_was_sub = True;
1614 else if (*last_was_super || *last_was_sub)
1618 *last_was_super = False;
1619 *last_was_sub = False;
1623 * if this wasn't a super or sub script, find out where
1624 * they get placed on this string.
1626 if (!(*last_was_super || *last_was_sub))
1628 if (_DtCvIsSegString(pSeg))
1629 _DtCvFontMetrics (canvas,_DtCvFontOfStringSeg(pSeg),
1630 NULL, NULL, NULL, super_y, sub_y);
1631 else if (_DtCvIsSegRegion(pSeg))
1633 *super_y = _DtCvHeightOfRegionSeg(pSeg) * 4 / 10;
1641 /******************************************************************************
1642 * Function: _DtCvDrawSegments
1645 * canvas Specifies the canvas on which to render
1647 * line Specifies the line metrics.
1648 * p_seg Specifies the starting segment.
1649 * start_char Specifies the starting index in a string
1650 * segment. 0 for all others.
1651 * count Specifies the number of characters
1652 * (including special characters to
1654 * prev_lnk Indicates the previous link index. Used
1655 * to calculate extra spacing needed for
1656 * traversal and link markup.
1657 * txt_x Specifies the starting x of the
1658 * segment(s). This does *NOT* take into
1659 * account traversal or link spacing. This
1660 * routine will do that. This is so
1661 * selected links will have correct spacing
1663 * sel_x Specifies where the selection x position
1664 * begins. Usually it equals txt_x, but
1665 * sometimes it will be less than it to
1666 * indicate blank space has been selected.
1667 * super_width Specifies the last super script x offset.
1668 * super_y Specifies the last super script y offset.
1669 * sub_width Specifies the last sub script x offset.
1670 * sub_y Specifies the last sub script y offset.
1671 * last_was_sub Specifies if the last element was a
1673 * last_was_super Specifies if the last element was a
1675 * last_was_vis Specifies if the last element was a
1676 * visible hypertext link.
1677 * old_flag Specifies what the line use to look like.
1678 * new_flag Specifies what the line is to look like.
1680 * Returns: txt_x Returns the maximum x unit processed.
1682 * Purpose: _DtCvDrawSegments draws one or more segments based on
1683 * the count passed in.
1685 * This routine adds CELink to new_flag when rendering segments
1686 * that are hypertext links. At the same time it will
1687 * determine the correct window hint and may place in old_flag
1688 * and new_flag either _DtCvLINK_POP_UP or _DtCvLINK_NEW_WINDOW.
1690 * This routine strips the _DtCvTRAVERSAL_END from old_flag and
1691 * new_flag (based on what's in new_flag). It will restore
1692 * these flags (if specified) when it renders the last element
1693 * in the count sequence.
1695 *****************************************************************************/
1698 _DtCanvasStruct *canvas,
1700 struct _dtCvSegment *p_seg,
1706 _DtCvUnit *script_x,
1707 _DtCvUnit *super_width,
1709 _DtCvUnit *sub_width,
1711 _DtCvValue *last_was_sub,
1712 _DtCvValue *last_was_super,
1713 _DtCvValue *last_link_vis,
1714 _DtCvFlags old_flag,
1715 _DtCvFlags new_flag,
1716 _DtCvElemType trav_type,
1717 _DtCvPointer trav_data )
1721 short cropped = _DtCvFALSE;
1722 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 */