cdesktopenv/cde/lib/DtHelp/Canvas.c

2875 lines
74 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $TOG: Canvas.c /main/40 1999/10/14 13:17:22 mgreess $ */
/************************************<+>*************************************
****************************************************************************
**
** File: Canvas.c
**
** Project: Cde Help System
**
** Description: UI independent layer for the help system. These
** routines manage the information within a 'canvas'.
** The 'canvas' routines call UI dependent code to
** render the information.
**
** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
**
** (c) Copyright 1993, 1994 Hewlett-Packard Company
** (c) Copyright 1993, 1994 International Business Machines Corp.
** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
** (c) Copyright 1993, 1994 Novell, Inc.
****************************************************************************
************************************<+>*************************************/
/*
* system includes
*/
#include <stdlib.h>
#include <string.h>
/*
* Canvas Engine includes
*/
#include "CanvasP.h"
#include "CanvasSegP.h"
/*
* private includes
*/
#include "CanvasI.h"
#include "CvStringI.h"
#include "LinkMgrI.h"
#include "LayoutUtilI.h"
#include "SelectionI.h"
#include "VirtFuncsI.h"
#ifdef NLS16
#endif
/******** Private Function Declarations ********/
static _DtCvUnit DrawText(
_DtCanvasStruct *canvas,
_DtCvDspLine *line,
int txt_line,
_DtCvFlags old_flag,
_DtCvFlags new_flag );
/******** End Private Function Declarations ********/
/*****************************************************************************
* Private Variables
*****************************************************************************/
static _DtCanvasStruct DefaultCanvas =
{
0, /* int error; */
0, /* int txt_cnt; */
0, /* int txt_max; */
0, /* int line_cnt; */
0, /* int line_max; */
0, /* int mark_cnt; */
0, /* int mark_max; */
0, /* int trav_cnt; */
0, /* int trav_max; */
0, /* int cur_trav; */
0, /* search_cnt */
0, /* search_max */
0, /* brk_cnt */
0, /* brk_max */
1, /* short mb_length; */
0, /* _DtCvUnit max_x; */
0, /* _DtCvUnit max_y; */
_DtCvIGNORE_BOUNDARY, /* _DtCvValue constraint; */
_DtCvFALSE, /* _DtCvValue trav_on; */
NULL, /* _DtCvPointer client_data; */
{ /* CanvasMetrics metrics; */
0, /* _DtCvUnit width; */
0, /* _DtCvUnit height; */
0, /* _DtCvUnit top_margin; */
0, /* _DtCvUnit line_height; */
0, /* _DtCvUnit horiz_pad_hint; */
},
{ /* _DtCvSpaceMetrics link_info; */
0, /* _DtCvUnit space_before; */
0, /* _DtCvUnit space_after; */
0, /* _DtCvUnit space_above; */
0, /* _DtCvUnit space_below; */
},
{ /* _DtCvSpaceMetrics traversal_info; */
0, /* _DtCvUnit space_before; */
0, /* _DtCvUnit space_after; */
0, /* _DtCvUnit space_above; */
0, /* _DtCvUnit space_below; */
},
{ /* _DtCvLocale locale; */
_DtCvModeWrapNone, /* _DtCvModeType line_wrap_mode; */
NULL, /* const wchar_t *cant_begin_chars; */
NULL, /* const wchar_t *cant_end_chars; */
},
NULL, /* _DtCvSegment *element_lst; */
NULL, /* _DtCvDspLine *txt_lst; */
NULL, /* _DtCvLineSeg *line_lst; */
NULL, /* _DtCvTraversalInfo *trav_lst; */
NULL, /* _DtCvLinkDb link_data; */
{ /* CESelection select_start; */
-1, /* _DtCvUnit x; */
-1, /* _DtCvUnit y; */
-1, /* int line_idx; */
-1, /* int char_idx; */
},
{ /* CESelection select_end; */
-1, /* _DtCvUnit x; */
-1, /* _DtCvUnit y; */
-1, /* int line_idx; */
-1, /* int char_idx; */
},
NULL, /* _DtCvMarkData *marks; */
NULL, /* searchs */
NULL, /* pg_breaks */
{ NULL }, /* _DtCvVirtualInfo virt_functions; */
};
/*****************************************************************************
* Private Functions
*****************************************************************************/
/*****************************************************************************
* Function: RenderSubSet
*
* Returns: nothing
* Purpose: Render the items next to an item of text.
*
*****************************************************************************/
static void
RenderSubSet (
_DtCanvasStruct *canvas,
_DtCvDspLine *lines,
int cnt,
_DtCvUnit y1,
_DtCvUnit y2,
_DtCvUnit *last_y)
{
int i;
_DtCvUnit minY;
_DtCvUnit maxY;
/*
* Loop through the list looking for the item(s) next to the text.
*/
for (i = 0; NULL != lines && i < cnt; lines++, i++)
{
/*
* get the minimum and maximum y of the next line
*/
minY = lines->baseline - lines->ascent;
maxY = lines->baseline + lines->descent;
/*
* has this line been reviewed yet?
* is this line on the 'page'?
* Does it hang off the 'page' (and if so is it allowed)?
*/
if (_DtCvIsNotProcessed(*lines) && maxY >= y1 && maxY <= y2)
{
(void) DrawText (canvas, lines, i, 0, 0);
/*
* indicate that this line has been rendered.
*/
_DtCvSetProcessed(*lines);
/*
* is this the maximum that we've rendered?
*/
if (*last_y < maxY)
*last_y = maxY;
/*
* now render anything next to this!
*/
RenderSubSet(canvas, canvas->txt_lst, cnt, minY, y2, last_y);
}
}
}
/*****************************************************************************
* Function: CheckAround
*
* Returns: _DtCvSTATUS_NONE if no other text is to the side of
* this text.
* _DtCvFALSE if other text is to the side, but the
* maximum y position is not violated.
* _DtCvTRUE if other text is to the side and the
* maximum y position is violated.
* Purpose: Find if another line of text intrudes upon this line.
*
*****************************************************************************/
static _DtCvStatus
CheckAround (
_DtCvDspLine *lines,
int cnt,
int idx,
_DtCvUnit y2)
{
int i = 0;
_DtCvUnit topY = lines[idx].baseline - lines[idx].ascent;
_DtCvUnit botY = lines[idx].baseline + lines[idx].descent;
_DtCvUnit minY;
_DtCvUnit maxY;
_DtCvStatus result = _DtCvSTATUS_NONE;
/*
* set the processed flag so that we don't test something that's
* already tested.
*/
_DtCvSetProcessed(lines[idx]);
/*
* go through looking for unprocessed lines to test.
*/
while (i < cnt && _DtCvTRUE != result)
{
if (_DtCvIsNotProcessed(lines[i]))
{
/*
* calculate the minimum and maximum y positions for the line.
*/
minY = lines[i].baseline - lines[i].ascent;
maxY = lines[i].baseline + lines[i].descent;
/*
* Does this line infringe vertically on the test line?
*/
if (maxY > topY && minY < botY &&
_DtCvTRUE == _DtCvCheckInfringement(topY, botY, minY, maxY))
{
/*
* indicate that it is not clear to the side.
*/
result = _DtCvFALSE;
/*
* Does it have something else infringing one it?
* Or does it hang down below the test line?
*/
if (maxY > y2 || _DtCvTRUE == CheckAround(lines, cnt, i, y2))
result = _DtCvTRUE;
}
}
i++;
}
/*
* Clear that this line has be processed. Otherwise, rendering will
* think this has been rendered when it hasn't.
*/
_DtCvClearProcessed(lines[idx]);
return result;
}
/*****************************************************************************
* Function: FindChar
*
* FindChar calculates the char that is x pixels into the string.
*
*****************************************************************************/
static int
FindChar (
_DtCanvasStruct *canvas,
_DtCvSegmentI *segment,
void *string,
int max_len,
_DtCvUnit x_pos,
_DtCvUnit *diff)
{
int myIndex;
_DtCvUnit myDiff = 0;
_DtCvUnit len;
_DtCvUnit charWidth;
_DtCvValue triedBack = False;
_DtCvValue triedForward = False;
/*
* get information about the font used
*/
_DtCvFontMetrics(canvas, _DtCvFontOfStringSeg(segment),
NULL, NULL, &charWidth, NULL, NULL);
/*
* try to get close to the correct index.
*/
myIndex = x_pos / charWidth;
if (myIndex >= max_len)
myIndex = max_len - 1;
while (!triedBack || !triedForward)
{
len = _DtCvGetStringWidth(canvas, segment, string, myIndex + 1);
if (len > x_pos)
{
myDiff = len - x_pos;
triedForward = True;
if (!triedBack && myIndex)
myIndex--;
else
triedBack = True;
}
else if (len < x_pos)
{
myDiff = x_pos - len;
triedBack = True;
myIndex++;
if (myIndex >= max_len)
{
myIndex--;
triedForward = True;
}
}
else /* len == x_pos */
{
myIndex++;
triedBack = True;
triedForward = True;
myDiff = 0;
}
}
if (diff != NULL)
*diff = myDiff;
return (myIndex);
}
/*****************************************************************************
* Function: DrawCanvasLines
*
*****************************************************************************/
static void
DrawCanvasLines(
_DtCanvasStruct *canvas,
_DtCvUnit x1,
_DtCvUnit y1,
_DtCvUnit x2,
_DtCvUnit y2,
_DtCvRenderType flag,
_DtCvUnit *ret_y,
_DtCvUnit *ret_next)
{
int i;
_DtCvUnit newY2 = y2;
_DtCvLineSeg *pLS;
_DtCvLineInfo lnInfo;
/*
* are there any lines?
*/
if (canvas->line_lst != NULL && canvas->line_cnt &&
NULL != canvas->virt_functions.render_elem)
{
/*
* find the maximum y of all the lines that fit in the page.
* do this only if the flag indicates whole lines.
*/
if (_DtCvRENDER_COMPLETE == flag)
{
for (i = 0, pLS = canvas->line_lst;
i < canvas->line_cnt; i++, pLS++)
{
/*
* Does this line end off the page?
*/
if (pLS->max_y > newY2 && pLS->pos_y < newY2)
newY2 = pLS->pos_y - 1;
}
}
/*
* check each line to see if it is on the 'page'
*/
for (i = 0, pLS = canvas->line_lst; i < canvas->line_cnt; i++, pLS++)
{
lnInfo.width = pLS->width;
lnInfo.data = pLS->data;
lnInfo.x2 = pLS->pos_x;
lnInfo.y2 = pLS->pos_y;
/*
* horizontal or vertial line?
*/
if (_DtCvLINE_HORZ == pLS->dir)
lnInfo.x2 = pLS->max_x;
else
lnInfo.y2 = pLS->max_y;
/*
* does it fit on the page? Take into account the rendering type.
*/
if (pLS->max_y >= y1 && pLS->pos_y <= newY2
&& lnInfo.x2 >= x1 && pLS->pos_x <= x2
&& (_DtCvRENDER_PARTIAL == flag || pLS->max_y <= newY2))
{
if (pLS->max_y > *ret_y)
*ret_y = pLS->max_y;
(*(canvas->virt_functions.render_elem))(
canvas->client_data, _DtCvLINE_TYPE,
pLS->pos_x, pLS->pos_y, -1, 0, 0,
_DtCvBAD_TYPE, NULL, &lnInfo);
}
/*
* otherwise, would this start the next page?
* make sure this is in the horizontal space.
*/
else if (lnInfo.x2 >= x1 && pLS->pos_x <= x2 && pLS->max_y > newY2
&& (-1 == *ret_next || *ret_next > pLS->pos_y))
*ret_next = pLS->pos_y;
}
}
} /* End DrawCanvasLines */
/******************************************************************************
* Function: DrawText
*
* Parameters:
* canvas Specifies the canvas on which to render
* the text.
* line Specifies the line in the line table.
* start_x Specifies the starting x position to use
* for selected text. If greater than the
* starting position for the segment, determine
* the closest character to 'start_x' and
* use it.
* end_x Specifies the ending x position to use
* for selected text. If -1, means display
* the entire set of segments.
* old_flag Specifies....
* new_flag Specifies....
*
* Returns: max_x Returns the maximum x unit processed.
*
* Purpose: DrawText draws text segments on one line in the
* line table.
*
*****************************************************************************/
static _DtCvUnit
DrawText(
_DtCanvasStruct *canvas,
_DtCvDspLine *line,
int txt_line,
_DtCvFlags old_flag,
_DtCvFlags new_flag )
{
int len;
int curIdx = 0;
int lastLnk = -1;
int count = line->length;
int start = line->byte_index;
_DtCvUnit xPos;
_DtCvUnit superWidth = 0;
_DtCvUnit superY = 0;
_DtCvUnit subWidth = 0;
_DtCvUnit subY = 0;
_DtCvUnit scriptX = 0;
_DtCvValue lastWasSuper = False;
_DtCvValue lastWasSub = False;
_DtCvValue lastLnkVis = False;
_DtCvSegmentI *pSeg;
xPos = _DtCvGetStartXOfLine(line, &pSeg);
/*
* get the corrected x for links and traversals.
*/
xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos, &lastLnk, &lastLnkVis);
/*
* take into account the if this is a super or sub script - or not.
*/
xPos = _DtCvAdjustForSuperSub(canvas, pSeg, xPos,
&scriptX, &superWidth, &superY,
&subWidth, &subY,
&lastWasSuper, &lastWasSub);
/*
* now process the line
*/
while (NULL != pSeg && 0 < count)
{
len = count;
/*
* check for selected and marked text.
*/
_DtCvCheckLineMarks(canvas, txt_line, curIdx, count, xPos,
(_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
&len, &old_flag, &new_flag);
/*
* if this is the last segment(s) of the (un)selection
* set the end flags.
*/
if (len == count)
{
new_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
old_flag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
}
/*
* render the segment length returned by _DtCvCheckLineMarks
*/
xPos = _DtCvDrawSegments(canvas, *line, pSeg, start, len,
&lastLnk, xPos, xPos,
&scriptX, &superWidth, &superY, &subWidth,
&subY, &lastWasSub, &lastWasSuper,
&lastLnkVis, old_flag, new_flag,
_DtCvBAD_TYPE, NULL);
/*
* decrement the count by the length processed
*/
count -= len;
curIdx += len;
if (0 < count)
_DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
&start, &pSeg);
}
return xPos;
} /* End DrawText */
/*****************************************************************************
* Function: IsLineSpecial (
*
* Purpose: Call a virtual function to draw the traversal indicator
*****************************************************************************/
static _DtCvValue
IsLineSpecial (
_DtCvSelectData start,
_DtCvSelectData end,
_DtCvDspLine line,
int line_idx,
int char_idx,
int length,
_DtCvUnit dst_x,
int *ret_len,
_DtCvFlags *ret_flag)
{
_DtCvUnit maxY = line.baseline + line.descent;
_DtCvUnit minY = line.baseline - line.ascent;
_DtCvFlags flag = 0;
/*
* zero out the return flag (which will be a logical OR of
* the mark flags.
*/
if (NULL != ret_flag)
*ret_flag = 0;
/*
* initialize the return value to the given inspection length.
*/
*ret_len = length;
/*
* is there anything to look at?
*/
if (start.y == -1 || maxY < start.y || minY >= end.y)
return False;
/*
* starts the mark/selection?
*/
if (line_idx == start.line_idx)
{
/*
* does this segment straddle the start of the mark/selection?
*/
if (start.char_idx > char_idx)
{
/*
* draw part(or all) of the segment un-mark/selected.
* never return a value larger than the inspection length!
*/
if (start.char_idx < char_idx + length)
*ret_len = start.char_idx - char_idx;
return False;
}
/*
* does this segment start the line? Set the start flag if so.
*/
if (start.char_idx == char_idx)
flag |= _DtCvMARK_BEGIN;
/*
* does this line end the mark/selection?
*/
if (line_idx == end.line_idx)
{
/*
* does this line straddle the end?
*/
if (char_idx >= end.char_idx)
{
/*
* draw this un mark/selected.
* Its after the mark/selected part.
*/
return False;
}
if (char_idx + length > end.char_idx)
{
/*
* draw the mark/selected part
*/
*ret_len = end.char_idx - char_idx;
flag |= _DtCvMARK_END;
}
}
/*
* draw the current *ret_len as mark/selected
*/
}
/*
* does this start the mark/selection?
*/
else if (line_idx == end.line_idx)
{
/*
* does not start the mark/selection.
* does end the mark/selection.
*/
if (char_idx >= end.char_idx)
return False;
/*
* straddle the end position?
*/
if (char_idx + length > end.char_idx)
{
*ret_len = end.char_idx - char_idx;
flag |= _DtCvMARK_END;
}
/*
* draw the current *ret_len as mark/selected
*/
}
/*
* start.y != -1
* start.y <= maxY && minY < end.y
*/
else if (minY < start.y)
{
/*
* straddles the start y
*/
if (dst_x < start.x)
return False;
/*
* dst_x > start.x
*/
if (start.y != end.y)
{
if (NULL != ret_flag)
*ret_flag = flag;
return True;
}
/*
* dst_x >= end.x
*/
if (dst_x > end.x)
return False;
}
/*
* start.y <= minY and maxY
* minY < end.y
*/
else if (end.y <= maxY)
{
/*
* straddles the end y position
*/
if (dst_x >= end.x)
return False;
}
/*
* start.y <= minY and maxY
* minY && maxY < end.y
*/
if (NULL != ret_flag)
*ret_flag = flag;
return True;
}
/*****************************************************************************
* Function: DrawTraversalIndicator (_DtCanvasStruct *canvas, _DtCvValue flag)
*
* Purpose: (Un)draws the traversal around the currently active link.
*****************************************************************************/
static void
DrawTraversalIndicator (
_DtCanvasStruct *canvas,
_DtCvValue render,
_DtCvValue draw_flag,
_DtCvUnit *ret_x,
_DtCvUnit *ret_y,
_DtCvUnit *ret_baseline,
_DtCvUnit *ret_height)
{
int count;
int len;
int start;
int wrkChr;
int totCnt;
int travIdx = canvas->cur_trav;
int curIdx = 0;
int txtLine = canvas->trav_lst[travIdx].idx;
int linkIndex;
int lstLnk = -1;
_DtCvUnit height = 0;
_DtCvUnit dstX;
_DtCvUnit tmpWidth;
_DtCvUnit superWidth = 0;
_DtCvUnit superY = 0;
_DtCvUnit subWidth = 0;
_DtCvUnit subY = 0;
_DtCvUnit scriptX = 0;
_DtCvFlags oldFlag = 0;
_DtCvFlags newFlag = 0;
_DtCvValue lastWasSub = False;
_DtCvValue lastWasSuper = False;
_DtCvValue lstLnkVis = False;
_DtCvSegmentI *pSeg;
_DtCvSegmentI *tmpSeg;
/*
* determine the flags for rendering.
*/
if (draw_flag)
newFlag = _DtCvTRAVERSAL_FLAG;
else
oldFlag = _DtCvTRAVERSAL_FLAG;
/*
* allow traversal to marks.
*/
if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type)
{
int markIdx = canvas->trav_lst[travIdx].idx;
if (True == render)
{
oldFlag = oldFlag | _DtCvMARK_FLAG
| _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
newFlag = newFlag | _DtCvMARK_FLAG
| _DtCvTRAVERSAL_BEGIN | _DtCvTRAVERSAL_END;
if (_DtCvTRUE == canvas->marks[markIdx].on)
{
oldFlag |= _DtCvMARK_ON;
newFlag |= _DtCvMARK_ON;
}
_DtCvDrawAreaWithFlags(canvas,
canvas->marks[markIdx].beg,
canvas->marks[markIdx].end,
oldFlag, newFlag,
_DtCvMARK_TYPE,
canvas->marks[markIdx].client_data);
}
if (ret_height)
*ret_height = canvas->marks[markIdx].end.y -
canvas->marks[markIdx].beg.y +
canvas->txt_lst[canvas->marks[markIdx].end.line_idx].descent +
canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
/*
* set some return variables
*/
if (ret_x)
*ret_x = canvas->marks[markIdx].beg.x;
if (ret_y)
*ret_y = canvas->marks[markIdx].beg.y -
canvas->txt_lst[canvas->marks[markIdx].beg.line_idx].ascent;
if (ret_baseline)
*ret_baseline = canvas->marks[markIdx].beg.y;
return;
}
/*
* get the link index
*/
linkIndex = canvas->trav_lst[travIdx].seg_ptr->link_idx;
/*
* determine the location of the hypertext segment.
*/
pSeg = canvas->trav_lst[travIdx].seg_ptr;
start = canvas->txt_lst[txtLine].byte_index;
count = canvas->txt_lst[txtLine].length;
/*
* get the start of the line
*/
dstX = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
while (pSeg->link_idx != linkIndex)
{
/*
* get the corrected x
*/
dstX = _DtCvAdvanceXOfLine (canvas, pSeg, dstX, &lstLnk, &lstLnkVis);
/*
* move the text x position base on if this is a super or
* sub script - or not.
*/
dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
&superWidth, &superY, &subWidth, &subY,
&lastWasSuper, &lastWasSub);
/*
* get the width of the segment.
*/
_DtCvGetWidthOfSegment(canvas, pSeg, start, count,
&len, &tmpWidth, NULL);
dstX += tmpWidth;
/*
* update pointers
*/
lstLnk = pSeg->link_idx;
count -= len;
curIdx += len;
pSeg = pSeg->next_disp;
start = 0;
}
/*
* set some return variables
*/
if (ret_x)
*ret_x = dstX;
if (ret_y)
*ret_y = canvas->txt_lst[txtLine].baseline -
canvas->txt_lst[txtLine].ascent;
if (ret_baseline)
*ret_baseline = canvas->txt_lst[txtLine].baseline;
/*
* start drawing the traversals
*/
height = 0;
if (True == render)
{
while (txtLine < canvas->txt_cnt && linkIndex == pSeg->link_idx)
{
/*
* get the corrected x
*/
dstX = _DtCvAdvanceXOfLine (canvas,pSeg, dstX, &lstLnk, &lstLnkVis);
/*
* move the text x position base on if this is a super or
* sub script - or not.
*/
dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
&superWidth, &superY, &subWidth, &subY,
&lastWasSuper, &lastWasSub);
/*
* now count up the number of bytes to display for
* the traversal.
*/
totCnt = count;
tmpSeg = pSeg;
count = 0;
wrkChr = start;
while (totCnt > 0 && tmpSeg != NULL
&& tmpSeg->link_idx == linkIndex)
{
_DtCvGetWidthOfSegment(canvas, tmpSeg, wrkChr,
totCnt, &len, NULL, NULL);
totCnt -= len;
count += len;
wrkChr = 0;
tmpSeg = tmpSeg->next_disp;
}
/*
* set the begin flag.
*/
newFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
oldFlag |= (_DtCvTRAVERSAL_BEGIN | _DtCvLINK_BEGIN);
while (count > 0 && pSeg != NULL && pSeg->link_idx == linkIndex)
{
/*
* the original count for the traversal.
*/
len = count;
/*
* if there is mark/selected text, determine, how much
*/
_DtCvCheckLineMarks(canvas, txtLine, curIdx, count, dstX,
(_DtCvSELECTED_FLAG | _DtCvMARK_FLAG),
&len, &oldFlag, &newFlag);
/*
* if this is the last segment(s) of the traversal
* set the end flags.
*/
if (len == count)
{
newFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
oldFlag |= (_DtCvTRAVERSAL_END | _DtCvLINK_END);
}
/*
* render the segments
*/
dstX = _DtCvDrawSegments(canvas, canvas->txt_lst[txtLine],
pSeg, start, len, &lstLnk, dstX, dstX,
&scriptX,&superWidth,&superY,&subWidth,&subY,
&lastWasSub, &lastWasSuper,
&lstLnkVis, oldFlag, newFlag,
_DtCvLINK_TYPE, NULL);
count -= len;
curIdx += len;
if (count > 0)
{
_DtCvSkipLineChars(canvas, pSeg, start, count + len, len,
&start, &pSeg);
newFlag &= ~(_DtCvTRAVERSAL_BEGIN);
oldFlag &= ~(_DtCvTRAVERSAL_BEGIN);
}
}
height += canvas->txt_lst[txtLine].ascent
+ canvas->txt_lst[txtLine].descent;
txtLine++;
if (txtLine < canvas->txt_cnt)
{
start = canvas->txt_lst[txtLine].byte_index;
count = canvas->txt_lst[txtLine].length;
curIdx = 0;
superWidth = 0;
superY = 0;
subWidth = 0;
subY = 0;
scriptX = 0;
lstLnk = -1;
lastWasSuper = False;
lastWasSub = False;
lstLnkVis = False;
/*
* get the correct x
*/
dstX = _DtCvGetStartXOfLine(&(canvas->txt_lst[txtLine]), &pSeg);
}
}
}
if (ret_height)
*ret_height = height;
} /* End DrawTraversalIndicator */
/*****************************************************************************
* Semi-Public Functions
*****************************************************************************/
/*****************************************************************************
* Function: _DtCvGetSearchLineMetrics (
*
* Purpose: gets the text line metrics for the search item.
*****************************************************************************/
int
_DtCvGetSearchLineMetrics(_DtCvHandle handle, int idx, _DtCvUnit* baseline,
_DtCvUnit* descent, _DtCvUnit* ascent)
{
int ret = 0;
_DtCanvasStruct* canvas = (_DtCanvasStruct*)handle;
_DtCvDspLine* line;
if (idx < 0 || idx >= canvas->search_cnt)
return -1;
line = &(canvas->txt_lst[canvas->searchs[idx].idx]);
*baseline = line->baseline;
*descent = line->descent;
*ascent = line->ascent;
return ret;
}
/*****************************************************************************
* Function: _DtCvCheckInfringement (
*
* Purpose: Checks to see if one object infringes vertically on another
* object.
*****************************************************************************/
_DtCvStatus
_DtCvCheckInfringement (
_DtCvUnit tst_top,
_DtCvUnit tst_bot,
_DtCvUnit obj_top,
_DtCvUnit obj_bot)
{
_DtCvStatus result = False;
/*
* check to see if the object is to the left or right of the test
* object and that it 'infringes' on the vertical space of the test
* object.
*
* I.e. ----obj_top------
* | | ----tst_top----
* ----obj_bot------ | |
* ----tst_bot----
*
* I.e. ----tst_top----
* ----obj_top------- | |
* | | ----tst_bot----
* ----obj_bot-------
*
* I.e. ----obj_top------
* | | ----tst_top----
* | | | |
* | | ----tst_bot----
* ----obj_bot------
*
* I.e. ----tst_top----
* ----obj_top------- | |
* | | | |
* ----obj_bot------- | |
* ----tst_bot----
*/
if ((obj_top < tst_top && tst_top < obj_bot)
|| (obj_top < tst_bot && tst_bot < obj_bot)
|| (obj_top <= tst_top && tst_bot <= obj_bot)
|| (tst_top < obj_top && obj_bot < tst_bot))
result = True;
return result;
}
/*****************************************************************************
* Function: _DtCvCheckLineMarks (
*
* Parameters:
* canvas Specifies the canvas to check for
* marks and/or selections.
* line_idx Specifies the line index into the
* list of text lines in the canvas.
* char_idx Specifies the starting character index
* in the text line.
* length Specifies the length of the text line
* to consider.
* dst_x Specifies the x position of the
* starting character in the text line.
* check_flags Specifies which type to look for -
* selection, marks or both.
* ret_len Returns the length of the text line
* starting at the starting character
* index for which the flags returned
* in ret_old and ret_new are valid.
* ret_old, ret_new
* Returns the values in ret_old and ret_new
* and may add _DtCvSELECTED_FLAG and/or
* _DtCvMARK_FLAG.
*
* Purpose: Find out how much of the line is (un)marked in some way.
*****************************************************************************/
void
_DtCvCheckLineMarks (
_DtCanvasStruct *canvas,
int line_idx,
int char_idx,
int length,
_DtCvUnit dst_x,
_DtCvFlags check_flags,
int *ret_len,
_DtCvFlags *ret_old,
_DtCvFlags *ret_new)
{
int i;
_DtCvFlags flag = 0;
/*
* check the selection
*/
if ((check_flags & _DtCvSELECTED_FLAG) && canvas->select_start.y != -1)
{
_DtCvSelectData start = canvas->select_start;
_DtCvSelectData end = canvas->select_end;
/*
* check to see if we need to switch the selection points
*/
if (start.y > end.y || (start.y == end.y && start.x > end.x))
{
end = canvas->select_start;
start = canvas->select_end;
}
/*
* clear the selected flag
*/
*ret_old &= ~(_DtCvSELECTED_FLAG);
*ret_new &= ~(_DtCvSELECTED_FLAG);
if (IsLineSpecial(start, end,
canvas->txt_lst[line_idx], line_idx,
char_idx, length, dst_x,
&length, NULL))
{
/*
* set the selected flag.
*/
*ret_old = *ret_old | _DtCvSELECTED_FLAG;
*ret_new = *ret_new | _DtCvSELECTED_FLAG;
}
}
if ((check_flags & _DtCvMARK_FLAG) && 0 < canvas->mark_cnt)
{
/*
* strip the mark flags from the old and new flags
*/
*ret_old &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
_DtCvMARK_END | _DtCvMARK_ON);
*ret_new &= ~(_DtCvMARK_FLAG | _DtCvMARK_BEGIN |
_DtCvMARK_END | _DtCvMARK_ON);
/*
* now add the correct flags into the old/new flags
*/
for (i = 0; i < canvas->mark_cnt; i++)
{
if (IsLineSpecial(canvas->marks[i].beg, canvas->marks[i].end,
canvas->txt_lst[line_idx], line_idx,
char_idx, length, dst_x,
&length, &flag))
{
/*
* A false return from IsLineSpecial means that 'length'
* is outside this mark.
*
* When true, it means that some part of this mark will
* be rendered on the call. Therefore set the mark flag
* and any other flags returned and check for mark 'on'.
*/
if (_DtCvTRUE == canvas->marks[i].on)
flag |= _DtCvMARK_ON;
*ret_old = *ret_old | _DtCvMARK_FLAG | flag;
*ret_new = *ret_new | _DtCvMARK_FLAG | flag;
}
}
}
/*
* return the next length that is marked/unmarked in someway.
*/
*ret_len = length;
}
/******************************************************************************
* Function: _DtCvSkipLineChars
*
* Parameters:
* canvas Specifies the canvas on which to render
* the text.
*
* Purpose: Given a length, skip ahead that number of 'characters' on
* the line.
*****************************************************************************/
void
_DtCvSkipLineChars(
_DtCanvasStruct *canvas,
_DtCvSegmentI *p_seg,
int start,
int max_cnt,
int use_len,
int *ret_start,
_DtCvSegmentI **ret_seg)
{
int len;
/*
* not all of the traversal line was displayed because
* part of it is selected. So skip what's been rendered,
* and do it again.
*/
while (use_len > 0)
{
/*
* get the byte length of the segment processed.
*/
_DtCvGetWidthOfSegment(canvas, p_seg, start, max_cnt, &len, NULL, NULL);
/*
* increment the start index by the number of total
* bytes processed. If this is more that what is in
* the segment, then the if stmt will catch this and
* set the start index to zero.
*/
if (len > use_len)
{
len = use_len;
start += len;
}
else /* if (len <= use_len) */
{
start = 0;
p_seg = p_seg->next_disp;
}
/*
* reduce the total number of bytes
* processed by the number in this segment.
*/
use_len -= len;
max_cnt -= len;
}
*ret_start = start;
*ret_seg = p_seg;
}
/******************************************************************************
* Function: _DtCvClearInternalUse
*
* Init every internal_use pointer on containers to NULL.
*****************************************************************************/
void
_DtCvClearInternalUse(
_DtCvSegmentI *list,
_DtCvStatus flag)
{
while (NULL != list)
{
/*
* initialize the internal variables
*/
list->internal_use = (void *) -1;
if (_DtCvIsSegContainer(list))
_DtCvClearInternalUse(_DtCvContainerListOfSeg(list), flag);
list = list->next_seg;
}
}
/******************************************************************************
* Function: _DtCvGetCharIdx
*
* Parameters:
* canvas Specifies the canvas on which to render
* the text.
* line Specifies the line in the line table.
* find_x Specifies the x position of the character.
*
* Returns: ?? Returns the idx of the character.
*
* Purpose:
*****************************************************************************/
int
_DtCvGetCharIdx(
_DtCanvasStruct *canvas,
_DtCvDspLine line,
_DtCvUnit find_x)
{
void *pChar;
_DtCvValue done = FALSE;
_DtCvValue lastLinkVisible = FALSE;
int count = line.length;
int start = line.byte_index;
int len = -1;
int lnkInd = -1;
_DtCvUnit segWidth;
_DtCvUnit xPos;
_DtCvSegmentI *pSeg;
xPos = _DtCvGetStartXOfLine(&line, &pSeg);
/*
* check to see if the start is in the middle of the line.
* If so, bump the x position and start indexes to the
* correct locations.
*/
while (!done && find_x > xPos && count > 0)
{
xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
&lnkInd, &lastLinkVisible);
if (xPos < find_x)
{
/*
* advance the pointer by the width
*/
_DtCvGetWidthOfSegment(canvas, pSeg, start, count,
&len, &segWidth, NULL);
if (segWidth + xPos <= find_x)
{
xPos += segWidth;
pSeg = pSeg->next_disp;
count -= len;
start = 0;
}
else /* if (xPos < find_x && find_x < xPos + segWidth) */
{
if (_DtCvIsSegString(pSeg))
{
pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
_DtCvIsSegWideChar(pSeg), start);
len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
if (len > count)
len = count;
count -= FindChar(canvas, pSeg, pChar, len,
find_x - xPos, NULL);
}
done = True;
}
}
len = line.length - count;
}
return len;
}
/*****************************************************************************
* Function: _DtCvGetStartXOfLine
*
* Purpose: Get the starting 'x' of the specified line
* Does *not* take into account traversal or link info.
*****************************************************************************/
_DtCvUnit
_DtCvGetStartXOfLine (
_DtCvDspLine *line,
_DtCvSegmentI **p_seg)
{
*p_seg = line->seg_ptr;
return line->text_x;
}
/*****************************************************************************
* Function: _DtCvAdvanceXOfLine
*
* Purpose: Move the 'x' to after the traversal and link info.
*****************************************************************************/
_DtCvUnit
_DtCvAdvanceXOfLine (
_DtCanvasStruct *canvas,
_DtCvSegmentI *p_seg,
_DtCvUnit x_pos,
int *link_idx,
_DtCvValue *link_flag)
{
_DtCvValue junk;
/*
* take into account the link before and after space
*/
junk = _DtCvIsSegVisibleLink(p_seg);
*link_flag = _DtCvModifyXpos (canvas->link_info, p_seg, junk,
*link_flag, *link_idx, &x_pos);
/*
* take into account the traversal before and after space
*/
junk = _DtCvIsSegALink(p_seg);
(void) _DtCvModifyXpos (canvas->traversal_info, p_seg, junk,
((_DtCvValue) True), *link_idx, &x_pos);
*link_idx = p_seg->link_idx;
return x_pos;
}
/******************************************************************************
* Function: _DtCvGetWidthOfSegment
*
* DetermineWidthOfSegment determines the width of the segment.
* The segment must have been already initialized with the correct
* font (for strings), the spc resolve, the graphic loaded, etc.
*
*****************************************************************************/
void
_DtCvGetWidthOfSegment(
_DtCanvasStruct *canvas,
_DtCvSegmentI *p_seg,
int start,
int max_cnt,
int *ret_cnt,
_DtCvUnit *ret_w,
_DtCvValue *ret_trimmed)
{
void *pChar;
/*
* return the width of the segment.
*/
*ret_cnt = 0;
if (ret_w != NULL)
*ret_w = 0;
if (ret_trimmed != NULL)
*ret_trimmed = False;
if (!(_DtCvIsSegNoop(p_seg)))
{
if (_DtCvIsSegRegion(p_seg))
{
*ret_cnt = 1;
if (ret_w != NULL)
*ret_w = _DtCvWidthOfRegionSeg(p_seg);
}
else
{
pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(p_seg),
_DtCvIsSegWideChar(p_seg), start);
*ret_cnt = _DtCvStrLen (pChar, _DtCvIsSegWideChar(p_seg));
if (*ret_cnt > max_cnt)
{
*ret_cnt = max_cnt;
if (ret_trimmed != NULL)
*ret_trimmed = True;
}
/*
* determine the width of the string.
*/
if (ret_w != NULL)
*ret_w = _DtCvGetStringWidth(canvas, p_seg,pChar,*ret_cnt);
}
}
}
/******************************************************************************
* Function: _DtCvModifyXpos
*****************************************************************************/
_DtCvValue
_DtCvModifyXpos (
_DtCvSpaceMetrics info,
_DtCvSegmentI *seg,
_DtCvValue tst_result,
_DtCvValue cur_flag,
int last_idx,
_DtCvUnit *x)
{
int addx = 0;
/*
* take into account the link before and after space
*/
if (tst_result)
{
/*
* Ignore if the same link
*/
if (last_idx != seg->link_idx)
{
/*
* if one link followed by another add the space after.
*/
if (last_idx != -1)
addx = info.space_after;
/*
* add the space before the link
*/
addx += info.space_before;
}
cur_flag = True;
}
else
{
if (last_idx != -1 && cur_flag == True)
addx = info.space_after;
cur_flag = False;
}
*x += addx;
return cur_flag;
}
/*****************************************************************************
* Function: _DtCvAdjustForSuperSub
*
* Parameters:
* canvas Specifies the canvas.
* start_x Specifies the current text x position.
* script_x Specifies the current super and sub
* scripting x position. Returns the same
* value as start_x if the segment is not a
* super or sub script.
* super_width Specifies the width of the previously
* rendered super script. Set to 0 if the
* next segment is not a super or sub
* script.
* super_y Specifies the y offset for super
* scripts. Set to a new value if the last
* segment was not a super or sub script.
* sub_width Specifies the width of the previously
* rendered sub script. Set to 0 if the
* next segment is not a super or sub
* script.
* sub_y Specifies the y offset for sub scripts.
* Set to a new value if the last segment
* was not a super or sub script.
* last_was_super Specifies if the last item was a super
* script. Set to False if the segment
* is not a super or sub script.
* last_was_sub Specifies if the last item was a sub
* script. Set to False if the segment
* is not a super or sub script.
* Returns: new text x positon.
*
* Purpose: Determines the super and sub scripting positions for text.
* If the last item was not a script, then the base offset for
* scripting (script_x) is moved to start_x. If the current
* item is a string, its scripting y position is determined
* (super_y and sub_y). If the new item is a super or sub
* script, the next text placement (start_x) is moved to after
* the script_x plus the super or sub script size currently
* active(super_width and sub_width). Otherwise, the the flags
* are set to false and the widths are set to 0.
*
*****************************************************************************/
_DtCvUnit
_DtCvAdjustForSuperSub(
_DtCanvasStruct *canvas,
_DtCvSegmentI *pSeg,
_DtCvUnit start_x,
_DtCvUnit *script_x,
_DtCvUnit *super_width,
_DtCvUnit *super_y,
_DtCvUnit *sub_width,
_DtCvUnit *sub_y,
_DtCvValue *last_was_super,
_DtCvValue *last_was_sub)
{
/*
* if the last item was not a super or sub script,
* move the script x to the end of the last output.
*/
if (!(*last_was_super || *last_was_sub))
*script_x = start_x;
/*
* check for super and sub scripts.
* adjust text x positioning accordingly.
*/
if (_DtCvIsSegSuperScript(pSeg))
{
start_x = *script_x + *super_width;
*last_was_super = True;
}
else if (_DtCvIsSegSubScript(pSeg))
{
start_x = *script_x + *sub_width;
*last_was_sub = True;
}
else if (*last_was_super || *last_was_sub)
{
*sub_width = 0;
*super_width = 0;
*last_was_super = False;
*last_was_sub = False;
}
/*
* if this wasn't a super or sub script, find out where
* they get placed on this string.
*/
if (!(*last_was_super || *last_was_sub))
{
if (_DtCvIsSegString(pSeg))
_DtCvFontMetrics (canvas,_DtCvFontOfStringSeg(pSeg),
NULL, NULL, NULL, super_y, sub_y);
else if (_DtCvIsSegRegion(pSeg))
{
*super_y = _DtCvHeightOfRegionSeg(pSeg) * 4 / 10;
*sub_y = *super_y;
}
}
return start_x;
}
/******************************************************************************
* Function: _DtCvDrawSegments
*
* Parameters:
* canvas Specifies the canvas on which to render
* the text.
* line Specifies the line metrics.
* p_seg Specifies the starting segment.
* start_char Specifies the starting index in a string
* segment. 0 for all others.
* count Specifies the number of characters
* (including special characters to
* render).
* prev_lnk Indicates the previous link index. Used
* to calculate extra spacing needed for
* traversal and link markup.
* txt_x Specifies the starting x of the
* segment(s). This does *NOT* take into
* account traversal or link spacing. This
* routine will do that. This is so
* selected links will have correct spacing
* indicated.
* sel_x Specifies where the selection x position
* begins. Usually it equals txt_x, but
* sometimes it will be less than it to
* indicate blank space has been selected.
* super_width Specifies the last super script x offset.
* super_y Specifies the last super script y offset.
* sub_width Specifies the last sub script x offset.
* sub_y Specifies the last sub script y offset.
* last_was_sub Specifies if the last element was a
* subscript.
* last_was_super Specifies if the last element was a
* superscript.
* last_was_vis Specifies if the last element was a
* visible hypertext link.
* old_flag Specifies what the line use to look like.
* new_flag Specifies what the line is to look like.
*
* Returns: txt_x Returns the maximum x unit processed.
*
* Purpose: _DtCvDrawSegments draws one or more segments based on
* the count passed in.
*
* This routine adds CELink to new_flag when rendering segments
* that are hypertext links. At the same time it will
* determine the correct window hint and may place in old_flag
* and new_flag either _DtCvLINK_POP_UP or _DtCvLINK_NEW_WINDOW.
*
* This routine strips the _DtCvTRAVERSAL_END from old_flag and
* new_flag (based on what's in new_flag). It will restore
* these flags (if specified) when it renders the last element
* in the count sequence.
*
*****************************************************************************/
_DtCvUnit
_DtCvDrawSegments(
_DtCanvasStruct *canvas,
_DtCvDspLine line,
struct _dtCvSegment *p_seg,
int start_char,
int count,
int *prev_lnk,
_DtCvUnit txt_x,
_DtCvUnit sel_x,
_DtCvUnit *script_x,
_DtCvUnit *super_width,
_DtCvUnit *super_y,
_DtCvUnit *sub_width,
_DtCvUnit *sub_y,
_DtCvValue *last_was_sub,
_DtCvValue *last_was_super,
_DtCvValue *last_link_vis,
_DtCvFlags old_flag,
_DtCvFlags new_flag,
_DtCvElemType trav_type,
_DtCvPointer trav_data )
{
int linkType = 0;
int len;
short cropped = _DtCvFALSE;
short image_offset = _DtCvFALSE;
_DtCvUnit segWidth;
_DtCvUnit yPos;
void *pChar;
_DtCvFlags saveEnd = new_flag &
(_DtCvTRAVERSAL_END | _DtCvLINK_END | _DtCvMARK_END);
_DtCvElemType elemType;
_DtCvRenderInfo posInfo;
_DtCvStringInfo strInfo;
/*
* skip any leading no-op lines
*/
while (p_seg != NULL && _DtCvIsSegNoop(p_seg))
{
start_char = 0;
p_seg = p_seg->next_disp;
}
/*
* strip the any end info from the flags.
* it will be put back on with the last element that makes up the count.
*/
old_flag &= ~saveEnd;
new_flag &= ~saveEnd;
/*
* now process the segments included in 'count'
*/
while (p_seg != NULL && count > 0)
{
/*
* reset the baseline.
* when processing super or sub scripts, this gets changed.
*/
yPos = line.baseline;
/*
* take into account the visible link and traversal info.
*/
txt_x = _DtCvAdvanceXOfLine(canvas, p_seg, txt_x,
prev_lnk, last_link_vis);
/*
* check for super and sub scripts.
* adjust text x positioning accordingly.
*/
txt_x = _DtCvAdjustForSuperSub(canvas, p_seg, txt_x,
script_x, super_width, super_y,
sub_width, sub_y,
last_was_super, last_was_sub);
if (sel_x > txt_x)
sel_x = txt_x;
/*
* set visible link indicator flags
*/
_DtCvClearLinkFlags(old_flag);
_DtCvClearLinkFlags(new_flag);
/*
* is this a visible link?
*/
if (_DtCvIsSegVisibleLink(p_seg))
{
/*
* visible link - set the flags.
*/
new_flag |= _DtCvLINK_FLAG;
old_flag |= _DtCvLINK_FLAG;
/*
* is this the start of a new link? If so, set the begin flag.
*/
if (*prev_lnk != p_seg->link_idx)
{
new_flag |= _DtCvLINK_BEGIN;
old_flag |= _DtCvLINK_BEGIN;
}
/*
* get the link type and set the window hint.
*/
linkType = _DtLinkDbGetLinkType(canvas->link_data,p_seg->link_idx);
switch (_DtLinkDbGetHint(canvas->link_data, p_seg->link_idx))
{
case _DtCvWindowHint_PopupWindow:
new_flag |= _DtCvLINK_POP_UP;
old_flag |= _DtCvLINK_POP_UP;
break;
case _DtCvWindowHint_NewWindow:
new_flag |= _DtCvLINK_NEW_WINDOW;
old_flag |= _DtCvLINK_NEW_WINDOW;
break;
}
}
/*
* rememeber this link index.
*/
*prev_lnk = p_seg->link_idx;
/*
* set the search flag
*/
_DtCvClearSearchFlags(old_flag);
_DtCvClearSearchFlags(new_flag);
old_flag |= (p_seg->type & _DtCvSEARCH_FLAG);
new_flag |= (p_seg->type & _DtCvSEARCH_FLAG);
if (0 == start_char)
{
_DtCvSetSearchBegin(old_flag, p_seg);
_DtCvSetSearchBegin(new_flag, p_seg);
}
old_flag &= ~_DtCvAPP_FLAG2;
new_flag &= ~_DtCvAPP_FLAG2;
old_flag |= p_seg->type & _DtCvAPP_FLAG2;
new_flag |= p_seg->type & _DtCvAPP_FLAG2;
old_flag &= ~(_DtCvAPP_FLAG3 | _DtCvAPP_FLAG4);
new_flag &= ~(_DtCvAPP_FLAG3 | _DtCvAPP_FLAG4);
/*
* init some variables
*/
segWidth = 0;
len = 0;
/*
* adjust the yPos for sub/superscripts.
*/
if (_DtCvIsSegSuperScript(p_seg))
yPos -= *super_y;
else if (_DtCvIsSegSubScript(p_seg))
yPos += *sub_y;
elemType = -1;
switch (_DtCvPrimaryTypeOfSeg(p_seg))
{
case _DtCvSTRING:
/*
* set the type
*/
elemType = _DtCvSTRING_TYPE;
/*
* get the string and its length.
*/
pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(p_seg),
_DtCvIsSegWideChar(p_seg), start_char);
len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(p_seg));
/*
* if length of the string is longer than we want to
* output, crop.
*/
if (len > count)
{
len = count;
cropped = _DtCvTRUE;
}
/*
* initialize the string structure.
*/
strInfo.string = pChar;
strInfo.byte_len = len;
strInfo.wc = _DtCvIsSegWideChar(p_seg);
strInfo.font_ptr = _DtCvFontOfStringSeg(p_seg);
strInfo.csd = p_seg->client_use;
/*
* now get the width of the string to update the x positions
*/
segWidth = _DtCvGetStringWidth(canvas, p_seg, pChar, len);
/*
* attach the string information to the position info.
*/
posInfo.info = &strInfo;
/*
* reset starting index.
*/
start_char = 0;
break;
case _DtCvREGION:
/*
* set the type, length and width
*/
elemType = _DtCvREGION_TYPE;
len = 1;
segWidth = _DtCvWidthOfRegionSeg(p_seg);
/*
* attach the region information to the position info.
*/
posInfo.info = _DtCvInfoOfRegionSeg(p_seg);
break;
}
/*
* do we have valid information?
*/
if (-1 != elemType)
{
/*
* now set up the position information
*/
posInfo.box_x = sel_x;
posInfo.box_y = line.baseline - line.ascent;
posInfo.box_height = line.ascent + line.descent + 1;
posInfo.box_width = segWidth;
/*
* if this is the last segment to be rendered,
* restore the end flags.
*/
if (len == count)
{
new_flag |= saveEnd;
old_flag |= saveEnd;
}
/*
* if the item (string) was not cropped, set the Search end
* flag accordingly.
*/
if (_DtCvFALSE == cropped)
{
_DtCvSetSearchEnd(old_flag, p_seg);
_DtCvSetSearchEnd(new_flag, p_seg);
if (new_flag & _DtCvSEARCH_END && new_flag & _DtCvAPP_FLAG2 &&
!(new_flag & _DtCvSELECTED_FLAG)) {
new_flag |= _DtCvAPP_FLAG4;
}
}
if (image_offset == _DtCvTRUE) {
old_flag |= _DtCvAPP_FLAG3;
new_flag |= _DtCvAPP_FLAG3;
image_offset = _DtCvFALSE;
}
/*
* render the element
*/
if (NULL != canvas->virt_functions.render_elem)
(*(canvas->virt_functions.render_elem))(
canvas->client_data, elemType,
txt_x, yPos,
linkType, old_flag, new_flag,
trav_type, trav_data, &posInfo);
if (cropped == _DtCvFALSE && new_flag & _DtCvSEARCH_END
&& new_flag & _DtCvAPP_FLAG2
&& !(new_flag & _DtCvSELECTED_FLAG))
image_offset = _DtCvTRUE;
}
/*
* strip the any begin flags.
*/
_DtCvRemoveBeginFlags(old_flag);
_DtCvRemoveBeginFlags(new_flag);
/*
* take into account subscripting and superscripting.
*/
if (_DtCvIsSegSuperScript(p_seg))
*super_width += segWidth;
else if (_DtCvIsSegSubScript(p_seg))
*sub_width += segWidth;
/*
* adjust the pointers
*/
txt_x += segWidth;
sel_x = txt_x;
count -= len;
p_seg = p_seg->next_disp;
}
return txt_x;
} /* End _DtCvDrawSegments */
/*****************************************************************************
* Public Functions
*****************************************************************************/
/*****************************************************************************
* Function: _DtCvHandle _DtCanvasCreate (_DtCvVirtualInfo virt_info);
*
* Parameters:
* virt_info Specifies the virtual functions to attach
* to the created canvas.
*
* Returns: A handle to the canvas or NULL if an error occurs.
*
* Purpose: Create a canvas and attach the appropriate virtual functions
* to the canvas.
*****************************************************************************/
_DtCvHandle
_DtCanvasCreate (
_DtCvVirtualInfo virt_info,
_DtCvPointer client_data)
{
_DtCanvasStruct *newCanvas;
newCanvas = (_DtCanvasStruct *) malloc (sizeof (_DtCanvasStruct));
if (newCanvas == NULL)
return NULL;
*newCanvas = DefaultCanvas;
newCanvas->virt_functions = virt_info;
newCanvas->client_data = client_data;
newCanvas->mb_length = MB_CUR_MAX;
/*
* load the metrics
*/
_DtCanvasLoadMetrics((_DtCvHandle)newCanvas);
return ((_DtCvHandle)(newCanvas));
} /* End _DtCanvasCreate */
void _DtCanvasLoadMetrics(_DtCvHandle handle)
{
_DtCanvasStruct *canvas = (_DtCanvasStruct*)handle;
(*(canvas->virt_functions.get_metrics))(canvas->client_data,
_DtCvCANVAS_TYPE, &(canvas->metrics));
(*(canvas->virt_functions.get_metrics))(canvas->client_data,
_DtCvLINK_TYPE, &(canvas->link_info));
(*(canvas->virt_functions.get_metrics))(canvas->client_data,
_DtCvTRAVERSAL_TYPE, &(canvas->traversal_info));
if (MB_CUR_MAX > 1)
(*(canvas->virt_functions.get_metrics))(canvas->client_data,
_DtCvLOCALE_TYPE, &(canvas->locale));
}
/*****************************************************************************
* Function: void _DtCanvasClean (_DtCvHandle canvas_handle);
*
* Parameters:
* canvas Specifies the handle for the canvas.
*
* Returns: A handle to the canvas or NULL if an error occurs.
*
* Purpose: Create a canvas and attach the appropriate virtual functions
* to the canvas.
*****************************************************************************/
void
_DtCanvasClean (_DtCvHandle canvas_handle)
{
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
/*
* clean the selection
*/
_DtCanvasProcessSelection (canvas_handle, 0, 0, _DtCvSELECTION_CLEAR);
/*
* zero the lists
*/
canvas->txt_cnt = 0;
canvas->line_cnt = 0;
canvas->mark_cnt = 0;
canvas->trav_cnt = 0;
canvas->search_cnt = 0;
canvas->brk_cnt = 0;
/*
* reset some indicators
*/
canvas->error = 0;
canvas->cur_trav = -1;
/*
* free the internal use structures.
*/
_DtCvClearInternalUse(canvas->element_lst, _DtCvTRUE);
canvas->element_lst = NULL;
canvas->link_data = NULL;
} /* End _DtCanvasClean */
/*****************************************************************************
* Function: void _DtCanvasDestroy (_DtCvHandle canvas_handle);
*
* Parameters:
* canvas Specifies the handle for the canvas.
*
* Returns: A handle to the canvas or NULL if an error occurs.
*
* Purpose: Create a canvas and attach the appropriate virtual functions
* to the canvas.
*****************************************************************************/
void
_DtCanvasDestroy (_DtCvHandle canvas_handle)
{
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
_DtCanvasClean (canvas_handle);
if (NULL != canvas->txt_lst)
free ((void *) canvas->txt_lst);
if (NULL != canvas->line_lst)
free ((void *) canvas->line_lst);
if (NULL != canvas->trav_lst)
free ((void *) canvas->trav_lst);
if (NULL != canvas->marks)
free ((void*) canvas->marks);
if (NULL != canvas->searchs)
free ((void*) canvas->searchs);
if (NULL != canvas->pg_breaks)
free ((void*) canvas->pg_breaks);
free ((void *) canvas);
return;
} /* End _DtCanvasDestroy */
/*****************************************************************************
* Function: void _DtCanvasRender (_DtCvHandle canvas_handle);
*
* Parameters:
* canvas Specifies the handle for the canvas.
*
* Returns: A handle to the canvas or NULL if an error occurs.
*
* Purpose:
*
*****************************************************************************/
void
_DtCanvasRender (
_DtCvHandle canvas_handle,
_DtCvUnit x1,
_DtCvUnit y1,
_DtCvUnit x2,
_DtCvUnit y2,
_DtCvRenderType flag,
_DtCvValue pg_break,
_DtCvUnit *max_y,
_DtCvUnit *next_y)
{
int i = 0;
_DtCvUnit lastY = 0;
_DtCvUnit nextY = -1;
_DtCvUnit minY;
_DtCvUnit maxY;
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
_DtCvDspLine *lines;
_DtCvFlags sideCk;
/*
* check the list of page breaks, it may constrain y2
*/
if (_DtCvTRUE == pg_break && 0 != canvas->brk_cnt)
{
i = 0;
while (y1 > canvas->pg_breaks[i]) i++;
if (i < canvas->brk_cnt && y2 > canvas->pg_breaks[i])
y2 = canvas->pg_breaks[i];
}
/*
* Draw the lines first, they may constrain y2
*/
DrawCanvasLines (canvas, x1, y1, x2, y2, flag, &lastY, &nextY);
if (-1 != nextY && y2 > nextY)
y2 = nextY - 1;
/*
* clear the processed flag from all the text lines.
*/
for (i = 0; i < canvas->txt_cnt; i++)
_DtCvClearProcessed(canvas->txt_lst[i]);
for (lines = canvas->txt_lst, i = 0;
NULL != lines && i < canvas->txt_cnt; lines++, i++)
{
/*
* get the minimum and maximum y of the next line
*/
minY = lines->baseline - lines->ascent;
maxY = lines->baseline + lines->descent;
/*
* is this line on the 'page'?
* Does it hang off the 'page' (and if so is it allowed)?
*/
sideCk = _DtCvSTATUS_NONE;
if (_DtCvIsNotProcessed(*lines) && maxY >= y1 && minY <= y2 &&
(_DtCvRENDER_PARTIAL == flag ||
(maxY <= y2 &&
_DtCvTRUE != (sideCk = CheckAround(canvas->txt_lst, canvas->txt_cnt, i, y2)))))
{
(void) DrawText (canvas, lines, i, 0, 0);
/*
* indicate that this line has been rendered.
*/
_DtCvSetProcessed(*lines);
/*
* if doing complete printing, get any other lines that exist
* next to this one, but don't fit the [y1,y2] pair. This will
* catch scrolling problems using _DtCvRENDER_COMPLETE.
*
* The previous CheckAround() call will have set sideCk to
* _DtCvFALSE if there are other items to the side, but these
* items did not violate the maximum y.
*
* sideCk will be _DtCvSTATUS_NONE if there is nothing to the
* side for _DtCvRENDER_COMPLETE or if flag is _DtCvRENDER_PARTIAL.
*/
if (_DtCvFALSE == sideCk)
RenderSubSet(canvas, canvas->txt_lst, canvas->txt_cnt,
minY, maxY, &lastY);
/*
* is this the maximum that we've rendered?
*/
if (lastY < maxY)
lastY = maxY;
}
/*
* otherwise, would this 'start' the next 'page'?
*
* a) the render type is _DtCvRENDER_PARTIAL but the top of the
* text(minY) is beyound y2 (and so would maxY).
* b) the render type is _DtCvRENDER_COMPLETE and the line is
* split across a page boundary (maxY greater than y2).
* c) the render type is _DtCvRENDER_COMPLETE and there is text
* to the side of this text and it is split across a page
* boundary (sideCk == _DtCvTRUE).
*/
else if ((-1 == nextY || nextY > minY) &&
(maxY > y2 || _DtCvTRUE == sideCk))
nextY = minY;
}
/*
* if doing _DtCvRENDER_PARTIAL, lastY will end up larger than
* actually rendered. So set it back.
*/
if (lastY > y2)
lastY = y2;
/*
* return the values if the user asked for them.
*/
if (NULL != max_y)
*max_y = lastY;
if (NULL != next_y)
*next_y = nextY;
} /* End _DtCanvasRender */
/*****************************************************************************
* Function: void _DtCanvasMoveTraversal ()
*
* Parameters:
* canvas Specifies the handle for the canvas.
*
* Returns: A handle to the canvas or NULL if an error occurs.
*
* Purpose:
*
*****************************************************************************/
_DtCvStatus
_DtCanvasMoveTraversal (
_DtCvHandle canvas_handle,
_DtCvTraversalCmd cmd,
_DtCvValue wrap,
_DtCvValue render,
_DtCvPointer rid,
_DtCvUnit *ret_x,
_DtCvUnit *ret_y,
_DtCvUnit *ret_baseline,
_DtCvUnit *ret_height)
{
int newIndex;
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
if (0 == canvas->trav_cnt)
return _DtCvSTATUS_NONE;
newIndex = canvas->cur_trav;
if (-1 == newIndex)
newIndex = 0;
switch (cmd)
{
case _DtCvTRAVERSAL_TOP:
newIndex = 0;
break;
case _DtCvTRAVERSAL_NEXT:
newIndex++;
if (newIndex >= canvas->trav_cnt)
{
newIndex--;
if (wrap == True)
newIndex = 0;
}
break;
case _DtCvTRAVERSAL_PREV:
newIndex--;
if (newIndex < 0)
{
newIndex = 0;
if (wrap == True)
newIndex = canvas->trav_cnt - 1;
}
break;
case _DtCvTRAVERSAL_BOTTOM:
newIndex = canvas->trav_cnt - 1;
break;
case _DtCvTRAVERSAL_ID:
case _DtCvTRAVERSAL_MARK:
if (NULL != rid)
{
int idx;
char *lnkId;
_DtCvValue found = False;
newIndex = 0;
while (False == found && newIndex < canvas->trav_cnt)
{
if (_DtCvTRAVERSAL_ID == cmd &&
_DtCvTraversalLink ==
canvas->trav_lst[newIndex].type)
{
idx = canvas->trav_lst[newIndex].seg_ptr->link_idx;
lnkId = _DtLinkDbGetLinkSpec(canvas->link_data,
idx);
if (_DtCvStrCaseCmpLatin1(lnkId, rid) == 0)
found = True;
}
else if (_DtCvTRAVERSAL_MARK == cmd &&
_DtCvTraversalMark == canvas->trav_lst[newIndex].type)
{
idx = canvas->trav_lst[newIndex].idx;
if (rid == canvas->marks[idx].client_data)
found = True;
}
if (False == found)
newIndex++;
}
if (False == found)
return _DtCvSTATUS_BAD;
}
break;
}
/*
* turn off the old traversal
*/
if (cmd == _DtCvTRAVERSAL_OFF)
{
if (-1 != canvas->cur_trav)
DrawTraversalIndicator (canvas, render, False,
NULL, NULL, NULL, NULL);
canvas->trav_on = _DtCvFALSE;
}
/*
* turn off the old traversal and turn on the new one.
*/
else if (newIndex != canvas->cur_trav)
{
if (-1 != canvas->cur_trav)
DrawTraversalIndicator (canvas, render, False,
NULL, NULL, NULL, NULL);
canvas->cur_trav = newIndex;
DrawTraversalIndicator (canvas, render, True,
ret_x, ret_y, ret_baseline, ret_height);
canvas->trav_on = _DtCvTRUE;
return _DtCvSTATUS_OK;
}
/*
* Other wise turn on the traversal
*/
else if (cmd == _DtCvTRAVERSAL_ON && -1 != canvas->cur_trav)
{
DrawTraversalIndicator (canvas, render, True,
ret_x, ret_y, ret_baseline, ret_height);
canvas->trav_on = _DtCvTRUE;
return _DtCvSTATUS_OK;
}
return _DtCvSTATUS_NONE;
}
/*****************************************************************************
* Function: void _DtCanvasGetPosLink (_DtCvHandle canvas_handle,
* _DtCvUnit x, _DtCvUnit y);
*
* Parameters:
* canvas Specifies the handle for the canvas.
*
* Returns: A handle to the canvas or NULL if an error occurs.
*
* Purpose:
*
*****************************************************************************/
_DtCvStatus
_DtCanvasGetPosLink (
_DtCvHandle canvas_handle,
_DtCvUnit x1,
_DtCvUnit y1,
_DtCvUnit x2,
_DtCvUnit y2,
_DtCvLinkInfo *ret_info)
{
int travIdx;
int line;
int len;
int count;
int startChar;
_DtCvUnit topY;
_DtCvUnit botY;
_DtCvUnit startX;
_DtCvUnit endX;
void *pChar;
_DtCvValue junk;
_DtCvStatus found = _DtCvSTATUS_NONE;
_DtCvSegmentI *pSeg = NULL;
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
_DtCvTraversalInfo *lnkSegs = canvas->trav_lst;
if (0 == canvas->trav_cnt)
return _DtCvSTATUS_NONE;
botY = 0;
topY = 0;
line = 0;
while (line < canvas->txt_cnt && _DtCvSTATUS_NONE == found)
{
topY = canvas->txt_lst[line].baseline - canvas->txt_lst[line].ascent;
botY = canvas->txt_lst[line].baseline + canvas->txt_lst[line].descent;
startX = canvas->txt_lst[line].text_x;
/*
* make sure the requested link is on this line.
*/
if (topY <= y1 && y1 <= botY && startX <= x1 &&
x1 <= canvas->txt_lst[line].max_x)
{
int lnkIndx = -1;
_DtCvValue lstVisible = False;
count = canvas->txt_lst[line].length;
pSeg = canvas->txt_lst[line].seg_ptr;
startChar = canvas->txt_lst[line].byte_index;
while (count > 0 && _DtCvSTATUS_NONE == found)
{
/*
* adjust the starting position by the link space
*/
junk = _DtCvIsSegVisibleLink(pSeg);
lstVisible = _DtCvModifyXpos (canvas->link_info, pSeg,
junk, lstVisible, lnkIndx, &startX);
/*
* adjust the starting position by the traversal space
*/
junk = _DtCvIsSegALink(pSeg);
(void) _DtCvModifyXpos (canvas->traversal_info, pSeg,
junk, ((_DtCvValue) True), lnkIndx, &startX);
lnkIndx = pSeg->link_idx;
/*
* skip no-op
*/
if (_DtCvIsSegNoop(pSeg))
len = 0;
/*
* check region
*/
else if (_DtCvIsSegRegion(pSeg))
{
len = 1;
endX = startX + _DtCvWidthOfRegionSeg(pSeg);
}
else
{
/*
* initialize the pointer to the string
*/
pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
_DtCvIsSegWideChar(pSeg), startChar);
/*
* get the length of the current string.
* If it is longer than the line count indicates,
* it must be wrapped to the next line. We are
* only interested in in the part of the line
* that is on the line selected.
*/
len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
if (len > count)
len = count;
/*
* calculate the ending pixel postion for
* this string segment.
*/
endX = startX + _DtCvGetStringWidth(canvas, pSeg,
pChar, len);
}
/*
* test to see if the selected segment was this segment.
*/
if (x1 >= startX && x1 < endX && x2 >= startX && x2 < endX)
{
found = _DtCvSTATUS_OK;
/*
* Find the hypertext entry.
*/
travIdx = 0;
while (travIdx < canvas->trav_cnt
&& _DtCvTraversalLink == lnkSegs->type
&& lnkSegs->seg_ptr->link_idx != pSeg->link_idx)
{
lnkSegs++;
travIdx++;
}
}
else
{
/*
* go to the next segment.
*/
pSeg = pSeg->next_disp;
/*
* adjust for the new begining.
*/
startX = endX;
count = count - len;
startChar = 0;
}
}
}
line++;
}
/*
* check to see if we found a segment and
* see if it is a hypertext segment
*/
if (_DtCvSTATUS_OK == found)
{
found = _DtCvSTATUS_NONE;
if (_DtCvIsSegALink(pSeg) &&
_DtLinkDbGetLinkInfo(canvas->link_data, pSeg->link_idx,
canvas->virt_functions.exec_cmd_filter,
canvas->client_data, ret_info) == 0)
{
ret_info->offset_x = x1 - startX;
ret_info->offset_y = y1 - topY;
found = _DtCvSTATUS_OK;
}
}
return found;
} /* End _DtCanvasGetPosLink */
/*****************************************************************************
* Function: void _DtCanvasGetCurLink ()
*
* Parameters:
* canvas Specifies the handle for the canvas.
*
* Returns: A handle to the canvas or NULL if an error occurs.
*
* Purpose:
*
*****************************************************************************/
_DtCvStatus
_DtCanvasGetCurLink (
_DtCvHandle canvas_handle,
_DtCvLinkInfo *ret_info)
{
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
_DtCvSegmentI *pSeg;
int curTrav = canvas->cur_trav;
/*
* if there isn't any traversal entry or it is a mark, return nothing.
*/
if (0 == canvas->trav_cnt || -1 == curTrav ||
_DtCvTraversalMark == canvas->trav_lst[curTrav].type)
return _DtCvSTATUS_NONE;
/*
* otherwise this is a hypertext link
*/
if (NULL != ret_info &&
_DtCvTraversalLink == canvas->trav_lst[curTrav].type)
{
pSeg = canvas->trav_lst[curTrav].seg_ptr;
if (_DtLinkDbGetLinkInfo(canvas->link_data, pSeg->link_idx,
canvas->virt_functions.exec_cmd_filter,
canvas->client_data, ret_info) == 0)
return _DtCvSTATUS_OK;
}
return _DtCvSTATUS_BAD;
}
/*****************************************************************************
* Function: void _DtCanvasGetCurTraversal ()
*
* Parameters:
* canvas Specifies the handle for the canvas.
*
* Returns: A handle to the canvas or NULL if an error occurs.
*
* Purpose:
*
*****************************************************************************/
_DtCvStatus
_DtCanvasGetCurTraversal (
_DtCvHandle canvas_handle,
_DtCvLinkInfo *ret_info,
_DtCvPointer *ret_data)
{
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
_DtCvSegmentI *pSeg;
int curTrav = canvas->cur_trav;
/*
* if there isn't any traversal entry, return nothing.
*/
if (0 == canvas->trav_cnt || -1 == curTrav)
return _DtCvSTATUS_NONE;
/*
* if this is a mark, return the client data.
*/
if (NULL != ret_data &&
_DtCvTraversalMark == canvas->trav_lst[curTrav].type)
{
*ret_data = canvas->marks[canvas->trav_lst[curTrav].idx].client_data;
return _DtCvSTATUS_MARK;
}
/*
* otherwise this is a hypertext link
*/
if (NULL != ret_info &&
_DtCvTraversalLink == canvas->trav_lst[curTrav].type)
{
pSeg = canvas->trav_lst[curTrav].seg_ptr;
if (_DtLinkDbGetLinkInfo(canvas->link_data, pSeg->link_idx,
canvas->virt_functions.exec_cmd_filter,
canvas->client_data, ret_info) == 0)
return _DtCvSTATUS_LINK;
}
return _DtCvSTATUS_BAD;
}
/*****************************************************************************
* Function: void _DtCanvasGetSpotInfo (_DtCvHandle canvas_handle,
* _DtCvUnit x, _DtCvUnit y);
*
* Parameters:
* canvas Specifies the handle for the canvas.
*
* Returns: _DtCvSTATUS_OK if a segment was found at x, y.
* _DtCvSTATUS_NONE if no segment found at that location.
*
* Purpose:
*
*****************************************************************************/
_DtCvStatus
_DtCanvasGetSpotInfo (
_DtCvHandle canvas_handle,
_DtCvUnit x,
_DtCvUnit y,
_DtCvSegment **ret_seg,
_DtCvUnit *ret_offx,
_DtCvUnit *ret_offy,
_DtCvElemType *ret_elem)
{
int line;
int len;
int count;
int startChar;
_DtCvUnit topY;
_DtCvUnit botY;
_DtCvUnit startX;
_DtCvUnit endX;
void *pChar;
_DtCvValue junk;
_DtCvStatus found = _DtCvSTATUS_NONE;
_DtCvSegmentI *pSeg = NULL;
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
if (NULL != ret_seg)
*ret_seg = NULL;
botY = 0;
topY = 0;
line = 0;
while (line < canvas->txt_cnt && _DtCvSTATUS_NONE == found)
{
topY = canvas->txt_lst[line].baseline - canvas->txt_lst[line].ascent;
botY = canvas->txt_lst[line].baseline + canvas->txt_lst[line].descent;
startX = canvas->txt_lst[line].text_x;
/*
* make sure the requested link is on this line.
*/
if (topY <= y && y <= botY && startX <= x &&
x <= canvas->txt_lst[line].max_x)
{
int lnkIndx = -1;
_DtCvValue lstVisible = False;
count = canvas->txt_lst[line].length;
pSeg = canvas->txt_lst[line].seg_ptr;
startChar = canvas->txt_lst[line].byte_index;
while (count > 0 && _DtCvSTATUS_NONE == found)
{
/*
* adjust the starting position by the link space
*/
junk = _DtCvIsSegVisibleLink(pSeg);
lstVisible = _DtCvModifyXpos (canvas->link_info, pSeg,
junk, lstVisible, lnkIndx, &startX);
/*
* adjust the starting position by the traversal space
*/
junk = _DtCvIsSegALink(pSeg);
(void) _DtCvModifyXpos (canvas->traversal_info, pSeg,
junk, ((_DtCvValue) True), lnkIndx, &startX);
lnkIndx = pSeg->link_idx;
/*
* skip no-op
*/
if (_DtCvIsSegNoop(pSeg))
len = 0;
/*
* check region
*/
else if (_DtCvIsSegRegion(pSeg))
{
len = 1;
endX = startX + _DtCvWidthOfRegionSeg(pSeg);
}
else
{
/*
* initialize the pointer to the string
*/
pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
_DtCvIsSegWideChar(pSeg), startChar);
/*
* get the length of the current string.
* If it is longer than the line count indicates,
* it must be wrapped to the next line. We are
* only interested in in the part of the line
* that is on the line selected.
*/
len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
if (len > count)
len = count;
/*
* calculate the ending pixel postion for
* this string segment.
*/
endX = startX + _DtCvGetStringWidth(canvas, pSeg,
pChar, len);
}
/*
* test to see if the selected segment was this segment.
*/
if (x >= startX && x < endX)
found = _DtCvSTATUS_OK;
else
{
/*
* go to the next segment.
*/
pSeg = pSeg->next_disp;
/*
* adjust for the new begining.
*/
startX = endX;
count = count - len;
startChar = 0;
}
}
}
line++;
}
/*
* check to see if we found a segment.
*/
if (_DtCvSTATUS_OK == found)
{
*ret_elem = _DtCvREGION_TYPE;
if (_DtCvIsSegString(pSeg))
*ret_elem = _DtCvSTRING_TYPE;
if (NULL != ret_seg)
*ret_seg = pSeg;
if (NULL != ret_offx)
*ret_offx = x - startX;
if (NULL != ret_offy)
*ret_offy = y - topY;
}
return found;
} /* End _DtCanvasGetPosition */