mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
1104 lines
22 KiB
C
1104 lines
22 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "xp.h"
|
|
#include "layout.h"
|
|
#include "intl_csi.h"
|
|
|
|
#ifdef PROFILE
|
|
#pragma profile on
|
|
#endif
|
|
|
|
#ifdef XP_MAC
|
|
# ifdef XP_TRACE
|
|
# undef XP_TRACE
|
|
# endif
|
|
# define XP_TRACE(X)
|
|
#else
|
|
#ifndef XP_TRACE
|
|
# define XP_TRACE(X) fprintf X
|
|
#endif
|
|
#endif /* XP_MAC */
|
|
|
|
#ifdef TEST_16BIT
|
|
#define XP_WIN16
|
|
#endif /* TEST_16BIT */
|
|
|
|
#define INTL_FIND 1 /* ftang */
|
|
#include "libi18n.h"
|
|
|
|
/*************************
|
|
* The following is to speed up case conversion
|
|
* to allow faster checking of caseless equal among strings.
|
|
*************************/
|
|
#ifdef NON_ASCII_STRINGS
|
|
# define TOLOWER(x) (tolower((int)(x)))
|
|
#else /* ASCII TABLE LOOKUP */
|
|
static unsigned char lower_lookup[256]={
|
|
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
|
|
27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,
|
|
51,52,53,54,55,56,57,58,59,60,61,62,63,64,
|
|
97,98,99,100,101,102,103,104,105,106,107,108,109,
|
|
110,111,112,113,114,115,116,117,118,119,120,121,122,
|
|
91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,
|
|
111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
|
|
129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,
|
|
147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,
|
|
165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,
|
|
183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,
|
|
201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,
|
|
219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,
|
|
237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,
|
|
255};
|
|
# define TOLOWER(x) (lower_lookup[(unsigned int)(x)])
|
|
#endif /* NON_ASCII_STRINGS */
|
|
|
|
|
|
static void
|
|
lo_next_character(MWContext *context, lo_DocState *state, LO_Element **ele_loc,
|
|
int32 *pos, Bool forward)
|
|
{
|
|
INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
|
|
int16 win_csid = INTL_GetCSIWinCSID(c);
|
|
LO_Element *eptr;
|
|
int32 position;
|
|
|
|
eptr = *ele_loc;
|
|
position = *pos;
|
|
|
|
/*
|
|
* If our current element is text, we may be able to just
|
|
* move inside of it.
|
|
*/
|
|
if (eptr->type == LO_TEXT)
|
|
{
|
|
if ((forward != FALSE)&&
|
|
(position < (eptr->lo_text.text_len - 1)))
|
|
{
|
|
#ifdef INTL_FIND
|
|
/* Add by ftang to provide international find */
|
|
position = INTL_NextCharIdxInText(win_csid, (unsigned char*)eptr->lo_text.text, position );
|
|
#else
|
|
position++;
|
|
#endif
|
|
*ele_loc = eptr;
|
|
*pos = position;
|
|
return;
|
|
}
|
|
else if ((forward == FALSE)&&(position > 0))
|
|
{
|
|
#ifdef INTL_FIND
|
|
/* Add by ftang to provide international find */
|
|
position = INTL_PrevCharIdxInText(win_csid, (unsigned char*)eptr->lo_text.text, position );
|
|
#else
|
|
position--;
|
|
#endif
|
|
*ele_loc = eptr;
|
|
*pos = position;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we didn't return above, we need to move to a new element.
|
|
*/
|
|
if (forward != FALSE)
|
|
{
|
|
/*
|
|
* If no next element, see if this is a CELL we can
|
|
* hop out of.
|
|
*/
|
|
if (eptr->lo_any.next == NULL)
|
|
{
|
|
int32 no_loop_id;
|
|
|
|
no_loop_id = eptr->lo_any.ele_id;
|
|
|
|
/*
|
|
* Jump cell boundries if there is one
|
|
* between here and the next element.
|
|
*/
|
|
eptr = lo_JumpCellWall(context, state, eptr);
|
|
|
|
/*
|
|
* If non-null eptr is the cell we were in, move
|
|
* to the next cell/element.
|
|
*/
|
|
if (eptr != NULL)
|
|
{
|
|
eptr = eptr->lo_any.next;
|
|
}
|
|
|
|
/*
|
|
* infinite loop prevention
|
|
*/
|
|
if ((eptr != NULL)&&(eptr->lo_any.ele_id <= no_loop_id))
|
|
{
|
|
#ifdef DEBUG
|
|
XP_TRACE(("Find loop avoidance 1\n"));
|
|
#endif /* DEBUG */
|
|
eptr = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
eptr = eptr->lo_any.next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If no previous element, see if this is a CELL we can
|
|
* hop out of.
|
|
*/
|
|
if (eptr->lo_any.prev == NULL)
|
|
{
|
|
int32 no_loop_id;
|
|
|
|
no_loop_id = eptr->lo_any.ele_id;
|
|
|
|
/*
|
|
* Jump cell boundries if there is one
|
|
* between here and the previous element.
|
|
*/
|
|
eptr = lo_JumpCellWall(context, state, eptr);
|
|
|
|
/*
|
|
* If non-null eptr is the cell we were in, move
|
|
* to the previous cell/element.
|
|
*/
|
|
if (eptr != NULL)
|
|
{
|
|
eptr = eptr->lo_any.prev;
|
|
}
|
|
|
|
/*
|
|
* infinite loop prevention
|
|
*/
|
|
if ((eptr != NULL)&&(eptr->lo_any.ele_id >= no_loop_id))
|
|
{
|
|
#ifdef DEBUG
|
|
XP_TRACE(("Find loop avoidance 2\n"));
|
|
#endif /* DEBUG */
|
|
eptr = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
eptr = eptr->lo_any.prev;
|
|
}
|
|
}
|
|
|
|
while (eptr != NULL)
|
|
{
|
|
if (eptr->type == LO_LINEFEED)
|
|
{
|
|
break;
|
|
}
|
|
else if ((eptr->type == LO_TEXT)&&(eptr->lo_text.text != NULL))
|
|
{
|
|
break;
|
|
}
|
|
else if (eptr->type == LO_CELL)
|
|
{
|
|
/*
|
|
* When we walk onto a cell, we need
|
|
* to walk into it if it isn't empty.
|
|
*/
|
|
if ((forward != FALSE)&&
|
|
(eptr->lo_cell.cell_list != NULL))
|
|
{
|
|
eptr = eptr->lo_cell.cell_list;
|
|
continue;
|
|
}
|
|
else if ((forward == FALSE)&&
|
|
(eptr->lo_cell.cell_list_end != NULL))
|
|
{
|
|
eptr = eptr->lo_cell.cell_list_end;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Move forward or back to the next element
|
|
*/
|
|
if (forward != FALSE)
|
|
{
|
|
/*
|
|
* If no next element, see if this is a CELL we can
|
|
* hop out of.
|
|
*/
|
|
if (eptr->lo_any.next == NULL)
|
|
{
|
|
int32 no_loop_id;
|
|
|
|
no_loop_id = eptr->lo_any.ele_id;
|
|
|
|
/*
|
|
* Jump cell boundries if there is one
|
|
* between here and the next element.
|
|
*/
|
|
eptr = lo_JumpCellWall(context, state, eptr);
|
|
|
|
/*
|
|
* If non-null eptr is the cell we were in, move
|
|
* to the next cell/element.
|
|
*/
|
|
if (eptr != NULL)
|
|
{
|
|
eptr = eptr->lo_any.next;
|
|
}
|
|
|
|
/*
|
|
* infinite loop prevention
|
|
*/
|
|
if ((eptr != NULL)&&(
|
|
eptr->lo_any.ele_id <= no_loop_id))
|
|
{
|
|
#ifdef DEBUG
|
|
XP_TRACE(("Find loop avoidance 3\n"));
|
|
#endif /* DEBUG */
|
|
eptr = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
eptr = eptr->lo_any.next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If no previous element, see if this is a CELL we can
|
|
* hop out of.
|
|
*/
|
|
if (eptr->lo_any.prev == NULL)
|
|
{
|
|
int32 no_loop_id;
|
|
|
|
no_loop_id = eptr->lo_any.ele_id;
|
|
|
|
/*
|
|
* Jump cell boundries if there is one
|
|
* between here and the previous element.
|
|
*/
|
|
eptr = lo_JumpCellWall(context, state, eptr);
|
|
|
|
/*
|
|
* If non-null eptr is the cell we were in, move
|
|
* to the previous cell/element.
|
|
*/
|
|
if (eptr != NULL)
|
|
{
|
|
eptr = eptr->lo_any.prev;
|
|
}
|
|
|
|
/*
|
|
* infinite loop prevention
|
|
*/
|
|
if ((eptr != NULL)&&
|
|
(eptr->lo_any.ele_id >= no_loop_id))
|
|
{
|
|
#ifdef DEBUG
|
|
XP_TRACE(("Find loop avoidance 4\n"));
|
|
#endif /* DEBUG */
|
|
eptr = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
eptr = eptr->lo_any.prev;
|
|
}
|
|
}
|
|
}
|
|
if (eptr == NULL)
|
|
{
|
|
*ele_loc = NULL;
|
|
*pos = 0;
|
|
}
|
|
else if (eptr->type == LO_TEXT)
|
|
{
|
|
*ele_loc = eptr;
|
|
if (forward != FALSE)
|
|
{
|
|
*pos = 0;
|
|
}
|
|
else
|
|
{
|
|
#ifdef INTL_FIND
|
|
/* Add by ftang to provide international find */
|
|
if(eptr->lo_text.text_len == 0)
|
|
position = 0;
|
|
else
|
|
position = INTL_PrevCharIdxInText(win_csid, (unsigned char*)eptr->lo_text.text, eptr->lo_text.text_len );
|
|
#else
|
|
position = eptr->lo_text.text_len - 1;
|
|
if (position < 0)
|
|
{
|
|
position = 0;
|
|
}
|
|
#endif
|
|
*pos = position;
|
|
}
|
|
}
|
|
else if (eptr->type == LO_LINEFEED)
|
|
{
|
|
*ele_loc = eptr;
|
|
*pos = 0;
|
|
}
|
|
}
|
|
|
|
|
|
static Bool
|
|
lo_find_in_list(MWContext *context, lo_DocState *state,
|
|
LO_Element *eptr, char *cmp_text, int32 len, int32 position,
|
|
LO_Element **start_ele_loc, int32 *start_position,
|
|
LO_Element **end_ele_loc, int32 *end_position,
|
|
Bool use_case, Bool forward)
|
|
{
|
|
int32 cnt;
|
|
LO_Element *start_element, *end_element;
|
|
int32 start_pos, end_pos;
|
|
INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
|
|
int16 win_csid = INTL_GetCSIWinCSID(c);
|
|
|
|
while (eptr != NULL)
|
|
{
|
|
Bool have_start, not_equal;
|
|
int charlen = 1;
|
|
|
|
have_start = FALSE;
|
|
while ((eptr != NULL)&&(have_start == FALSE))
|
|
{
|
|
unsigned char *tptr;
|
|
unsigned char *str;
|
|
|
|
switch (eptr->type)
|
|
{
|
|
#ifndef INTL_FIND
|
|
char tchar;
|
|
#endif
|
|
case LO_TEXT:
|
|
if (eptr->lo_text.text != NULL)
|
|
{
|
|
PA_LOCK(str, unsigned char *,
|
|
eptr->lo_text.text);
|
|
tptr = (unsigned char *)(str + position);
|
|
#ifdef INTL_FIND
|
|
if (use_case)
|
|
have_start = INTL_MatchOneCaseChar(win_csid, (unsigned char*)cmp_text,tptr,&charlen);
|
|
else
|
|
have_start = INTL_MatchOneChar(win_csid, (unsigned char*)cmp_text,tptr,&charlen);
|
|
#else
|
|
if (use_case == FALSE)
|
|
{
|
|
tchar = TOLOWER(*tptr);
|
|
}
|
|
else
|
|
{
|
|
tchar = *tptr;
|
|
}
|
|
if (cmp_text[0] == tchar)
|
|
{
|
|
have_start = TRUE;
|
|
}
|
|
#endif
|
|
PA_UNLOCK(eptr->lo_text.text);
|
|
}
|
|
break;
|
|
case LO_LINEFEED:
|
|
if (cmp_text[0] == ' ')
|
|
{
|
|
have_start = TRUE;
|
|
}
|
|
break;
|
|
case LO_HRULE:
|
|
case LO_FORM_ELE:
|
|
case LO_BULLET:
|
|
case LO_IMAGE:
|
|
case LO_SUBDOC:
|
|
case LO_TABLE:
|
|
default:
|
|
break;
|
|
}
|
|
if (have_start == FALSE)
|
|
{
|
|
lo_next_character(context, state,
|
|
&eptr, &position, forward);
|
|
}
|
|
}
|
|
if (have_start == FALSE)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
start_element = eptr;
|
|
start_pos = position;
|
|
#ifdef INTL_FIND
|
|
if (len == charlen)
|
|
#else
|
|
if (len == 1)
|
|
#endif
|
|
{
|
|
end_element = eptr;
|
|
end_pos = position;
|
|
*start_ele_loc = start_element;
|
|
*start_position = start_pos;
|
|
*end_ele_loc = end_element;
|
|
*end_position = end_pos;
|
|
return(TRUE);
|
|
}
|
|
|
|
#ifdef INTL_FIND
|
|
cnt = charlen;
|
|
#else
|
|
cnt = 1;
|
|
#endif
|
|
not_equal = FALSE;
|
|
lo_next_character(context, state, &eptr, &position, TRUE);
|
|
while ((eptr != NULL)&&(cnt < len)&&(not_equal == FALSE))
|
|
{
|
|
unsigned char *tptr; /* this needs to be an unsigned quantity! chouck 3-Nov-94 */
|
|
char *str;
|
|
|
|
switch (eptr->type)
|
|
{
|
|
#ifndef INTL_FIND
|
|
char tchar;
|
|
#endif
|
|
case LO_TEXT:
|
|
if (eptr->lo_text.text != NULL)
|
|
{
|
|
PA_LOCK(str, char *,
|
|
eptr->lo_text.text);
|
|
tptr = (unsigned char *)(str + position);
|
|
#ifdef INTL_FIND
|
|
if (use_case)
|
|
not_equal = ! INTL_MatchOneCaseChar(win_csid,(unsigned char *) cmp_text+cnt,tptr,&charlen);
|
|
else
|
|
not_equal = ! INTL_MatchOneChar(win_csid,(unsigned char *) cmp_text+cnt,tptr,&charlen);
|
|
#else
|
|
if (use_case == FALSE)
|
|
{
|
|
/* this needs to be an unsigned quantity! chouck 3-Nov-94 */
|
|
tchar = TOLOWER(*tptr);
|
|
}
|
|
else
|
|
{
|
|
tchar = (char) *tptr;
|
|
}
|
|
if (tchar != cmp_text[cnt])
|
|
{
|
|
not_equal = TRUE;
|
|
}
|
|
#endif
|
|
PA_UNLOCK(eptr->lo_text.text);
|
|
}
|
|
break;
|
|
case LO_LINEFEED:
|
|
if (cmp_text[cnt] != ' ')
|
|
{
|
|
not_equal = TRUE;
|
|
}
|
|
break;
|
|
case LO_HRULE:
|
|
case LO_FORM_ELE:
|
|
case LO_BULLET:
|
|
case LO_IMAGE:
|
|
case LO_SUBDOC:
|
|
case LO_TABLE:
|
|
default:
|
|
break;
|
|
}
|
|
#ifdef INTL_FIND
|
|
cnt += charlen;
|
|
#else
|
|
cnt++;
|
|
#endif
|
|
if ((not_equal == FALSE)&&(cnt < len))
|
|
{
|
|
lo_next_character(context, state,
|
|
&eptr, &position, TRUE);
|
|
}
|
|
}
|
|
|
|
if ((cnt == len)&&(not_equal == FALSE))
|
|
{
|
|
end_element = eptr;
|
|
end_pos = position;
|
|
*start_ele_loc = start_element;
|
|
*start_position = start_pos;
|
|
*end_ele_loc = end_element;
|
|
*end_position = end_pos;
|
|
return(TRUE);
|
|
}
|
|
|
|
eptr = start_element;
|
|
position = start_pos;
|
|
lo_next_character(context, state, &eptr, &position, forward);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
static Bool
|
|
lo_element_in_floating_cell(MWContext *context, lo_DocState *state,
|
|
LO_Element *eptr)
|
|
{
|
|
LO_Element *cell;
|
|
LO_Element *f_ptr;
|
|
int32 x, y;
|
|
int32 ret_x, ret_y;
|
|
|
|
/*
|
|
* Error test.
|
|
*/
|
|
if (eptr == NULL)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
x = eptr->lo_any.x + eptr->lo_any.x_offset;
|
|
y = eptr->lo_any.y + eptr->lo_any.y_offset;
|
|
|
|
/*
|
|
* This wouldn't work if the element had zero width, but since
|
|
* we are assuming we are calling this on an element returned
|
|
* as the result of a FIND operation, it must be a text item
|
|
* with a non-zero width.
|
|
*/
|
|
cell = lo_XYToDocumentElement(context, state, x, y, TRUE, FALSE, TRUE,
|
|
&ret_x, &ret_y);
|
|
if ((cell == NULL)||(cell->type != LO_CELL))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
* Now look for this cell in the float list.
|
|
*/
|
|
f_ptr = state->float_list;
|
|
while (f_ptr != NULL)
|
|
{
|
|
if (f_ptr == cell)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
f_ptr = f_ptr->lo_any.next;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
Bool
|
|
LO_FindText(MWContext *context, char *text,
|
|
LO_Element **start_ele_loc, int32 *start_position,
|
|
LO_Element **end_ele_loc, int32 *end_position,
|
|
Bool use_case, Bool forward)
|
|
{
|
|
int32 doc_id;
|
|
lo_TopState *top_state;
|
|
lo_DocState *state;
|
|
LO_Element *eptr;
|
|
LO_Element *start_element, *end_element;
|
|
int32 start_pos, end_pos;
|
|
int32 position;
|
|
int32 i, len;
|
|
char *cmp_text;
|
|
Bool start_at_top;
|
|
Bool search_float_list;
|
|
Bool ret_val;
|
|
|
|
start_at_top = FALSE;
|
|
search_float_list = TRUE;
|
|
|
|
/*
|
|
* Get the unique document ID, and retreive this
|
|
* documents layout state.
|
|
*/
|
|
doc_id = XP_DOCID(context);
|
|
top_state = lo_FetchTopState(doc_id);
|
|
if ((top_state == NULL)||(top_state->doc_state == NULL))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
state = top_state->doc_state;
|
|
|
|
eptr = *start_ele_loc;
|
|
position = *start_position;
|
|
|
|
if (eptr == NULL)
|
|
{
|
|
start_at_top = TRUE;
|
|
if (forward != FALSE)
|
|
{
|
|
if (state->line_num <= 1)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
else
|
|
{
|
|
LO_Element **array;
|
|
#ifdef XP_WIN16
|
|
{
|
|
XP_Block *larray_array;
|
|
|
|
XP_LOCK_BLOCK(larray_array, XP_Block *,
|
|
state->larray_array);
|
|
state->line_array = larray_array[0];
|
|
XP_UNLOCK_BLOCK(state->larray_array);
|
|
}
|
|
#endif /* XP_WIN16 */
|
|
|
|
XP_LOCK_BLOCK(array, LO_Element **,
|
|
state->line_array);
|
|
eptr = array[0];
|
|
XP_UNLOCK_BLOCK(state->line_array);
|
|
if (eptr == NULL)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
position = 0;
|
|
}
|
|
else
|
|
{
|
|
if (state->line_num <= 1)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
else
|
|
{
|
|
eptr = state->end_last_line;
|
|
if (eptr == NULL)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
position = 0;
|
|
}
|
|
}
|
|
/*
|
|
* Else, if we were passed a start position, we need to know if
|
|
* that position is in a floating element in the margin, or is
|
|
* in one of the normal document lines. If we starting in the
|
|
* float list, we don't want to search it a second time.
|
|
*/
|
|
else if (lo_element_in_floating_cell(context, state, eptr))
|
|
{
|
|
search_float_list = FALSE;
|
|
}
|
|
|
|
len = XP_STRLEN(text);
|
|
cmp_text = (char*) XP_ALLOC(len + 1);
|
|
if (cmp_text == NULL)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
#ifdef INTL_FIND
|
|
/* If we use INTL_FIND. Do the conversion for the cmp_text later in INTL_MatchOneChar() routine */
|
|
for (i=0; i<len; i++)
|
|
{
|
|
cmp_text[i] = text[i];
|
|
}
|
|
#else
|
|
if (use_case != FALSE)
|
|
{
|
|
for (i=0; i<len; i++)
|
|
{
|
|
cmp_text[i] = text[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i=0; i<len; i++)
|
|
{
|
|
cmp_text[i] = TOLOWER((unsigned char) text[i]);
|
|
}
|
|
}
|
|
#endif
|
|
cmp_text[len] = '\0';
|
|
|
|
if (start_at_top == FALSE)
|
|
{
|
|
lo_next_character(context, state, &eptr, &position, forward);
|
|
}
|
|
|
|
ret_val = lo_find_in_list(context, state, eptr, cmp_text, len,
|
|
position, &start_element, &start_pos,
|
|
&end_element, &end_pos, use_case, forward);
|
|
if (ret_val != FALSE)
|
|
{
|
|
*start_ele_loc = start_element;
|
|
*start_position = start_pos;
|
|
*end_ele_loc = end_element;
|
|
*end_position = end_pos;
|
|
|
|
if (cmp_text != NULL)
|
|
{
|
|
XP_FREE(cmp_text);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* While we failed to find anything, we still havn't checked the
|
|
* contents of table in the margins. It will appear out of
|
|
* order, but we should check them now.
|
|
*/
|
|
if (search_float_list != FALSE)
|
|
{
|
|
eptr = state->float_list;
|
|
position = 0;
|
|
ret_val = lo_find_in_list(context, state, eptr, cmp_text, len,
|
|
position, &start_element, &start_pos,
|
|
&end_element, &end_pos, use_case, forward);
|
|
if (ret_val != FALSE)
|
|
{
|
|
*start_ele_loc = start_element;
|
|
*start_position = start_pos;
|
|
*end_ele_loc = end_element;
|
|
*end_position = end_pos;
|
|
|
|
if (cmp_text != NULL)
|
|
{
|
|
XP_FREE(cmp_text);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
if (cmp_text != NULL)
|
|
{
|
|
XP_FREE(cmp_text);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
static Bool
|
|
lo_child_search(MWContext *context, MWContext **ret_context, char *text,
|
|
LO_Element **start_ele_loc, int32 *start_position,
|
|
LO_Element **end_ele_loc, int32 *end_position,
|
|
Bool use_case, Bool forward)
|
|
{
|
|
int32 doc_id;
|
|
lo_TopState *top_state;
|
|
lo_DocState *state;
|
|
Bool ret_val;
|
|
|
|
/*
|
|
* Get the unique document ID, and retreive this
|
|
* documents layout state.
|
|
*/
|
|
doc_id = XP_DOCID(context);
|
|
top_state = lo_FetchTopState(doc_id);
|
|
if ((top_state == NULL)||(top_state->doc_state == NULL))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
state = top_state->doc_state;
|
|
ret_val = FALSE;
|
|
|
|
if (top_state->is_grid == FALSE)
|
|
{
|
|
ret_val = LO_FindText(context, text,
|
|
start_ele_loc, start_position,
|
|
end_ele_loc, end_position,
|
|
use_case, forward);
|
|
if (ret_val != FALSE)
|
|
{
|
|
*ret_context = context;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lo_GridCellRec *cell_ptr;
|
|
|
|
cell_ptr = top_state->the_grid->cell_list;
|
|
while (cell_ptr != NULL)
|
|
{
|
|
if (cell_ptr->context != NULL)
|
|
{
|
|
/*
|
|
* Always start at the beginning of
|
|
* child docs.
|
|
*/
|
|
*start_ele_loc = NULL;
|
|
*end_ele_loc = NULL;
|
|
*start_position = 0;
|
|
*end_position = 0;
|
|
ret_val = lo_child_search(cell_ptr->context,
|
|
ret_context, text,
|
|
start_ele_loc, start_position,
|
|
end_ele_loc, end_position,
|
|
use_case, forward);
|
|
if (ret_val != FALSE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
cell_ptr = cell_ptr->next;
|
|
}
|
|
}
|
|
|
|
return(ret_val);
|
|
}
|
|
|
|
|
|
static Bool
|
|
lo_sibling_search(MWContext *child, MWContext **ret_context, char *text,
|
|
LO_Element **start_ele_loc, int32 *start_position,
|
|
LO_Element **end_ele_loc, int32 *end_position,
|
|
Bool use_case, Bool forward)
|
|
{
|
|
MWContext *parent;
|
|
int32 doc_id;
|
|
lo_TopState *top_state;
|
|
Bool ret_val;
|
|
lo_GridCellRec *cell_ptr;
|
|
|
|
/*
|
|
* We must have a grid parent
|
|
*/
|
|
parent = child->grid_parent;
|
|
if (parent == NULL)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
* Get the unique document ID, and retreive this
|
|
* documents layout state.
|
|
*/
|
|
doc_id = XP_DOCID(parent);
|
|
top_state = lo_FetchTopState(doc_id);
|
|
if ((top_state == NULL)||(top_state->doc_state == NULL))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
* We must have a grid parent
|
|
*/
|
|
if (top_state->is_grid == FALSE)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
ret_val = FALSE;
|
|
|
|
/*
|
|
* Find the sibling after the child
|
|
*/
|
|
cell_ptr = top_state->the_grid->cell_list;
|
|
while (cell_ptr != NULL)
|
|
{
|
|
if (cell_ptr->context == child)
|
|
{
|
|
cell_ptr = cell_ptr->next;
|
|
break;
|
|
}
|
|
cell_ptr = cell_ptr->next;
|
|
}
|
|
|
|
/*
|
|
* Search all siblings (if any).
|
|
*/
|
|
while (cell_ptr != NULL)
|
|
{
|
|
if (cell_ptr->context != NULL)
|
|
{
|
|
/*
|
|
* Always start at the beginning of sibling docs.
|
|
*/
|
|
*start_ele_loc = NULL;
|
|
*end_ele_loc = NULL;
|
|
*start_position = 0;
|
|
*end_position = 0;
|
|
ret_val = lo_child_search(cell_ptr->context,
|
|
ret_context, text,
|
|
start_ele_loc, start_position,
|
|
end_ele_loc, end_position,
|
|
use_case, forward);
|
|
if (ret_val != FALSE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
cell_ptr = cell_ptr->next;
|
|
}
|
|
|
|
return(ret_val);
|
|
}
|
|
|
|
|
|
Bool
|
|
LO_FindGridText(MWContext *context, MWContext **ret_context, char *text,
|
|
LO_Element **start_ele_loc, int32 *start_position,
|
|
LO_Element **end_ele_loc, int32 *end_position,
|
|
Bool use_case, Bool forward)
|
|
{
|
|
int32 doc_id;
|
|
lo_TopState *top_state;
|
|
lo_DocState *state;
|
|
Bool ret_val;
|
|
LO_Element *start_ele;
|
|
LO_Element *end_ele;
|
|
int32 start_pos;
|
|
int32 end_pos;
|
|
|
|
/*
|
|
* Get the unique document ID, and retreive this
|
|
* documents layout state.
|
|
*/
|
|
doc_id = XP_DOCID(context);
|
|
top_state = lo_FetchTopState(doc_id);
|
|
if ((top_state == NULL)||(top_state->doc_state == NULL))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
state = top_state->doc_state;
|
|
ret_val = FALSE;
|
|
start_ele = *start_ele_loc;
|
|
end_ele = *end_ele_loc;
|
|
start_pos = *start_position;
|
|
end_pos = *end_position;
|
|
|
|
/*
|
|
* If no starting context we start at the top level grid context.
|
|
*/
|
|
if (*ret_context == NULL)
|
|
{
|
|
MWContext *parent;
|
|
|
|
/*
|
|
* Find the top of the nested grid tree
|
|
*/
|
|
parent = context;
|
|
while ((parent->is_grid_cell != FALSE)&&
|
|
(parent->grid_parent != NULL))
|
|
{
|
|
parent = parent->grid_parent;
|
|
}
|
|
/*
|
|
* Search the tree completely.
|
|
*/
|
|
ret_val = lo_child_search(parent, ret_context, text,
|
|
start_ele_loc, start_position,
|
|
end_ele_loc, end_position,
|
|
use_case, forward);
|
|
}
|
|
else
|
|
{
|
|
MWContext *child;
|
|
|
|
/*
|
|
* Search the starting context at the starting position.
|
|
*/
|
|
child = *ret_context;
|
|
ret_val = lo_child_search(child, ret_context, text,
|
|
start_ele_loc, start_position,
|
|
end_ele_loc, end_position,
|
|
use_case, forward);
|
|
|
|
/*
|
|
* If it wasn't in the starting context, walk up the tree
|
|
* searching all siblings (after the parent sibling)
|
|
* at each level.
|
|
*/
|
|
while ((ret_val == FALSE)&&(child->is_grid_cell != FALSE)&&
|
|
(child->grid_parent != NULL))
|
|
{
|
|
/*
|
|
* Always start at the beginning of sibling docs.
|
|
*/
|
|
*start_ele_loc = NULL;
|
|
*end_ele_loc = NULL;
|
|
*start_position = 0;
|
|
*end_position = 0;
|
|
ret_val = lo_sibling_search(child, ret_context, text,
|
|
start_ele_loc, start_position,
|
|
end_ele_loc, end_position,
|
|
use_case, forward);
|
|
child = child->grid_parent;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we didn't find it, restore starting values.
|
|
*/
|
|
if (ret_val == FALSE)
|
|
{
|
|
*start_ele_loc = start_ele;
|
|
*end_ele_loc = end_ele;
|
|
*start_position = start_pos;
|
|
*end_position = end_pos;
|
|
}
|
|
|
|
return(ret_val);
|
|
}
|
|
|
|
|
|
void
|
|
LO_SelectText(MWContext *context, LO_Element *start, int32 start_pos,
|
|
LO_Element *end, int32 end_pos, int32 *x, int32 *y)
|
|
{
|
|
int32 doc_id;
|
|
lo_TopState *top_state;
|
|
lo_DocState *state;
|
|
|
|
/*
|
|
* Get the unique document ID, and retreive this
|
|
* documents layout state.
|
|
*/
|
|
doc_id = XP_DOCID(context);
|
|
top_state = lo_FetchTopState(doc_id);
|
|
if ((top_state == NULL)||(top_state->doc_state == NULL))
|
|
{
|
|
return;
|
|
}
|
|
state = top_state->doc_state;
|
|
|
|
if ((start == NULL)||(end == NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
LO_HighlightSelection(context, FALSE);
|
|
|
|
state->selection_start = start;
|
|
state->selection_start_pos = start_pos;
|
|
state->selection_end = end;
|
|
state->selection_end_pos = end_pos;
|
|
|
|
LO_HighlightSelection(context, TRUE);
|
|
|
|
*x = (start->lo_any.x + state->base_x);
|
|
*y = (start->lo_any.y + state->base_y);
|
|
}
|
|
|
|
#ifdef TEST_16BIT
|
|
#undef XP_WIN16
|
|
#endif /* TEST_16BIT */
|
|
|
|
#ifdef PROFILE
|
|
#pragma profile off
|
|
#endif
|