Esempio n. 1
0
ERRORCODE TextFlow::adjust_words(DB_RECORD_NUMBER p_record,
					DB_RECORD_NUMBER f_record,
					CHARACTER_DELTA cdelta, WORD_DELTA_PTR wdelta)
{
	ParagraphPtr paragraph;
	W_INDEX w_index;
	TEXT_WORD_PTR wp;
	ERRORCODE error;

	/* Redisplay vars */
	LINE_PTR lp;
	FramePtr frame;
	PCOORD erase_xmin, erase_xmax;
	W_INDEX old_windex;
	L_INDEX l_index;
	BOOL deleted_something;

/*
// Initialize the word delta structure first.
*/

	wdelta->w_start = -1;
	wdelta->count = 0;

/* Make sure we avoid busy work. */

	if (cdelta.count == 0)
	{
		return ERRORCODE_None;
	}

/* Lock the paragraph so we can access it. */

	if ((paragraph = (ParagraphPtr)database->get_record(p_record, &error, RECORD_TYPE_Paragraph)) == NULL)
	{
		return error;
	}

/* Get the frame object. */

	if ((frame = (FramePtr)database->get_record(f_record, &error, RECORD_TYPE_Frame)) == NULL)
	{
		paragraph->release();
		return error;
	}

/*
// Run through the word array and update all words which need it.
// We must be careful using a pointer into the word array data since any
// deletions can cause the array data to change locations.
*/

	/* Initialize redisplay variables */
	deleted_something = FALSE;
	lp = NULL;
	old_windex = 0;
	l_index = frame->line_of_word(0, NULL);
	lp = (LINE_PTR)frame->line.get_element(l_index);

	for (wp = (TEXT_WORD_PTR)paragraph->word.get_element(0), w_index = 0;
							w_index < paragraph->word.count();
							old_windex++,
 							w_index++, wp++)
	{
		C_INDEX this_start;

		if ((this_start = wp->c_start) >= cdelta.c_start)
		{
		/* This has moved. Move it now. */
		/* If deleting, see if the array is still valid. */

			if ((this_start += cdelta.count) <= cdelta.c_start)
			{
				this_start = cdelta.c_start;
				if (!deleted_something)
				{
					deleted_something = TRUE;

					erase_xmin = wp->x_offset + wp->draw_left;
					erase_xmax = wp->x_offset + wp->draw_width;
				}

			/*
			// Update the word delta.
			// This makes the (valid) assumption that words which get
			// deleted are all contiguous.
			*/

				if (wdelta->w_start == -1)
				{
					wdelta->w_start = w_index;

					/* Start updating w1 (last word to erase) */
					l_index = frame->line_of_word(w_index, NULL);
					lp = (LINE_PTR)frame->line.get_element(l_index);

					erase_xmax = __max(erase_xmax, wp->x_offset + wp->draw_width);
					erase_xmin = __min(erase_xmin, wp->x_offset + wp->draw_left);
				}
				else
				{
				/* The previous word has vanished. Delete it now. */
					if (old_windex > lp->w_end)
					{
						/* That's all the words for this line.  Erase the words */
						add_width_refresh_extent(frame, lp,
									erase_xmin, erase_xmax, REFRESH_ERASE);

						/* Start a new line */
						erase_xmin = wp->x_offset + wp->draw_left;
						erase_xmax = wp->x_offset + wp->draw_width;
						lp++;
					}
					else
					{
						erase_xmax = __max(erase_xmax, wp->x_offset + wp->draw_width);
					}

					wdelta->count--;

				/* Do the actual delete. */

					paragraph->delete_word(--w_index);
					paragraph->modified();
#ifdef DEBUG_AW
					printf("Delete previous word (%d)\n", w_index);
#endif
				/* Recompute 'wp' in case 'word.data' changed. */

					wp = (TEXT_WORD_PTR)paragraph->word.get_element(w_index);
				}
			}

#ifdef DEBUG_AW
			printf("Bumped WORD %d from index %d to %d (", w_index, wp->c_start, this_start);
#endif

		/* Set the new start. */

			wp->c_start = this_start;

#ifdef DEBUG_AW
			dump_word(paragraph, wp);
			printf(")\n");
#endif
		}
		else
		{
			/* Advance the erase anchor point */
			erase_xmin = __min(erase_xmin, wp->x_offset + wp->draw_left);
		}
	}

	if (deleted_something)
	{
		/* Found at least one line to delete.  Delete the last line we found */
		add_width_refresh_extent(frame, lp,
			erase_xmin, erase_xmax, REFRESH_ERASE);
	}

/* Release the objects we got. */

	frame->release();
	paragraph->release();

	return ERRORCODE_None;
}
Esempio n. 2
0
ERRORCODE TextFlow::rebuild_words(DB_RECORD_NUMBER p_record,
					DB_RECORD_NUMBER f_record,
					CHARACTER_RANGE crange,
					WORD_DELTA_PTR wdelta, WORD_RANGE_PTR wrange)
{
	ParagraphPtr paragraph;
	FramePtr frame;
	W_INDEX w_index, w_start, w_end;
	TEXT_WORD_PTR wp;
	C_INDEX c_index;
	CHARACTER_PTR cp;
	ERRORCODE error;

/*
// Initialize the word delta structure first.
*/

	wrange->w_start =
		wrange->w_end =
		wdelta->w_start = -1;
	wdelta->count = 0;

/* Get the paragraph so we can operate on it. */

	if ((paragraph = (ParagraphPtr)database->get_record(p_record, &error, RECORD_TYPE_Paragraph)) == NULL)
	{
	/* Error! */
		return error;
	}

/* See if there is any text. */

	SHORT text_count = paragraph->number_of_characters();

	if (text_count == 0)
	{
	/* No text! No words to form. */
		paragraph->release();
		return ERRORCODE_None;
	}

/* Figure out where to begin forming words. */

	if (crange.c_start < 0)
	{
		crange.c_start = 0;
	}
	if (crange.c_start >= text_count)
	{
		crange.c_start = text_count-1;
	}
	if (crange.c_end < 0 || crange.c_end >= text_count)
	{
		crange.c_end = text_count-1;
	}

	if (crange.c_start > crange.c_end)
	{
	/*
 	// Huh? Bad parameters!
	// We could adjust the parameters to full extent and continue, but then
	// we might not catch a bad programming case.
	// Let's just return an error for now.
 	*/
		od("rebuild_words: bad parameters\r\n");

		paragraph->release();

		return ERRORCODE_BadParameter;
	}

/*
// The first thing we need to do is go through and figure out which words
// are going to be rebuilt. The first word to be rebuilt is the word containing
// the start change (or the previous one if it's the first character of that
// word). The c_index where word forming starts is the first character of
// this word. The last word to be rebuilt is the word containing the end
// change. The c_index where word forming stops is the last character of this
// word. These words will be deleted and rebuilt from the c_index range
// generated.
*/

/*
// A paragraph should always have at least one word (the eop word).
// OK. Here's the first problem: what happens if c_start > word(eop).c_start?
// This means that the character indicies are inconsistent. This shouldn't
// happen, so let's see if we can detect it and flag an error.
*/

/*
// Look for the word containing the start offset.
*/

	SHORT word_count = paragraph->number_of_words();

	w_start = w_end = word_count;

	for (w_index = 0, wp = (TEXT_WORD_PTR)paragraph->word.get_element(0);
						w_index < word_count;
						wp++, w_index++)
	{
		if (wp->c_start >= crange.c_start)
		{
			w_start = w_index-1;
			break;
		}
	}

	if (w_start == word_count)
	{
	/* Couldn't find the c_index in our word array. Inconsistent. */
		paragraph->release();
		od("rebuild_words: start index inconsistent\r\n");
		return ERRORCODE_BadParameter;
	}
	else if (w_start < 0)
	{
	/* Means c_start is in first word. */
		w_start = 0;
	}

#ifdef DEBUG_RW
	printf("Found start offset %d in word %d (", crange.c_start, w_start);
	dump_word(paragraph, (TEXT_WORD_PTR)paragraph->word.data + w_start);
	printf(")\n");
#endif

/* Get the first index in this word. */

	wrange->w_start =
		wrange->w_end =
		wdelta->w_start = w_start;

	if ((c_index = paragraph->get_word(w_start)->c_start) < crange.c_start)
	{
	/* Move back to start of word. */
		crange.c_start = c_index;
		wdelta->w_start++;			/* First word stays put. */
	}

#ifdef DEBUG_RW
	printf("Start offset moves to %d\n", crange.c_start);
#endif

/*
// Look for the word containing the end offset.
*/

	for (; w_index < word_count; wp++, w_index++)
	{
		if (wp->c_start >= crange.c_end)
		{
			w_end = w_index;
			break;
		}
	}

	if (w_end == word_count)
	{
	/* Couldn't find the c_index in our word array. Inconsistent. */
		paragraph->release();

		od("rebuild_words: end index inconsistent\r\n");

		return ERRORCODE_IntError;
	}
	else if (w_end == word_count-1)
	{
	/* We ended up on the eop word. Move off of it. */
		w_end--;
	}

#ifdef DEBUG_RW
	printf("Found end offset %d in word %d (", crange.c_end, w_end);
	dump_word(paragraph, (TEXT_WORD_PTR)paragraph->word.data + w_end);
	printf(")\n");
#endif

/* Get the first index of the next word. */

	if ((c_index = paragraph->get_word(w_end+1)->c_start-1) > crange.c_end)
	{
	/* Move forward to end of word. */
		crange.c_end = c_index;
	}

#ifdef DEBUG_RW
	printf("End offset moves to %d\n", crange.c_end);
#endif

/*
// Delete the existing range if we have one.
// Perhaps this should be optimized someday to do all at once!
*/
	if (w_end >= w_start)
	{
		/* Redisplay variables */
		BOOL new_line = TRUE;
		L_INDEX l_index;
		LINE_PTR lp;
		TEXT_WORD_PTR wp0;
		PCOORD erase_xmin, erase_xmax;

		if ((frame = (FramePtr)database->get_record(f_record, &error, RECORD_TYPE_Frame)) == NULL)
		{
			paragraph->release();
			return error;
		}

		/* Get line pointer for redisplay purposes */

		l_index = frame->line_of_word(w_end, NULL);

		lp = frame->get_line(l_index);

		erase_xmin = 0x7fffffff;
		erase_xmax = -erase_xmin;

		wdelta->count = -(w_end - w_start + 1);
		while (w_end >= w_start)
		{
#ifdef DEBUG_RW
			printf("Delete word %d\n", w_end);
#endif
			wp0 = paragraph->get_word(w_end);
			if (!new_line && w_end < lp->w_start)
			{
				new_line = TRUE;
				add_width_refresh_extent(frame, lp,
					erase_xmin, erase_xmax, REFRESH_ERASE);
				lp--;
			}
			if (new_line)
			{
				new_line = FALSE;

				erase_xmin = wp0->x_offset + wp0->draw_left;
				erase_xmax = wp0->x_offset + wp0->draw_width;
			}
			else
			{
				erase_xmin = __min(erase_xmin, wp0->x_offset + wp0->draw_left);
				erase_xmax = __max(erase_xmax, wp0->x_offset + wp0->draw_width);
			}

			paragraph->delete_word(w_end--);
		}
		add_width_refresh_extent(frame, lp,
				erase_xmin, erase_xmax, REFRESH_ERASE);
		frame->release();
	}

/*
// Start forming new words.
*/

	for (w_index = w_start, c_index = crange.c_start,
 					cp = paragraph->get_character(c_index);
							c_index <= crange.c_end; )
	{
		TEXT_WORD word;

	/* Start this word. */

#ifdef DEBUG_RW
		printf(*cp < ' ' ? "[%d]" : "[%c]", *cp);
#endif

		word.type = character_type(*cp++);
		word.flags = WORD_FLAG_needs_sizing;
		word.c_start = c_index++;
		word.x_offset = -1;
		word.width = 0;

	/* Accumulate the rest of the word. */

		if (word.type == WORD_TYPE_solid)
		{
		/* Search for the next word start. */

			while (c_index <= crange.c_end && character_type(*cp) == word.type)
			{
#ifdef DEBUG_RW
				printf(*cp < ' ' ? "(%d)" : "(%c)", *cp);
#endif

				cp++;
				c_index++;
			}
		}

	/* This is a whole new word. */

#ifdef DEBUG_RW
		printf(" ADD word %d, type %d, c (%d to %d) \n", w_index, word.type, word.c_start, c_index-1);
#endif
		paragraph->insert_word(w_index++, &word);

	/* Another delta in the word array. */

		wdelta->count++;
		wrange->w_end++;
	}

/* Release the paragraph. */

	paragraph->release(TRUE);

	return ERRORCODE_None;
}
Esempio n. 3
0
ERRORCODE TextFlow::refresh_frame(DB_RECORD_NUMBER f_record, CHARACTER_RANGE crange)
{
	ERRORCODE error;
	DB_RECORD_NUMBER p_record;
	WORD_RANGE wrange;
	FramePtr frame;
	ParagraphPtr paragraph;
	LINE line;
	PBOX pbox;

/* Get the frame. */

	if ((frame = (FramePtr)database->get_record(f_record, &error, RECORD_TYPE_Frame)) == NULL)
	{
		return error;
	}

	p_record = frame->get_paragraph();

/* Get the paragraph of the frame. */

	if ((paragraph = (ParagraphPtr)database->get_record(p_record, &error, RECORD_TYPE_Paragraph)) == NULL)
	{
		frame->release();
		return error;
	}

/* Fix the character range if special values were used. */

	if (crange.c_start < 0)
	{
		crange.c_start = 0;
	}
	if (crange.c_end < 0)
	{
		crange.c_end = paragraph->number_of_characters();
	}

/* Get the word range. */

	paragraph->crange_to_wrange(crange, &wrange);
	paragraph->release();

/* Get the top (and possibly bottom) line.*/

	frame->line_of_word(wrange.w_start, &line);

	pbox.y0 = line.baseline - line.ascend;

/* Now see if the words differ. If not, we must be on the same line. */

	if (wrange.w_end != wrange.w_start)
	{
	/* Get the bottom line. */
		frame->line_of_word(wrange.w_end, &line);
	}

	pbox.y1 = line.baseline + line.descend;

/* Get the frame so we can get the bound. */

	PBOX bound = frame->get_bound();
	FLAGS object_flags = frame_object->get_flags();

	pbox.x0 = bound.x0;
	pbox.x1 = bound.x1;

	if (object_flags & OBJECT_FLAG_yflipped)
	{
		PCOORD y0 = pbox.y0;
		pbox.y0 = bound.y1 - pbox.y1;
		pbox.y1 = bound.y1 - y0;
	}
	else
	{
		pbox.y0 += bound.y0;
		pbox.y1 += bound.y0;
	}

	frame->release();

/* Do the actual refresh add. */

	database->do_refresh_notify(&pbox, REFRESH_ALL, NULL);

	return ERRORCODE_None;
}