};
};
+/* If you need to draw slices using Evas Line,
+ * define the following debug flag manually. */
+//#define EFL_UI_TEXTPATH_LINE_DEBUG
+
struct _Efl_Ui_Textpath_Data
{
Evas_Object *text_obj;
Eina_Inlist *segments;
int total_length;
+#ifdef EFL_UI_TEXTPATH_LINE_DEBUG
+ Eina_List *lines;
+#endif
};
#define EFL_UI_TEXTPATH_DATA_GET(o, sd) \
}
static void
-_segment_draw(Efl_Ui_Textpath_Data *pd, int slice_no, int w1, int w2, int cmp, Evas_Map *map, Eina_Bezier bezier)
+_segment_draw(Efl_Ui_Textpath_Data *pd, int slice_no, double dt, double dist,
+ int w1, int cmp, Evas_Map *map, Eina_Bezier bezier,
+ int *last_x1, int *last_y1, int *last_x2, int *last_y2)
{
int x = 0, y = 0, w = 0, h = 0;
- int i, len, seg_len;
+ int i;
double u0, u1, v0, v1;
- double dist, t, dt;
+ double t;
double px, py, px2, py2;
double rad;
Eina_Vector2 vec, nvec, vec0, vec1, vec2, vec3;
Eina_Matrix2 mat;
+#ifdef EFL_UI_TEXTPATH_LINE_DEBUG
+ static Eina_Bool yello_color_flag = EINA_FALSE;
+ yello_color_flag = !yello_color_flag;
+#endif
- len = w2 - w1;
evas_object_geometry_get(pd->text_obj, NULL, NULL, &w, &h);
- seg_len = eina_bezier_length_get(&bezier);
- if (pd->autofit)
- dt = len / (seg_len * (double) slice_no);
- else
- dt = 1.0 / (double) slice_no;
- dist = len / (double)slice_no;
+
rad = _deg_to_rad(90);
eina_matrix2_values_set(&mat, cos(rad), -sin(rad), sin(rad), cos(rad));
vec2.x = (-vec.x + px);
vec2.y = (-vec.y + py);
+ if (cmp == 0)
+ {
+ *last_x1 = (int) floor(vec1.x + x + 0.5);
+ *last_y1 = (int) floor(vec1.y + y + 0.5);
+ *last_x2 = (int) floor(vec2.x + x + 0.5);
+ *last_y2 = (int) floor(vec2.y + y + 0.5);
+ }
+
//add points to map
for (i = 0; i < slice_no; i++)
{
+ int mp0_x, mp0_y;
+ int mp1_x, mp1_y;
+ int mp2_x, mp2_y;
+ int mp3_x, mp3_y;
+ double next_dt = dt;
+
//v0, v3
vec0.x = vec1.x;
vec0.y = vec1.y;
vec3.x = vec2.x;
vec3.y = vec2.y;
+ //UV
+ u0 = w1 + i * dist;
+ u1 = u0 + dist;
+ if (u1 > w)
+ u1 = w;
+ v0 = (double) 0;
+ v1 = (double) h;
+
+ /* If u1 is modified not to exceed its end,
+ * modify next_dt according to changes of dist. */
+ if (u1 < u0 + dist)
+ next_dt = dt * (u1 - u0) / dist;
+
//v1, v2
- t = ((double) (i + 1) * dt);
+ t = (double) (i * dt) + next_dt;
eina_bezier_point_at(&bezier, t, &px, &py);
- eina_bezier_point_at(&bezier, t + dt, &px2, &py2);
+ eina_bezier_point_at(&bezier, t + next_dt, &px2, &py2);
vec.x = (px2 - px);
vec.y = (py2 - py);
vec2.x = (-vec.x + px);
vec2.y = (-vec.y + py);
- evas_map_point_coord_set(map, cmp + i * 4, (int) vec0.x + x, (int) vec0.y + y, 0);
- evas_map_point_coord_set(map, cmp + i * 4 + 1, (int) vec1.x + x, (int) vec1.y + y, 0);
- evas_map_point_coord_set(map, cmp + i * 4 + 2, (int) vec2.x + x, (int) vec2.y + y, 0);
- evas_map_point_coord_set(map, cmp + i * 4 + 3, (int) vec3.x + x, (int) vec3.y + y, 0);
-
- //UV
- u0 = w1 + i * dist;
- u1 = u0 + dist;
- v0 = (double) 0;
- v1 = (double) h;
+ /* Set mp1, mp2 position according to difference between previous points and next points.
+ * It improves smoothness of curve's slope changing. */
+ mp0_x = *last_x1;
+ mp0_y = *last_y1;
+ mp1_x = *last_x1 + (int) floor(vec1.x - vec0.x + 0.5);
+ mp1_y = *last_y1 + (int) floor(vec1.y - vec0.y + 0.5);
+ mp2_x = *last_x2 + (int) floor(vec2.x - vec3.x + 0.5);
+ mp2_y = *last_y2 + (int) floor(vec2.y - vec3.y + 0.5);
+ mp3_x = *last_x2;
+ mp3_y = *last_y2;
+
+ evas_map_point_coord_set(map, cmp + i * 4, mp0_x, mp0_y, 0);
+ evas_map_point_coord_set(map, cmp + i * 4 + 1, mp1_x, mp1_y, 0);
+ evas_map_point_coord_set(map, cmp + i * 4 + 2, mp2_x, mp2_y, 0);
+ evas_map_point_coord_set(map, cmp + i * 4 + 3, mp3_x, mp3_y, 0);
evas_map_point_image_uv_set(map, cmp + i * 4, u0, v0);
evas_map_point_image_uv_set(map, cmp + i * 4 + 1, u1, v0);
evas_map_point_image_uv_set(map, cmp + i * 4 + 2, u1, v1);
evas_map_point_image_uv_set(map, cmp + i * 4 + 3, u0, v1);
+
+ *last_x1 = mp1_x;
+ *last_y1 = mp1_y;
+ *last_x2 = mp2_x;
+ *last_y2 = mp2_y;
+
+#ifdef EFL_UI_TEXTPATH_LINE_DEBUG
+ Evas_Object *line = evas_object_line_add(evas_object_evas_get(pd->text_obj));
+ pd->lines = eina_list_append(pd->lines, line);
+ if (yello_color_flag)
+ evas_object_color_set(line, 255, 255, 0, 255);
+ else
+ evas_object_color_set(line, 255, 0, 0, 255);
+ evas_object_line_xy_set(line,
+ mp0_x, mp0_y,
+ mp1_x, mp1_y);
+ evas_object_show(line);
+
+ line = evas_object_line_add(evas_object_evas_get(pd->text_obj));
+ pd->lines = eina_list_append(pd->lines, line);
+ if (yello_color_flag)
+ evas_object_color_set(line, 255, 255, 0, 255);
+ else
+ evas_object_color_set(line, 255, 0, 0, 255);
+ evas_object_line_xy_set(line,
+ mp1_x, mp1_y,
+ mp2_x, mp2_y);
+ evas_object_show(line);
+
+ line = evas_object_line_add(evas_object_evas_get(pd->text_obj));
+ pd->lines = eina_list_append(pd->lines, line);
+ if (yello_color_flag)
+ evas_object_color_set(line, 255, 255, 0, 255);
+ else
+ evas_object_color_set(line, 255, 0, 0, 255);
+ evas_object_line_xy_set(line,
+ mp2_x, mp2_y,
+ mp3_x, mp3_y);
+ evas_object_show(line);
+
+ line = evas_object_line_add(evas_object_evas_get(pd->text_obj));
+ pd->lines = eina_list_append(pd->lines, line);
+ if (yello_color_flag)
+ evas_object_color_set(line, 255, 255, 0, 255);
+ else
+ evas_object_color_set(line, 255, 0, 0, 255);
+ evas_object_line_xy_set(line,
+ mp3_x, mp3_y,
+ mp0_x, mp0_y);
+ evas_object_show(line);
+#endif
+
+ if (u1 >= w) break;
}
}
}
else if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO)
{
- int no = pd->slice_no * seg->length / (double)pd->total_length;
+ int no = (int)ceil(pd->slice_no * seg->length / (double)pd->total_length);
+ if (no == 0) no = 1;
map_no += no;
}
}
{
Efl_Ui_Textpath_Segment *seg;
Evas_Map *map;
- double slice_unit, slice_len;
int w, h, w1, w2;
int remained_w;
- int total_slice, drawn_slice = 0;
int cur_map_point = 0, map_point_no;
+ int last_x1, last_y1, last_x2, last_y2;
+
+ last_x1 = last_y1 = last_x2 = last_y2 = 0;
evas_object_geometry_get(pd->text_obj, NULL, NULL, &w, &h);
if (pd->autofit)
remained_w = w;
else
remained_w = pd->total_length;
- slice_unit = (double)pd->slice_no / pd->total_length;
-
- slice_len = 1.0 / slice_unit;
- total_slice = w / slice_len + 1;
map_point_no = _map_point_calc(pd);
if (map_point_no == 0)
{
- ERR("no map point");
evas_object_map_enable_set(pd->text_obj, EINA_FALSE);
return;
}
evas_map_util_object_move_sync_set(map, EINA_TRUE);
/* END */
+#ifdef EFL_UI_TEXTPATH_LINE_DEBUG
+ Evas_Object *line;
+ EINA_LIST_FREE(pd->lines, line)
+ evas_object_del(line);
+#endif
+
w1 = w2 = 0;
EINA_INLIST_FOREACH(pd->segments, seg)
{
w2 = w;
if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
{
- drawn_slice += 1;
_text_on_line_draw(pd, w1, w2, cur_map_point, map, seg->line);
cur_map_point += 4;
}
else
{
+ double slice_value, dt, dist;
int slice_no;
- slice_no = pd->slice_no * seg->length / (double)pd->total_length;
- if (slice_no == 0)
- slice_no = len * slice_unit + 1;
- if (remained_w == 0)
- slice_no = total_slice - drawn_slice;
- drawn_slice += slice_no;
- _segment_draw(pd, slice_no, w1, w2, cur_map_point, map, seg->bezier);
+
+ slice_value = pd->slice_no * seg->length / (double)pd->total_length;
+ dt = (double)pd->total_length / (pd->slice_no * seg->length);
+
+ if (pd->autofit)
+ dist = (double)pd->total_length / (double)pd->slice_no;
+ else
+ dist = (double)pd->total_length * (w2 - w1) / ((double)pd->slice_no * seg->length);
+
+ slice_no = (int)ceil(slice_value);
+ dt = (double)slice_value * dt / (double)slice_no;
+ dist = (double)slice_value * dist / (double)slice_no;
+
+ _segment_draw(pd, slice_no, dt, dist,
+ w1, cur_map_point, map, seg->bezier,
+ &last_x1, &last_y1, &last_x2, &last_y2);
cur_map_point += slice_no * 4;
}
w1 = w2;
- remained_w -= len;
+ remained_w -= seg->length;
}
evas_object_map_enable_set(pd->text_obj, EINA_TRUE);
evas_object_map_set(pd->text_obj, map);
free(seg);
}
+#ifdef EFL_UI_TEXTPATH_LINE_DEBUG
+ Evas_Object *line;
+ EINA_LIST_FREE(pd->lines, line)
+ evas_object_del(line);
+#endif
+
//efl_destructor(efl_super(obj, MY_CLASS));
eo_do_super(obj, MY_CLASS, eo_destructor());
}