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 /* $XConsortium: LayoutUtil.c /main/26 1996/11/06 12:25:09 cde-hp $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 ** Project: Cde DtHelp
33 ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
35 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
36 ** (c) Copyright 1993, 1994 International Business Machines Corp.
37 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
38 ** (c) Copyright 1993, 1994 Novell, Inc.
42 ****************************************************************************
43 ************************************<+>*************************************/
53 * Canvas Engine includes
56 #include "CanvasSegP.h"
62 #include "CvStringI.h"
63 #include "LayoutUtilI.h"
64 #include "StringFuncsI.h"
65 #include "VirtFuncsI.h"
67 #if defined(NLS16) || !defined(NO_MESSAGE_CATALOG)
72 static const int NL_CAT_LOCALE = 0;
75 /******************************************************************************
79 *****************************************************************************/
81 #define CheckFormat(x) \
82 (((x)->format_y == -1 || (x)->format_y > (x)->y_pos) ? False : True)
84 /******************************************************************************
88 *****************************************************************************/
89 static char *OneByteCantBeginList = "])}`\"\'.,;?:!";
90 static char *OneByteCantEndList = "[({`\"";
92 static _DtCvLayoutInfo DefLayInfo =
94 NULL, /* _DtCvSegmentI *line_seg; */
95 0, /* unsigned int line_start; */
96 0, /* unsigned int line_bytes; */
97 0, /* _DtCvUnit cur_len; */
98 0, /* _DtCvUnit max_x_pos; */
99 0, /* _DtCvUnit cur_max_x; */
100 0, /* _DtCvUnit y_pos; */
101 0, /* _DtCvUnit text_x_pos; */
102 0, /* _DtCvUnit leading; */
103 -1, /* int lst_hyper; */
104 _CEFORMAT_ALL, /* int format_y; */
105 -1, /* int join_line; */
106 FALSE, /* _DtCvValue lst_vis; */
107 FALSE, /* _DtCvValue join; */
108 FALSE, /* _DtCvValue align_flag; */
109 NULL, /* const char *align_char; */
110 -1, /* _DtCvUnit align_pos; */
111 0, /* int delayed_search_saves */
114 static const _DtCvSelectData DefSelectData = { -1, -1, -1, -1 };
115 static const _DtCvTraversalInfo DefTravData =
117 _DtCvFALSE /* active */,
118 _DtCvTraversalNone /* type */,
127 /******************************************************************************
131 *****************************************************************************/
132 /******************************************************************************
133 * Function: IsTrueMultiByte
135 * Returns: True if the character is a multibyte character
136 * False if the character is a single byte character.
137 *****************************************************************************/
139 IsTrueMultiByte (wchar_t wc_char)
141 char buf[MB_LEN_MAX];
144 * check to see if this is a one byte character
145 * There might not be a multibyte list for this locale.
146 * Can't break on single byte characters.
148 if (1 != wctomb(buf, wc_char))
154 /******************************************************************************
155 * Function: CheckList
157 * Returns: True if the character matches one of the characters in
158 * the MultiCantEndList.
159 * False if the character does not match an item in
160 * the MultiCantEndList.
161 *****************************************************************************/
168 * check the multibyte list for the character
172 while ('\0' != *list)
175 * it matches, return true
177 if (*list == wc_char)
186 /*****************************************************************************
187 * Function: static int CompareTraversalPos (_DtCvHandle canvas);
195 *****************************************************************************/
197 CompareTraversalPos (
201 _DtCvTraversalInfo *linkA = (_DtCvTraversalInfo *) a;
202 _DtCvTraversalInfo *linkB = (_DtCvTraversalInfo *) b;
203 _DtCvUnit centA = linkA->y_pos + (linkA->height >> 1);
204 _DtCvUnit centB = linkB->y_pos + (linkB->height >> 1);
206 if (linkA->y_pos + linkA->height < centB && centA < linkB->y_pos)
209 if (linkB->y_pos + linkB->height < centA && centB < linkA->y_pos)
212 if (linkA->x_pos != linkB->x_pos)
213 return ((linkA->x_pos < linkB->x_pos) ? -1 : 1);
215 if (linkA->y_pos != linkB->y_pos)
216 return ((linkA->y_pos < linkB->y_pos) ? -1 : 1);
218 if (linkA->height != linkB->height)
219 return ((linkA->height < linkB->height) ? -1 : 1);
221 if (linkA->width != linkB->width)
222 return ((linkA->width < linkB->width) ? -1 : 1);
227 /******************************************************************************
229 * Private Layout Utility Functions
231 *****************************************************************************/
232 /******************************************************************************
233 * Function: void _DtCvInitLayoutInfo ()
239 *****************************************************************************/
241 _DtCvInitLayoutInfo (
242 _DtCanvasStruct *canvas,
243 _DtCvLayoutInfo *layout)
245 *layout = DefLayInfo;
247 layout->y_pos = canvas->metrics.top_margin;
250 /******************************************************************************
251 * Function: int _DtCvGetTraversalWidth ()
255 * Returns: The total amount of space to add before and after the
256 * segment to take into account traversal/link metrics on
257 * this segment including any necessary to 'close' out the
258 * link on the previous segment.
260 *****************************************************************************/
262 _DtCvGetTraversalWidth (
263 _DtCanvasStruct *canvas,
264 _DtCvSegmentI *p_seg,
272 * does this segment have a different link than the previous one?
274 if (lst_hyper != p_seg->link_idx)
277 * is the link visible?
279 if (_DtCvIsSegVisibleLink(p_seg))
282 * get the visible link metrics
284 lnkBefore = canvas->link_info.space_before;
285 lnkAfter = canvas->link_info.space_after;
287 if (_DtCvIsSegALink(p_seg))
290 * if the last 'link' was really a link, close it out by
291 * leaving room for the traversal and link end indicators
294 value += (canvas->traversal_info.space_after + lnkAfter);
297 * leave space for the traversal/link begin and end
298 * indicators for this segment.
300 value += (canvas->traversal_info.space_before
301 + canvas->traversal_info.space_after
310 /******************************************************************************
311 * Function: _DtCvAddLines
313 * makes sure the last x number of lines are blank.
314 *****************************************************************************/
327 * adjust the global Y position to allow the extra room
329 *ret_y = *ret_y + number;
332 /******************************************************************************
333 * Function: CheckOneByteCantEndList
335 * Returns: True if the character matches one of the characters in
336 * the OneByteCantEndList.
337 * False if the character does not match an item in
338 * the OneByteCantEndList.
339 *****************************************************************************/
341 _DtCvCheckOneByteCantEndList (
347 for (i = 0; cant_end_list[i]; i++)
348 if (cant_end_list[i] == c)
354 /******************************************************************************
355 * Function: CheckOneByteCantBeginList
357 * Returns: True if the character matches one of the characters in
358 * the OneByteCantBeginList.
359 * False if the character does not match an item in
360 * the OneByteCantBeginList.
361 *****************************************************************************/
363 _DtCvCheckOneByteCantBeginList (
365 char *cant_begin_list)
369 for (i = 0; cant_begin_list[i]; i++)
370 if (cant_begin_list[i] == c)
376 /******************************************************************************
377 * Function: CheckLineSyntax
379 * Returns: True if the segment can end a line.
380 * False if the segment can not end a line.
382 * Purpose: Checks the line syntax. Will not allow a segment to end
384 * the segment does not end with a hypen.
385 * the segment does not end with a space and the
386 * next segment does not begin with a space.
387 * the segment ends with a two byte characters that
388 * can not end a line.
389 * The next segment starts with a two byte character
390 * that can not begin a line.
391 * the segment ends with an one-byte open type and
392 * the next segment starts with a
393 * two byte character.
394 * the segment ends with a two byte character and
395 * the next segment starts with a one-byte
397 * the next segment is a non-breaking string or region.
399 *****************************************************************************/
401 _DtCvCheckLineSyntax (
402 _DtCanvasStruct *canvas,
406 _DtCvValue skip_hypen_ck)
413 _DtCvValue lstCharMb = False;
414 _DtCvValue nxtCharMb = False;
417 * while this is a marker or a noop without a end-of-line, go to the
420 while (NULL != pSeg && (_DtCvIsSegMarker(pSeg) ||
421 (_DtCvIsSegNoop(pSeg) && !_DtCvIsSegNewLine(pSeg))))
422 pSeg = pSeg->next_seg;
425 * if this segment is null or not a string or region, stop the
428 if (pSeg == NULL || !(_DtCvIsSegString(pSeg) || _DtCvIsSegRegion(pSeg)))
432 * Get the string segment stats
434 if (_DtCvIsSegString(pSeg))
436 wcFlag = _DtCvIsSegWideChar(pSeg);
437 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg), wcFlag, start);
438 myStrLen = _DtCvStrLen (pChar, wcFlag);
442 * if this is a region or a string segment (at the end of its string)
443 * and it has a newline on it, then it can end a line.
445 if ((_DtCvIsSegRegion(pSeg) ||
446 (_DtCvIsSegString(pSeg) && myStrLen == str_len))
447 && (_DtCvIsSegNewLine (pSeg) || pSeg->next_seg == NULL))
451 * if this is a region, then check it's breaking flag.
453 if (_DtCvIsSegRegion(pSeg))
455 if (_DtCvIsSegNonBreakingChar(pSeg))
461 * so, to get this far, this is a string segment.
463 * Problems with indexing?
469 * do we need to check the last character in the string?
470 * If skip_hypen_ck is true, it means that 'lastChar' would be a hypen.
472 if (False == skip_hypen_ck)
475 * this region is a string, get its string information.
477 lastChar = _DtCvChar(pChar, wcFlag, str_len - 1);
480 * check to make sure the last character is a valid last
483 if (' ' == lastChar || '-' == lastChar)
487 * If this string is a multi-byte, check the list of multi-bytes
488 * that can't end a line. If one is found it can't end a line.
491 CheckList(lastChar, canvas->locale.cant_end_chars) == True)
495 * so at the end of these tests, the last character is
498 * -) either a single byte character or multibyte character
499 * that can end the line (including a single byte in
502 * set the flag for the type of character lastChar is.
503 * if skip_hypen_ck was True, then lstCharMb remains False
504 * which is logical since it means that the caller has already
505 * processed a hypen (a single byte character).
507 lstCharMb = IsTrueMultiByte(lastChar);
511 * Check for more characters in the string and
512 * check its next character for breakable space.
514 if (myStrLen > str_len)
517 * go to the next character.
519 nextChar = _DtCvChar(pChar, wcFlag, str_len);
522 * Is it a valid break point?
528 * set the multibyte flag for the next character
530 nxtCharMb = IsTrueMultiByte(nextChar);
533 * If this is wide char string, check the list of multi-byte
534 * that can't begin a line.
536 * But only if the last character wasn't a hypen! Otherwise
537 * it's a character after a hypen and should not be broken on.
539 * if this character is in the 'cannot begin line' list, then it
540 * can't be broken on (a return value of true). (A wide char
541 * encoding of a single byte character should come back as False
542 * as long as the character is not in the list.)
544 * Have to double check to make sure it is a multibyte
545 * character (want it to go through the CheckMulti list just in
546 * case it's specified in there, before eliminating it).
548 if (False == skip_hypen_ck && wcFlag
549 && CheckList(nextChar,canvas->locale.cant_begin_chars) == False
550 && True == nxtCharMb)
554 * either the character is after a hypen (starting a line) OR it
555 * is a multibyte character in the 'cannot begin a line' list OR
556 * it is a single byte character. Therefore, this is a
557 * nonbreakable character.
563 * We were at the last character of the string.
564 * go to the next segment and see if it can start a new line.
568 pSeg = pSeg->next_seg;
569 } while (pSeg != NULL && (_DtCvIsSegMarker(pSeg) ||
570 (_DtCvIsSegNoop (pSeg) && !(_DtCvIsSegNewLine(pSeg)))));
572 * If there isn't another valid segment, then the original segment
575 if (pSeg == NULL || !(_DtCvIsSegString(pSeg) || _DtCvIsSegRegion(pSeg)))
579 * if the last if fell through, then pSeg is a string or region.
580 * check to see if you can break on it.
582 if (_DtCvIsSegNonBreakingChar(pSeg))
586 * if the last if fell through, then this is a breaking string or
587 * region. Therefore, if a region, you can break on it.
589 if (_DtCvIsSegRegion(pSeg))
593 * To get this far, the next segment must be a string. Check the
594 * first character of the string to see if it can start a new line.
596 nextChar = _DtCvChar(_DtCvStringOfStringSeg(pSeg),
597 _DtCvIsSegWideChar(pSeg), 0);
602 * If the previous character was a single byte character (or a hypen),
603 * it couldn't end a line. If this is a single byte string, then
604 * this string can't start a line......
606 if (_DtCvIsSegRegChar(pSeg) &&
607 (True == skip_hypen_ck || False == lstCharMb))
611 * If this is multi-byte, check the list of multi-byte
612 * that can't begin a line.
614 if (_DtCvIsSegWideChar(pSeg))
617 * plus checking the 'can not begin a line' list, check
618 * if the previous character was a hypen, then this can't be
621 if (True == skip_hypen_ck ||
622 CheckList(nextChar, canvas->locale.cant_begin_chars) == True)
626 * if the previous character was a multi-byte and this
627 * character is a multibyte, then it is a valid break.
629 nxtCharMb = IsTrueMultiByte(nextChar);
630 if (True == lstCharMb && True == nxtCharMb)
635 * if the last character was a single byte character, then there
636 * is still more to check - 1 byte punctuation around multi-byte.
638 if (False == lstCharMb &&
639 _DtCvCheckOneByteCantEndList((char)lastChar,OneByteCantEndList) == True)
643 * or was the last character a multibyte and is followed by single byte
646 if (True == lstCharMb && False == nxtCharMb &&
647 _DtCvCheckOneByteCantBeginList((char)nextChar, OneByteCantBeginList)
654 /******************************************************************************
655 * Function: _DtCvGetNextWidth
657 * Purpose: Determines the width of the next legal segment.
659 * Returns: The width of the next legal segment.
661 *****************************************************************************/
664 _DtCanvasStruct *canvas,
669 _DtCvSegmentI *prev_seg,
670 _DtCvSegmentI **nextSeg,
686 * pass over noops that don't have newlines and markers
688 while (pSeg != NULL && (_DtCvIsSegMarker(pSeg) ||
689 (_DtCvIsSegNoop (pSeg) && !(_DtCvIsSegNewLine(pSeg)))))
691 pSeg = pSeg->next_seg;
697 if (nextStart != NULL)
701 * if the next segment is null or anything else but a string or region;
702 * return that there is no more after this segment.
704 if (pSeg == NULL || !(_DtCvIsSegString(pSeg) || _DtCvIsSegRegion(pSeg)))
708 * this segment is a region or string
709 * check for region...anything left is a string.
711 if (_DtCvIsSegRegion(pSeg))
714 * can I break on this region
716 if (_DtCvIsSegNonBreakingChar(pSeg))
719 * no...set the lengths and continue
722 curWidth = _DtCvWidthOfRegionSeg(pSeg);
728 * is this a non breaking string?
730 else if (_DtCvIsSegNonBreakingChar(pSeg))
732 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
733 _DtCvIsSegWideChar(pSeg), start);
734 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
736 curWidth = _DtCvGetStringWidth (canvas, pSeg, pChar, len)
737 + _DtCvGetTraversalWidth(canvas, pSeg, lst_hyper);
740 * so this is a string with possible breaks in it.
745 * get the string stats
747 wcFlag = _DtCvIsSegWideChar (pSeg);
748 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg), wcFlag, start);
749 myLength = _DtCvStrLen (pChar, wcFlag);
752 * if a single byte string, zoom through it looking for
753 * specific breaking characters.
762 * checking for a hypen or space
765 result = _DtCvStrcspn ((void *) tChar, " -", 0, &tLen);
769 * check for '-'. Some of the possible combinations are:
777 * if it is the first character to check and there is no
778 * previous segment, then it is starting a line and can
781 * _DtCvStrcpn return 0 if one of the characters in the
782 * test string was found.
784 if (0 == result && '-' == tChar[tLen] && 0 == len &&
786 _DtCvCheckLineSyntax(canvas,pSeg,start,1,True) == False)
796 * found either a space or a hypen or null byte.
797 * If we found a hypen, include it.
802 curWidth = _DtCvGetStringWidth (canvas, pSeg, pChar, len)
803 + _DtCvGetTraversalWidth(canvas, pSeg, lst_hyper);
806 * Did we find a space or hypen?
807 * If not, can this segment stand alone?
810 _DtCvCheckLineSyntax(canvas,pSeg,start,len,False) == True)
814 if (nextStart != NULL)
815 *nextStart = start + len;
816 if (widthCount != NULL)
822 * multibyte (wide char string), look for a break the hard way.
827 while (len < myLength)
830 if (_DtCvCheckLineSyntax(canvas,pSeg,start,len,False) == True)
832 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
833 _DtCvIsSegWideChar(pSeg), start);
834 curWidth = _DtCvGetStringWidth(canvas,pSeg,pChar,len)
835 + _DtCvGetTraversalWidth(canvas,pSeg,lst_hyper);
839 if (nextStart != NULL)
840 *nextStart = start + len;
841 if (widthCount != NULL)
848 * Didn't find a smaller segment that satisfied the requirements.
849 * Determine the length of the current segment.
851 curWidth = _DtCvGetStringWidth (canvas, pSeg, pChar, len)
852 + _DtCvGetTraversalWidth(canvas, pSeg,
858 * sigh...need to go further...this segment can't end a line
862 pSeg = pSeg->next_seg;
866 curWidth += _DtCvGetNextWidth (canvas,
867 _DtCvPrimaryTypeOfSeg (prev_seg), lst_hyper,
868 pSeg, start, prev_seg,
869 nextSeg, nextStart, &nextLen);
873 if (widthCount != NULL)
874 *widthCount = len + nextLen;
878 /******************************************************************************
879 * Function: _DtCvSaveInfo
881 * Initializes a line table element to the segment it should display.
882 *****************************************************************************/
885 _DtCanvasStruct *canvas,
886 _DtCvLayoutInfo *layout,
889 _DtCvFrmtOption txt_justify)
891 /*****************************************************************
892 * The ascent for a line is described as the number of units
893 * above the baseline.
895 * The descent for a line is described as the number of units
896 * below the baseline.
898 * Neither the ascent or decent value includes the baseline
899 ****************************************************************/
901 int start = layout->line_start;
902 int count = layout->line_bytes;
903 long txtCnt = canvas->txt_cnt;
904 _DtCvUnit maxAscent = 0;
905 _DtCvUnit maxDescent = 0;
906 _DtCvUnit maxRegion = 0;
907 _DtCvUnit superY = 0;
909 _DtCvUnit fontAscent;
910 _DtCvUnit fontDescent;
911 _DtCvValue fndLnk = False;
912 _DtCvValue visLnk = False;
916 _DtCvSegmentI *pSeg = layout->line_seg;
918 if (txtCnt >= canvas->txt_max)
920 canvas->txt_max += GROW_SIZE;
922 canvas->txt_lst = (_DtCvDspLine *) realloc (
923 (void *) canvas->txt_lst,
924 (sizeof(_DtCvDspLine) * canvas->txt_max));
926 canvas->txt_lst = (_DtCvDspLine *) malloc (
927 (sizeof(_DtCvDspLine) * canvas->txt_max));
929 * NOTE....should this routine return a value?
930 * If (re)alloc error occurs, this simply ignores the problem.
932 if (canvas->txt_lst == NULL)
940 while (pSeg != NULL && count > 0)
943 * set which line will this segment sit on, iff this is the
944 * first access to the segment.
946 if ((void *) -1 == pSeg->internal_use)
947 pSeg->internal_use = (void *) txtCnt;
950 * now get the segment's sizing so we can determine
951 * the height and depth of the line.
957 if (_DtCvIsSegVisibleLink(pSeg))
960 if (_DtCvIsSegALink(pSeg))
964 * get the ascent and descent of the segment along with a length
966 if (_DtCvIsSegString(pSeg))
968 _DtCvFontMetrics(canvas,_DtCvFontOfStringSeg(pSeg),
969 &fontAscent, &fontDescent, NULL, NULL, NULL);
971 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
972 _DtCvIsSegWideChar(pSeg), start);
973 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
978 else if (_DtCvIsSegRegion(pSeg))
980 if (-1 == _DtCvAscentOfRegionSeg(pSeg))
982 if (maxRegion < _DtCvHeightOfRegionSeg(pSeg))
983 maxRegion = _DtCvHeightOfRegionSeg(pSeg);
987 fontAscent = _DtCvAscentOfRegionSeg(pSeg);
988 fontDescent = _DtCvHeightOfRegionSeg(pSeg) - fontAscent;
993 * adjust the ascent and descent values by their subscript
994 * or superscript adjustments.
996 if (_DtCvIsSegSuperScript(pSeg))
998 fontAscent += superY;
999 fontDescent -= superY;
1001 if (_DtCvIsSegRegion(pSeg) && -1 == _DtCvAscentOfRegionSeg(pSeg)
1002 && maxRegion < _DtCvHeightOfRegionSeg(pSeg) + superY)
1003 maxRegion = _DtCvHeightOfRegionSeg(pSeg) + superY;
1005 else if (_DtCvIsSegSubScript(pSeg))
1008 fontDescent += subY;
1009 if (_DtCvIsSegRegion(pSeg) && -1 == _DtCvAscentOfRegionSeg(pSeg)
1010 && maxRegion < _DtCvHeightOfRegionSeg(pSeg) + subY)
1011 maxRegion = _DtCvHeightOfRegionSeg(pSeg) + subY;
1013 else /* not a subscript or superscript */
1016 * set up the super and sub script offsets for following
1019 if (_DtCvIsSegString (pSeg))
1020 _DtCvFontMetrics(canvas,_DtCvFontOfStringSeg(pSeg),
1021 NULL, NULL, NULL, &superY, &subY);
1022 else if (_DtCvIsSegRegion(pSeg))
1024 superY = _DtCvHeightOfRegionSeg(pSeg) * 4 / 10;
1030 * now determine the maximums for ascent and descent.
1032 if (fontAscent > maxAscent)
1033 maxAscent = fontAscent;
1034 if (fontDescent > maxDescent)
1035 maxDescent = fontDescent;
1038 * decrement the count
1043 * If this segment terminates the paragraph
1044 * force the end of the loop.
1046 pSeg = pSeg->next_disp;
1050 if (txt_justify == _DtCvJUSTIFY_RIGHT || _DtCvJUSTIFY_CENTER == txt_justify)
1055 _DtCvUnit workWidth = max_width - layout->text_x_pos -
1056 r_margin - layout->cur_len;
1057 if (txt_justify == _DtCvJUSTIFY_CENTER)
1058 workWidth = workWidth / 2;
1063 layout->text_x_pos += workWidth;
1067 * adjust for any special characters found
1069 if (maxRegion > maxAscent + maxDescent + 1)
1070 maxAscent = maxRegion - maxDescent - 1;
1073 * check to see if the max values have even been touched.
1075 if (layout->line_bytes == 0 && maxAscent == 0 && maxDescent == 0)
1076 maxAscent = canvas->metrics.line_height;
1079 * adjust ascent and descent by the traversal and link info
1081 maxDescent += layout->leading;
1084 maxAscent += canvas->traversal_info.space_above;
1085 maxDescent += canvas->traversal_info.space_below;
1088 maxAscent += canvas->link_info.space_above;
1089 maxDescent += canvas->link_info.space_below;
1094 * save the line information, if there is a string here.
1096 if (layout->line_bytes > 0)
1098 canvas->txt_lst[txtCnt].processed = _DtCvFALSE;
1099 canvas->txt_lst[txtCnt].text_x = layout->text_x_pos;
1100 canvas->txt_lst[txtCnt].max_x = layout->text_x_pos;
1101 canvas->txt_lst[txtCnt].baseline = layout->y_pos + maxAscent;
1102 canvas->txt_lst[txtCnt].descent = maxDescent;
1103 canvas->txt_lst[txtCnt].ascent = maxAscent;
1104 canvas->txt_lst[txtCnt].byte_index = layout->line_start;
1105 canvas->txt_lst[txtCnt].length = layout->line_bytes;
1106 canvas->txt_lst[txtCnt].seg_ptr = layout->line_seg;
1111 * blank line is one half the normal size line
1115 maxAscent = (maxAscent + maxDescent) / 2;
1119 if (layout->text_x_pos + layout->cur_len > layout->cur_max_x)
1120 layout->cur_max_x = layout->text_x_pos + layout->cur_len;
1122 if (layout->text_x_pos + layout->cur_len > layout->max_x_pos)
1123 layout->max_x_pos = layout->text_x_pos + layout->cur_len;
1126 * zero the string info
1128 layout->line_bytes = 0;
1129 layout->cur_len = 0;
1130 layout->lst_hyper = -1;
1131 layout->lst_vis = False;
1133 _DtCvSetJoinInfo(layout, False, -1);
1136 * adjust where the next line is positioned.
1138 layout->y_pos = layout->y_pos + maxAscent + maxDescent + 1;
1141 /******************************************************************************
1142 * Function: _DtCvCheckAddHyperToTravList
1144 *****************************************************************************/
1146 _DtCvCheckAddHyperToTravList (
1147 _DtCanvasStruct *canvas,
1148 _DtCvSegmentI *p_seg,
1150 _DtCvValue *lst_vis,
1157 _DtCvUnit retLen = *cur_len;
1159 if (_DtCvIsSegALink (p_seg))
1161 nxtHyper = _DtCvGetNextTravEntry(canvas);
1164 * NOTE....should this routine return a value?
1165 * If (re)alloc error occurs, this simply ignores the problem.
1169 prevIdx = nxtHyper - 1;
1171 || _DtCvTraversalLink != canvas->trav_lst[prevIdx].type
1172 || p_seg->link_idx != canvas->trav_lst[prevIdx].seg_ptr->link_idx)
1175 * save this hypertext link in the traversal list
1177 _DtCvSetTravEntryInfo (canvas, nxtHyper, _DtCvTraversalLink, p_seg,
1178 canvas->txt_cnt, _DtCvTRUE);
1183 * take into account the link metrics.
1185 junk = _DtCvIsSegVisibleLink(p_seg);
1186 *lst_vis = _DtCvModifyXpos(canvas->link_info, p_seg, junk,
1187 *lst_vis, *lst_hyper,
1190 * take into account the traversal metrics
1192 junk = _DtCvIsSegALink(p_seg);
1193 (void) _DtCvModifyXpos(canvas->traversal_info, p_seg, junk,
1194 ((_DtCvValue) True), *lst_hyper,
1197 *lst_hyper = p_seg->link_idx;
1199 if (_DtCvTRUE == flag)
1203 /******************************************************************************
1204 * Function: ProcessStringSegment
1206 * chops a string segment up until its completely used.
1209 * 0 if the entire string segment was processed.
1210 * 1 if the required number of lines were processed.
1211 *****************************************************************************/
1213 _DtCvProcessStringSegment(
1214 _DtCanvasStruct *canvas,
1215 _DtCvLayoutInfo *lay_info,
1216 _DtCvUnit max_width,
1219 _DtCvSegmentI *cur_seg,
1220 unsigned int *cur_start,
1221 _DtCvFrmtOption txt_justify,
1222 _DtCvValue stat_flag)
1224 _DtCvUnit workWidth;
1225 _DtCvUnit stringLen;
1226 _DtCvUnit textWidth;
1228 _DtCvUnit spaceSize = 0;
1235 _DtCvValue done = False;
1236 _DtCvSegmentI *retSeg;
1238 if (NULL != _DtCvStringOfStringSeg(cur_seg))
1240 if (lay_info->cur_len == 0)
1242 lay_info->line_seg = cur_seg;
1243 lay_info->line_start = *cur_start;
1246 if (*cur_start == 0 && (cur_seg->type & _DtCvSEARCH_FLAG))
1247 lay_info->delayed_search_saves++;
1249 oldType = _DtCvPrimaryTypeOfSeg (cur_seg);
1252 * is alignment in effect?
1254 if (TRUE == lay_info->align_flag)
1256 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
1257 _DtCvIsSegWideChar(cur_seg), *cur_start);
1258 nWidth = _DtCvStrcspn (pChar, lay_info->align_char,
1259 _DtCvIsSegWideChar(cur_seg),
1265 * we got a valid length back, calculate the length
1269 textWidth = _DtCvGetStringWidth(canvas,cur_seg,pChar,stringLen);
1272 * check to see if this a hypertext that needs
1275 _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvTRUE,
1276 &(lay_info->lst_vis),
1277 &(lay_info->lst_hyper),
1278 &(lay_info->cur_len));
1281 * update the length and position information
1282 * to skip past the characters before the alignment character.
1284 lay_info->line_bytes += stringLen;
1285 lay_info->cur_len += (textWidth
1286 + _DtCvGetTraversalWidth(canvas,
1287 cur_seg, lay_info->lst_hyper));
1289 *cur_start += stringLen;
1292 * if we didn't find the character, check to see if this forces
1293 * a newline - honor it if it does. We'll check the next
1294 * string segment for the alignment character.
1296 if (1 == nWidth && _DtCvIsSegNewLine (cur_seg)
1297 && lay_info->line_bytes)
1299 _DtCvSaveInfo (canvas,lay_info,max_width,r_margin,txt_justify);
1301 while (lay_info->delayed_search_saves > 0) {
1302 _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
1303 lay_info->delayed_search_saves--;
1309 * so we found the character, now get it's width.
1311 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
1312 _DtCvIsSegWideChar(cur_seg), *cur_start);
1313 textWidth = _DtCvGetStringWidth(canvas, cur_seg, pChar, 1)
1314 + _DtCvGetTraversalWidth(canvas, cur_seg,
1315 lay_info->lst_hyper);
1317 * is this the second or more align position?
1318 * if so, need to shift the character to align with others.
1320 if (lay_info->align_pos >
1321 lay_info->text_x_pos + lay_info->cur_len + textWidth / 2)
1322 lay_info->text_x_pos = lay_info->align_pos - lay_info->cur_len
1325 * otherwise, does this exceed the previous alignments?
1326 * if so, the table processing should catch that we've
1327 * changed the alignment position and re-format the others.
1329 else if (lay_info->align_pos <
1330 lay_info->text_x_pos + lay_info->cur_len + textWidth / 2)
1331 lay_info->align_pos =
1332 lay_info->text_x_pos + lay_info->cur_len + textWidth / 2;
1335 * indicate that the character has been found.
1337 lay_info->align_flag = False;
1340 * check to see if this item can end a line.
1341 * if can't end the line, force a join for the next segment or
1342 * for the rest of this segment.
1344 if (False == _DtCvCheckLineSyntax(canvas,cur_seg,*cur_start,1,False))
1345 lay_info->join = True;
1348 * update the length and position information to
1349 * include the character.
1351 lay_info->line_bytes++;
1352 lay_info->cur_len += textWidth;
1357 * check to see if this is the end of the segment.
1359 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
1360 _DtCvIsSegWideChar(cur_seg), *cur_start);
1361 if ((_DtCvIsSegWideChar(cur_seg) && 0 == *((wchar_t *) pChar))
1363 (_DtCvIsSegRegChar(cur_seg) && '\0' == *((char *) pChar)))
1370 * recalculate the width
1372 workWidth = max_width - lay_info->text_x_pos -
1373 lay_info->cur_len - r_margin;
1376 * adjust the character pointer and get the
1377 * length of the string.
1379 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
1380 _DtCvIsSegWideChar(cur_seg), *cur_start);
1381 stringLen = _DtCvStrLen (pChar, _DtCvIsSegWideChar(cur_seg));
1384 * get the pixel width of the text string.
1386 textWidth = _DtCvGetStringWidth(canvas,cur_seg,pChar,stringLen)
1387 + _DtCvGetTraversalWidth(canvas, cur_seg,
1388 lay_info->lst_hyper);
1390 * Will it fit in the current width?
1392 if (stat_flag == True || textWidth <= workWidth)
1395 * Yes, this segment or part of a segment can fit in the
1396 * current width. But can the last character of this
1397 * segment end a line and can the beginning of the next
1398 * segment start a new line?
1400 if (stat_flag == True ||
1401 _DtCvCheckLineSyntax (canvas, cur_seg,
1402 *cur_start, stringLen, False) == TRUE)
1405 * check to see if this a hypertext that needs
1408 _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvFALSE,
1409 &(lay_info->lst_vis),
1410 &(lay_info->lst_hyper),
1411 &(lay_info->cur_len));
1414 * The line syntax is good.
1415 * Update the global and width variables.
1417 lay_info->line_bytes += stringLen;
1418 lay_info->cur_len += textWidth;
1419 _DtCvSetJoinInfo(lay_info,
1420 _DtCvIsSegNonBreakingChar(cur_seg),
1424 * Check to see if this segment forces an end
1426 if (_DtCvIsSegNewLine (cur_seg) && lay_info->line_bytes) {
1427 _DtCvSaveInfo (canvas, lay_info, max_width,
1428 r_margin, txt_justify);
1429 while (lay_info->delayed_search_saves > 0) {
1430 _DtCvSetSearchEntryInfo(canvas,
1431 canvas->txt_cnt - 1);
1432 lay_info->delayed_search_saves--;
1440 * CheckLineSyntax says that either this line couldn't
1441 * end a line or the next segment couldn't start a line.
1442 * Therefore, find out how much of the next segment or
1443 * segments we need to incorporate to satisfy the Line
1446 nWidth = _DtCvGetNextWidth (canvas, oldType,
1447 lay_info->lst_hyper,
1448 cur_seg->next_seg, 0, cur_seg,
1449 &retSeg, &retStart, &retCount);
1451 * will this segment + the next segment fit?
1453 if (textWidth + nWidth <= workWidth)
1456 * check to see if this a hypertext that needs
1459 _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvFALSE,
1460 &(lay_info->lst_vis),
1461 &(lay_info->lst_hyper),
1462 &(lay_info->cur_len));
1465 * YEAH Team!! It Fits!!
1467 * Update the global and width variables.
1469 lay_info->line_bytes += stringLen;
1470 lay_info->cur_len += textWidth;
1471 _DtCvSetJoinInfo(lay_info, False, -1);
1478 * the text width plus the next segment is tooo big
1479 * to fit. Reduce the current segment if possible
1486 nWidth = _DtCvGetNextWidth (canvas, oldType,
1487 lay_info->lst_hyper,
1488 cur_seg, *cur_start, NULL,
1489 &retSeg, &retStart, &retCount);
1491 if (retSeg == cur_seg && textWidth + nWidth <= workWidth)
1494 * check to see if this a hypertext that needs
1497 _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvFALSE,
1498 &(lay_info->lst_vis),
1499 &(lay_info->lst_hyper),
1500 &(lay_info->cur_len));
1502 _DtCvSetJoinInfo(lay_info, False, -1);
1503 *cur_start = retStart;
1504 stringLen += retCount;
1505 textWidth += nWidth;
1509 * take into account a space if that is where it breaks.
1511 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
1512 _DtCvIsSegWideChar(cur_seg),
1514 if ((_DtCvIsSegWideChar(cur_seg) &&
1515 (' ' == *((wchar_t *) pChar)))
1517 (_DtCvIsSegRegChar(cur_seg) &&
1518 (' ' == *((char *) pChar))))
1520 spaceSize = _DtCvGetStringWidth(canvas,
1522 + _DtCvGetTraversalWidth (canvas,
1523 cur_seg, lay_info->lst_hyper);
1524 textWidth += spaceSize;
1532 * Done trying to find a segment that will
1533 * fit in the size given
1540 * Update the global variables
1542 lay_info->line_bytes += stringLen;
1543 lay_info->cur_len += textWidth;
1545 if (lay_info->join == True || lay_info->line_bytes == 0)
1548 * This line would be empty if we followed the rules.
1549 * Or it would break a line improperly.
1550 * Force this onto the line.
1551 * check to see if this a hypertext that needs
1554 _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvTRUE,
1555 &(lay_info->lst_vis),
1556 &(lay_info->lst_hyper),
1557 &(lay_info->cur_len));
1560 * Couldn't find a smaller, have to
1561 * go with the larger segment.
1563 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
1564 _DtCvIsSegWideChar(cur_seg),
1566 stringLen = _DtCvStrLen (pChar, _DtCvIsSegWideChar(cur_seg));
1567 if (retCount > 0 && retCount < stringLen)
1568 stringLen = retCount;
1570 lay_info->line_bytes += stringLen;
1571 lay_info->cur_len += (_DtCvGetStringWidth(canvas, cur_seg,
1573 + _DtCvGetTraversalWidth (canvas,
1574 cur_seg, lay_info->lst_hyper));
1576 _DtCvSetJoinInfo(lay_info, False, -1);
1579 * If we had to do a bigger segment,
1580 * then we're done processing the target segment.
1582 if (stringLen == _DtCvStrLen(pChar,_DtCvIsSegWideChar(cur_seg)))
1584 if (_DtCvCheckLineSyntax (canvas, cur_seg,
1585 *cur_start, stringLen, False) == False)
1586 _DtCvSetJoinInfo(lay_info, True, -1);
1587 else if (_DtCvIsSegNewLine (cur_seg)) {
1588 _DtCvSaveInfo (canvas, lay_info, max_width,
1589 r_margin, txt_justify);
1590 while (lay_info->delayed_search_saves > 0) {
1591 _DtCvSetSearchEntryInfo(canvas,
1592 canvas->txt_cnt - 1);
1593 lay_info->delayed_search_saves--;
1599 *cur_start = retStart;
1604 * If a space was included as the last character,
1607 lay_info->line_bytes--;
1608 lay_info->cur_len -= spaceSize;
1612 * Save the information
1614 _DtCvSaveInfo (canvas, lay_info, max_width, r_margin, txt_justify);
1615 if (*cur_start == 0 && (cur_seg->type & _DtCvSEARCH_FLAG))
1616 lay_info->delayed_search_saves--;
1618 while (lay_info->delayed_search_saves > 0) {
1619 _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
1620 lay_info->delayed_search_saves--;
1626 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
1627 _DtCvIsSegWideChar(cur_seg),
1629 if (_DtCvIsSegWideChar(cur_seg))
1640 else /* single byte string */
1643 while (' ' == *strPtr)
1653 * are we at the end of the segment?
1655 if ((_DtCvIsSegWideChar(cur_seg) && 0 == *((wchar_t *) pChar))
1657 (_DtCvIsSegRegChar(cur_seg) && 0 == *((char *) pChar)))
1660 if (*cur_start == 0 && (cur_seg->type & _DtCvSEARCH_FLAG))
1661 lay_info->delayed_search_saves++;
1664 * Initialize the global variables
1666 lay_info->line_seg = cur_seg;
1667 lay_info->line_start = *cur_start;
1668 lay_info->text_x_pos = l_margin;
1670 if (CheckFormat(lay_info) == True)
1674 * check to see if this a hypertext that needs
1677 _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvTRUE,
1678 &(lay_info->lst_vis),
1679 &(lay_info->lst_hyper),
1680 &(lay_info->cur_len));
1683 else if (_DtCvIsSegNewLine (cur_seg))
1686 * Force a save - even if it is an empty line.
1688 _DtCvSaveInfo (canvas, lay_info, max_width, r_margin, txt_justify);
1689 while (lay_info->delayed_search_saves > 0) {
1690 _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
1691 lay_info->delayed_search_saves--;
1697 } /* End _DtCvProcessStringSegment */
1699 /******************************************************************************
1700 * Function: _DtCvSetJoinInfo
1702 * Returns: sets the joining information to the given information.
1704 *****************************************************************************/
1707 _DtCvLayoutInfo *lay_info,
1711 lay_info->join = flag;
1712 lay_info->join_line = txt_ln;
1715 /******************************************************************************
1716 * Function: _DtCvGetNextTravEntry
1718 * Returns: >= 0 if success,
1721 * Purpose: Return the next available entry in the traversal list.
1723 *****************************************************************************/
1725 _DtCvGetNextTravEntry (
1726 _DtCanvasStruct *canvas)
1728 int nxtEntry = canvas->trav_cnt;
1731 * does the list need to grow?
1733 if (nxtEntry >= canvas->trav_max)
1736 * grow by a set amount
1738 canvas->trav_max += GROW_SIZE;
1741 * realloc or malloc?
1743 if (NULL != canvas->trav_lst)
1744 canvas->trav_lst = (_DtCvTraversalInfo *) realloc (
1745 (char *) canvas->trav_lst,
1746 ((sizeof(_DtCvTraversalInfo)) * canvas->trav_max));
1748 canvas->trav_lst = (_DtCvTraversalInfo *) malloc (
1749 ((sizeof(_DtCvTraversalInfo)) * canvas->trav_max));
1752 * did the memory allocation work? if not return error code.
1754 if (NULL == canvas->trav_lst)
1756 canvas->trav_max = 0;
1757 canvas->trav_cnt = 0;
1762 canvas->trav_lst[nxtEntry] = DefTravData;
1767 /******************************************************************************
1768 * Function: _DtCvSetTravEntryInfo
1770 * Returns: 0 if success,
1773 * Purpose: Set the high level information in an entry of the traversal
1775 *****************************************************************************/
1777 _DtCvSetTravEntryInfo (
1778 _DtCanvasStruct *canvas,
1780 _DtCvTraversalType type,
1781 _DtCvSegmentI *p_seg,
1787 if (-1 != entry && entry <= canvas->trav_cnt)
1789 _DtCvTraversalInfo *travEntry = &(canvas->trav_lst[entry]);
1791 travEntry->type = type;
1792 travEntry->seg_ptr = p_seg;
1793 travEntry->idx = line_idx;
1795 if (_DtCvTRUE == inc)
1805 _DtCvGetNextSearchEntry(_DtCanvasStruct* canvas)
1807 if (canvas->search_cnt >= canvas->search_max) {
1808 canvas->search_max += GROW_SIZE;
1810 if (canvas->searchs)
1811 canvas->searchs = (_DtCvSearchData *)
1812 realloc((void*)canvas->searchs,
1813 canvas->search_max * sizeof(_DtCvSearchData));
1815 canvas->searchs = (_DtCvSearchData *)
1816 malloc(canvas->search_max * sizeof(_DtCvSearchData));
1819 canvas->searchs[canvas->search_cnt].idx = -1;
1821 return canvas->search_cnt++;
1825 _DtCvSetSearchEntryInfo(_DtCanvasStruct* canvas, int line_idx)
1829 /* get a next available slot for search */
1830 search_idx = _DtCvGetNextSearchEntry(canvas);
1832 /* save information (i.e. line_idx) */
1833 canvas->searchs[search_idx].idx = line_idx;
1836 /******************************************************************************
1837 * Function: _DtCvSetTravEntryPos
1839 * Returns: 0 if success,
1842 * Purpose: Set the position and dimension information of an entry in
1843 * the traversal list.
1845 *****************************************************************************/
1847 _DtCvSetTravEntryPos (
1848 _DtCanvasStruct *canvas,
1857 if (-1 != entry && entry <= canvas->trav_cnt)
1859 _DtCvTraversalInfo *travEntry = &(canvas->trav_lst[entry]);
1861 travEntry->x_pos = x;
1862 travEntry->y_pos = y;
1863 travEntry->width = width;
1864 travEntry->height = height;
1872 /******************************************************************************
1873 * Function: _DtCvCalcMarkPos
1875 * Returns: 0 if success,
1878 * Purpose: Calcalate the position and dimension information of a mark.
1880 *****************************************************************************/
1883 _DtCanvasStruct *canvas,
1887 _DtCvUnit *ret_width,
1888 _DtCvUnit *ret_height)
1892 if (-1 != entry && entry <= canvas->mark_cnt)
1894 _DtCvMarkData *mark = &(canvas->marks[entry]);
1897 * if we've got a line index for the mark, get the positions.
1899 if (-1 != mark->beg.line_idx && -1 != mark->end.line_idx)
1901 _DtCvDspLine *line = &(canvas->txt_lst[mark->beg.line_idx]);
1903 *ret_x = mark->beg.x;
1904 *ret_y = mark->beg.y - line->ascent;
1906 if (mark->beg.line_idx == mark->end.line_idx)
1907 *ret_width = mark->end.x - *ret_x;
1909 *ret_width = canvas->txt_lst[mark->beg.line_idx].max_x - *ret_x;
1911 *ret_height = line->ascent + line->descent + 1;
1920 /******************************************************************************
1921 * Function: _DtCvSortTraversalList
1925 * Purpose: Sort the traversal list
1927 *****************************************************************************/
1929 _DtCvSortTraversalList (
1930 _DtCanvasStruct *canvas,
1933 int curTrav = canvas->cur_trav;
1935 if (1 < canvas->trav_cnt)
1938 * indicate this is the current traversal
1941 canvas->trav_lst[curTrav].active = retain;
1946 qsort (canvas->trav_lst, canvas->trav_cnt, sizeof(_DtCvTraversalInfo),
1947 CompareTraversalPos);
1949 if (_DtCvTRUE == retain && -1 != curTrav &&
1950 _DtCvFALSE == canvas->trav_lst[curTrav].active)
1953 while (_DtCvFALSE == canvas->trav_lst[curTrav].active)
1956 canvas->cur_trav = curTrav;
1960 * clear the active flag
1963 canvas->trav_lst[curTrav].active = _DtCvFALSE;
1967 /*****************************************************************************
1968 * Function: _DtCvCvtSegsToPts()
1970 * Purpose: Given a set of segments, determine the ending points.
1972 *****************************************************************************/
1975 _DtCanvasStruct *canvas,
1976 _DtCvSegPtsI **segs,
1977 _DtCvSelectData *beg,
1978 _DtCvSelectData *end,
1981 _DtCvSegmentI **ret_seg)
1989 _DtCvValue lastVisLnk = _DtCvFALSE;
1990 _DtCvUnit minY = -1;
1995 _DtCvSegmentI *pSeg;
1996 _DtCvSegmentI *saveSeg;
1997 _DtCvSegmentI **retSeg;
1998 _DtCvDspLine *lines = canvas->txt_lst;
1999 _DtCvFlags result = _DtCvSTATUS_NONE;
2000 _DtCvSelectData *tmpBeg;
2001 _DtCvSelectData *tmpEnd;
2002 _DtCvSelectData bReg;
2003 _DtCvSelectData eReg;
2006 * initialize the structures.
2008 bReg = DefSelectData;
2009 eReg = DefSelectData;
2010 *beg = DefSelectData;
2011 *end = DefSelectData;
2014 * go through each segment and determine the starting positions.
2016 while (NULL != *segs)
2018 result = _DtCvSTATUS_OK;
2021 * what line is this segment on?
2023 lineIdx = (long) ((*segs)->segment->internal_use);
2026 * get some information about the line
2028 length = lines[lineIdx].length;
2029 start = lines[lineIdx].byte_index;
2030 startX = _DtCvGetStartXOfLine(&(lines[lineIdx]), &pSeg);
2031 pSeg = lines[lineIdx].seg_ptr;
2034 * now skip the segments on this line that aren't in the data pt.
2036 while (NULL != pSeg && pSeg != (*segs)->segment)
2039 * advance past any hypertext link offsets.
2041 startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
2042 &linkIdx, &lastVisLnk);
2045 * we know that this is not the segment we are looking for,
2048 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
2049 &cnt, &segWidth, NULL);
2052 * skip the segment's width, decrease the overall length by
2053 * the segment's count, reset the character start point and
2054 * go to the next segment.
2059 pSeg = pSeg->next_disp;
2063 * This segment should be all or partially selected.
2066 return _DtCvSTATUS_BAD;
2069 * now figure the start location.
2071 startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
2072 &linkIdx, &lastVisLnk);
2074 * guarenteed that this is the *first* line that the segment
2075 * exists on. Therefore, may have to go to another line for
2076 * the correct offset
2078 while (start + length < (*segs)->offset)
2080 do { lineIdx++; } while (lineIdx < canvas->txt_cnt
2081 && pSeg != lines[lineIdx].seg_ptr);
2083 if (lineIdx >= canvas->txt_cnt)
2084 return _DtCvSTATUS_BAD;
2086 length = lines[lineIdx].length;
2087 start = lines[lineIdx].byte_index;
2088 startX = lines[lineIdx].text_x;
2092 startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
2093 &linkIdx, &lastVisLnk);
2097 * how many characters do we need to skip?
2099 count = (*segs)->offset - start;
2102 _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
2103 &cnt, &segWidth, NULL);
2105 * adjust the info by the width of the skipped characters.
2112 * is this a region? If so set the region information instead.
2117 if (_DtCvIsSegRegion((*segs)->segment))
2125 * does this segment start the selection? text or region?
2127 if (tmpBeg->x == -1 || tmpBeg->y > lines[lineIdx].baseline ||
2128 (tmpBeg->line_idx == lineIdx && tmpBeg->x > startX))
2131 tmpBeg->y = lines[lineIdx].baseline;
2132 tmpBeg->line_idx = lineIdx;
2133 tmpBeg->char_idx = lines[lineIdx].length - length;
2135 *retSeg = (*segs)->segment;
2139 * get the amount of this segment that is selected.
2141 count = (*segs)->len;
2144 * is it longer than what's (left) on this line?
2146 while (count > length)
2149 * go to the next line containing the segment
2153 * does this line have the minium y?
2156 minY > lines[lineIdx].baseline - lines[lineIdx].ascent)
2157 minY = lines[lineIdx].baseline - lines[lineIdx].ascent;
2160 } while (lineIdx < canvas->txt_cnt
2161 && pSeg != lines[lineIdx].seg_ptr);
2163 * did we run out of lines?
2165 if (lineIdx >= canvas->txt_cnt)
2166 return _DtCvSTATUS_BAD;
2169 * start over on this line
2174 * get the true count to the next offset
2176 cnt = lines[lineIdx].byte_index - start;
2179 * get the next lines starting info.
2181 start = lines[lineIdx].byte_index;
2182 length = lines[lineIdx].length;
2183 startX = _DtCvGetStartXOfLine(&(lines[lineIdx]), &pSeg);
2186 startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
2187 &linkIdx, &lastVisLnk);
2189 * subtract the previous length
2195 * now go down the line, examining each segment.
2200 * findout how many characters are in the next segment, and its
2203 _DtCvGetWidthOfSegment(canvas,pSeg,start,count,&cnt,&segWidth,NULL);
2206 * there are less than in the count, go to the next segment.
2210 pSeg = pSeg->next_disp;
2219 endX = startX + segWidth;
2222 * does this segment end a segment?
2224 if (tmpEnd->x == -1 || tmpEnd->y < lines[lineIdx].baseline ||
2225 (tmpEnd->line_idx == lineIdx && tmpEnd->x < endX))
2228 tmpEnd->y = lines[lineIdx].baseline;
2229 tmpEnd->line_idx = lineIdx;
2230 tmpEnd->char_idx = lines[lineIdx].length - length;
2234 * check for min and max values
2237 minY > lines[lineIdx].baseline - lines[lineIdx].ascent)
2238 minY = lines[lineIdx].baseline - lines[lineIdx].ascent;
2240 if (maxY < lines[lineIdx].baseline + lines[lineIdx].descent)
2241 maxY = lines[lineIdx].baseline + lines[lineIdx].descent;
2243 * go to the next segment
2249 * now determine if a region really starts the beginning of a
2250 * selection or a text does.
2252 * was a region found?
2257 * if no text was found, take the region information.
2262 if (NULL != ret_seg)
2266 * or if the region is inline to the other
2267 * text and it is before the text, then take it's x value.
2269 else if (bReg.x < beg->x &&
2270 (bReg.line_idx == beg->line_idx ||
2272 * Or if the region is 'standalone' (a bullet of a list, a
2273 * graphic to wrap around, etc.) then check to see if it
2274 * straddles the other information and is before the text. If
2275 * it does, take it's x value.
2277 _DtCvStraddlesPt(beg->y,
2278 bReg.y - lines[bReg.line_idx].ascent,
2279 bReg.y - lines[bReg.line_idx].descent)))
2283 if (NULL != ret_seg)
2289 * now determine if a region really ends the selection or a text does.
2291 * was a region found?
2296 * if no text was found, take the region information.
2301 * or if the region is inline to the other
2302 * text and it is before the text, then take it's x value.
2304 else if (eReg.x > end->x &&
2305 (eReg.line_idx == end->line_idx ||
2307 * Or if the region is 'standalone' (a bullet of a list, a
2308 * graphic to wrap around, etc.) then check to see if it
2309 * straddles the other information and is before the text. If
2310 * it does, take it's x value.
2312 _DtCvStraddlesPt(end->y,
2313 eReg.y - lines[eReg.line_idx].ascent,
2314 eReg.y - lines[eReg.line_idx].descent)))
2326 /*****************************************************************************
2327 * Function: _DtCvAddToMarkList()
2329 * Purpose: Add a mark to the list of marks.
2331 *****************************************************************************/
2333 _DtCvAddToMarkList (
2334 _DtCanvasStruct *canvas,
2335 _DtCvPointer client_data,
2337 _DtCvSelectData *beg,
2338 _DtCvSelectData *end)
2340 _DtCvMarkData *nxtMark;
2343 * does the array need more memory?
2345 if (canvas->mark_cnt >= canvas->mark_max)
2347 canvas->mark_max += GROW_SIZE;
2349 if (NULL == canvas->marks)
2350 canvas->marks = (_DtCvMarkData *) malloc(
2351 sizeof(_DtCvMarkData) * canvas->mark_max);
2353 canvas->marks = (_DtCvMarkData *) realloc((void *) canvas->marks,
2354 sizeof(_DtCvMarkData) * canvas->mark_max);
2357 * memory loss - bail
2359 if (NULL == canvas->marks)
2364 * set the mark information
2366 nxtMark = &(canvas->marks[canvas->mark_cnt]);
2368 nxtMark->client_data = client_data;
2369 nxtMark->beg = *beg;
2370 nxtMark->end = *end;
2373 return (canvas->mark_cnt - 1);