Attached is a fix for a bug in the etox_selection_get_geometry function. The bug caused the first line of the selection to be processed as a midline and consequently overrun the allocated memory for geometry rectangles. 3 lines were added at line 383.

By the way, the latest changes also broke word wrapping when the width of the etox region is smaller than the current word. I have not come up with a fix for that yet - just turned off word wrapping. :(

--
Bart Elberg
I.D.E.A.L. Technology Corporation


#include "Etox_private.h"

Evas_List *active_selections = NULL;

#define SELECTION_LOOP_START(selected) \
do { \
	Evas_Object *bit = NULL; \
	Etox_Line *line; \
	Evas_List *l, *bl; \
	Evas_Coord w, h; \
	line = selected->start.line; \
	l = evas_list_find_list(selected->etox->lines, selected->start.line); \
	bl = evas_list_find_list(line->bits, selected->start.bit); \
	while (bl && bit != selected->end.bit) { \
		bit = bl->data; \
		evas_object_geometry_get(bit, NULL, NULL, &w, NULL); \
		line->w -= w

#define SELECTION_LOOP_END \
		evas_object_geometry_get(bit, NULL, NULL, &w, &h); \
		line->w += w; \
		if (h > line->h) \
			line->h = h; \
		bl = bl->next; \
		if (!bl) { \
			l = l->next; \
			if (l) { \
				line = l->data; \
				bl = line->bits; \
			} \
		} \
	} \
} while (0)


Evas_Object *
etox_split_bit(Etox_Line *line, Evas_Object *bit, int index)
{
	Evas_List *l;
	Evas_Object *point = bit;
	Etox_Selection *selected;

	/*
	 * Split the leading bit, only need to inform selections that end with
	 * this bit.
	 */
	if (index && index < etox_style_length(bit)) {
		point = etox_style_split(bit, index);
		evas_object_smart_member_add(point, line->et->smart_obj);
		line->bits = evas_list_append_relative(line->bits, point, bit);

		l = active_selections;
		while (l) {
			selected = l->data;
			if (selected->end.bit == bit)
				selected->end.bit = point;
			l = l->next;
		}
	}

	return point;
}

Etox_Selection *
etox_selection_new(Etox *etox, Etox_Line *l1, Etox_Line *l2,
		Evas_Object *s1, Evas_Object *s2, int i1, int i2)
{
	Evas_Object *temp;
	Etox_Selection *selected;

	/*
	 * Split bits on their index boundaries, this updates selections that
	 * contain the bits.
	 */
	temp = etox_split_bit(l1, s1, i1);
	if (s1 == s2) {
		i2 -= i1;
		s2 = temp;
	}
	s1 = temp;

	/*
	 * Split on the ending index, we use the original s2 for the end,
	 * since it's the bit portion before the split.
	 */
	etox_split_bit(l2, s2, i2);

	selected = calloc(1, sizeof(Etox_Selection));
	memset(selected, 0, sizeof(Etox_Selection));

	selected->etox = etox;

	selected->start.line = l1;
	selected->start.bit = s1;

	selected->end.line = l2;
	selected->end.bit = s2;

	active_selections = evas_list_prepend(active_selections, selected);

	etox_layout(etox);

	return selected;
}

/**
 */
void
etox_selection_free(Etox_Selection *selected)
{
        CHECK_PARAM_POINTER("selected", selected);

	active_selections = evas_list_remove(active_selections, selected);
	FREE(selected);
}

/**
 */
void
etox_selection_free_by_etox(Evas_Object *obj)
{
	Etox *etox;
	Evas_List *l, *r = NULL;
	Etox_Selection *selected;

	CHECK_PARAM_POINTER("obj", obj);

	etox = evas_object_smart_data_get(obj);

        /*
         * loop through all active selections. add the ones on etox
         * to a second list, to be removed later.
         */
	for (l = active_selections; l; l = l->next) {
		selected = l->data;
		if (selected->etox == etox) {
                        r = evas_list_append(r, selected);
		}
	}


        for (l = r; l; l = l->next)
        {
          selected = l->data;

          active_selections = evas_list_remove(active_selections, selected);
          free(selected);
        }

        evas_list_free(r);
}

/**
 */
Etox_Selection *
etox_select_coords(Evas_Object *obj, Evas_Coord sx, Evas_Coord sy,
		   Evas_Coord ex, Evas_Coord ey)
{
	int i1, i2;
	Etox *et;
	Etox_Line *sl, *el = NULL;
	Evas_Object *sb, *eb = NULL;
	Etox_Selection *selected = NULL;

	CHECK_PARAM_POINTER_RETURN("obj", obj, NULL);

	et = evas_object_smart_data_get(obj);

	sl = etox_coord_to_line(et, sy);
	if (!sl)
		goto out;

	el = etox_coord_to_line(et, ey);
	if (!el)
		goto out;

	sb = etox_line_coord_to_bit(sl, sx);
	if (!sb)
		goto out;

	eb = etox_line_coord_to_bit(el, ex);
	if (!eb)
		goto out;

	i1 = etox_style_text_at_position(sb, sx, sy, NULL, NULL, NULL, NULL);
	i2 = etox_style_text_at_position(eb, sx, sy, NULL, NULL, NULL, NULL);

	selected = etox_selection_new(et, sl, el, sb, eb, i1, i2);

out:
	return selected;
}

/**
 * etox_select_index - create a selection based on two indices
 * @et: the etox to choose the selection
 * @si: the starting index of characters to be selected
 * @ei: the ending index of characters to be selected
 *
 * Returns a newly allocated selection on success, NULL on failure.
 */
Etox_Selection *
etox_select_index(Evas_Object * obj, int si, int ei)
{
	Etox *et;
	Etox_Line *sl = NULL, *el = NULL;
	Evas_Object *sb = NULL, *eb = NULL;
	Etox_Selection *selected = NULL;

	CHECK_PARAM_POINTER_RETURN("obj", obj, NULL);

	et = evas_object_smart_data_get(obj);

	/*
	 * First determine the lines containing the indices.
	 */
	sl = etox_index_to_line(et, &si);
	if (!sl)
		goto out;

	el = etox_index_to_line(et, &ei);
	if (!el)
		goto out;

	sb = etox_line_index_to_bit(sl, &si);
	if (!sb)
		goto out;

	eb = etox_line_index_to_bit(el, &ei);
	if (!eb)
		goto out;

	/*
	 * Create the new selection and assign it's fields
	 */
	selected = etox_selection_new(et, sl, el, sb, eb, si, ei);

out:
	return selected;
}

/**
 */
Etox_Selection *
etox_select_str(Evas_Object * obj, char *match, int *index)
{
	char *text = NULL, *pos = NULL;
	int i = 0, si = 0, ei = 0;

	CHECK_PARAM_POINTER_RETURN("obj", obj, NULL);

	/*
	 * FIXME possibly search bit by bit to cut down on
	 * memory for really large strings
	 */

	text = etox_get_text(obj);

	if (index)
	  i = *index;

	pos = strstr(text + i, match);	

	if (pos == NULL)
	{
	  if (index) *index = -1;
	  free(text);
	  return NULL;
	}

	si = pos - text;
	ei = si + strlen(match);

	printf("si: %d, ei: %d\n", si, ei);

	if (index)
	  *index = ei;

	free(text);

	return etox_select_index(obj, si, ei);
}

/**
 */
void
etox_selection_bounds(Etox_Selection *selected, Evas_Coord *sx, Evas_Coord *sy,
		      Evas_Coord *ex, Evas_Coord *ey)
{
}

/**
 */
void
etox_selection_add_callback(Etox_Selection *selected,
		Evas_Callback_Type callback, void (*func) (void *data, Evas *e,
					       Evas_Object *o, int b, int x,
					       int y), void *data)
{
}

/**
 */
void
etox_selection_del_callback(Etox_Selection *selected,
		Evas_Callback_Type callback)
{
}

void
etox_selection_apply_context(Etox_Selection *selected,
                             Etox_Context *context)
{
  Evas_List *l;
  Etox_Line *line;

  CHECK_PARAM_POINTER("selected", selected);
  CHECK_PARAM_POINTER("context", context);

  if (selected->start.line == selected->end.line)
  {
    etox_line_apply_context(selected->start.line, context,
                            selected->start.bit, selected->end.bit);
  }

  else
  {
    /* start on the first line */
    l = evas_list_find_list(selected->etox->lines, selected->start.line);

    line = l->data;
    
    for (; l; l = l->next)
    {
      line = l->data;

      /*
       * if start.bit is not on line, then the first bit of line will be
       * used as the starting bit. same for end.bit.
       */
      etox_line_apply_context(line, context, selected->start.bit,
                              selected->end.bit);
      
      if (line == selected->end.line)
        break;
    }
  }
  
  etox_layout(selected->etox);
}

void
etox_selections_update(Evas_Object *bit, Etox_Line *line)
{
	Evas_List *l;

	for (l = active_selections; l; l = l->next)
	{
		Etox_Selection *selected = evas_list_data(l);
		
		if (selected->start.bit == bit)
		{
		  selected->start.line = line;
		}

		if (selected->end.bit == bit)
		{
		  selected->end.line = line;
		}
	}
}

Etox_Rect *
etox_selection_get_geometry(Etox_Selection *selected, int *num)
{
  Etox_Rect *rects = NULL, *cur = NULL;
  Evas_List *l = NULL, *midlines = NULL;
  Evas_Coord x, y, w, h;
  int count = 0;

  l = evas_list_find_list(selected->etox->lines, selected->start.line);

  // Start with the second line (if any)
  l = l->next;
  count++; 	/* count the first line */

  while (l)
  {
    Etox_Line *line = l->data;

    count++; 	/* count the last line also */

    if (line == selected->end.line) break;

    midlines = evas_list_append(midlines, line);
    l = l->next;
  }

  printf("count: %d\n", count);

  rects = calloc(count, sizeof(Etox_Rect)); /* start and end line also */

  /* first line */
  //etox_line_index_to_geometry(selected->start.line, selected->start.index,
  //                             &x, &y, &w, &h);
  evas_object_geometry_get(selected->start.bit, &x, &y, &w, &h);
  rects->x = x;
  rects->y = y;
  etox_line_get_geometry(selected->start.line, &x, &y, &w, &h);
  rects->w = x + w - rects->x;
  rects->h = y + h - rects->y;

  cur = rects;
  /* printf("cur1: %d\n", cur); */
  for (l = midlines; l; l = l->next)
  {
    Etox_Line *line = l->data;

    cur++;
    /* printf("cur2: %d\n", cur); */
    etox_line_get_geometry(line, &x, &y, &w, &h);

    cur->x = x;
    cur->y = y;
    cur->w = w;
    cur->h = h;
  }

  if (selected->end.line != selected->start.line)
  {
    etox_line_get_geometry(selected->end.line, &x, &y, &w, &h);
    cur++;
    cur->x = x;
    cur->y = y;
  }

  //etox_line_index_to_geometry(selected->end.line, selected->end.index,
  //                            &x, &y, &w, &h);
  evas_object_geometry_get(selected->end.bit, &x, &y, &w, &h);
  cur->w = x + w - cur->x;
  cur->h = y + h - cur->y;

  
  if (num) *num = count;
  return rects;
}

Reply via email to