2875 lines
74 KiB
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 */
|