Revert "Evas GL Bug Fix: Fixed int variables that were assumed to be 0 instead"
[framework/uifw/evas.git] / src / lib / canvas / evas_object_textgrid.c
1 #include "evas_common.h" /* Includes evas_bidi_utils stuff. */
2 #include "evas_private.h"
3
4 /* save typing */
5 #define ENFN obj->layer->evas->engine.func
6 #define ENDT obj->layer->evas->engine.data.output
7
8 /* private magic number for text objects */
9 static const char o_type[] = "textgrid";
10
11 /* private struct for line object internal data */
12 typedef struct _Evas_Object_Textgrid       Evas_Object_Textgrid;
13 typedef struct _Evas_Object_Textgrid_Cell  Evas_Object_Textgrid_Cell;
14 typedef struct _Evas_Object_Textgrid_Color Evas_Object_Textgrid_Color;
15
16 typedef struct _Evas_Object_Textgrid_Row   Evas_Object_Textgrid_Row;
17 typedef struct _Evas_Object_Textgrid_Rect  Evas_Object_Textgrid_Rect;
18 typedef struct _Evas_Object_Textgrid_Text  Evas_Object_Textgrid_Text;
19 typedef struct _Evas_Object_Textgrid_Line  Evas_Object_Textgrid_Line;
20
21 struct _Evas_Object_Textgrid
22 {
23    DATA32                         magic;
24
25    struct {
26       int                         w, h;
27       int                         char_width;
28       int                         char_height;
29       Evas_Object_Textgrid_Row   *rows;
30       Evas_Textgrid_Cell         *cells;
31
32       const char                 *font_source;
33       const char                 *font_name;
34       Evas_Font_Size              font_size;
35       Evas_Font_Description      *font_description;
36
37       Eina_Array                 *palette_standard;
38       Eina_Array                 *palette_extended;
39    } cur, prev;
40
41    int                            max_ascent;
42
43    Evas_Font_Set                 *font;
44
45    unsigned int                   changed : 1;
46    unsigned int                   core_change : 1;
47    unsigned int                   row_change : 1;
48    unsigned int                   pal_change : 1;
49 };
50
51 struct _Evas_Object_Textgrid_Color
52 {
53    unsigned char r, g, b, a;
54 };
55
56 struct _Evas_Object_Textgrid_Row
57 {
58    int ch1, ch2; // change region, -1 == none
59    int rects_num, texts_num, lines_num;
60    int rects_alloc, texts_alloc, lines_alloc;
61    Evas_Object_Textgrid_Rect *rects; // rects + colors
62    Evas_Object_Textgrid_Text *texts; // text
63    Evas_Object_Textgrid_Line *lines; // underlines, strikethroughs
64 };
65
66 struct _Evas_Object_Textgrid_Rect
67 {
68    unsigned char r, g, b, a;
69    int x, w;
70 };
71
72 struct _Evas_Object_Textgrid_Text
73 {
74    unsigned char r, g, b, a;
75    int x;
76    Evas_Text_Props text_props;
77 };
78
79 struct _Evas_Object_Textgrid_Line
80 {
81    unsigned char r, g, b, a;
82    int x, w, y;
83 };
84
85 /* private methods for textgrid objects */
86 static void evas_object_textgrid_init(Evas_Object *obj);
87 static void *evas_object_textgrid_new(void);
88 static void evas_object_textgrid_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
89 static void evas_object_textgrid_free(Evas_Object *obj);
90 static void evas_object_textgrid_render_pre(Evas_Object *obj);
91 static void evas_object_textgrid_render_post(Evas_Object *obj);
92
93 static unsigned int evas_object_textgrid_id_get(Evas_Object *obj);
94 static unsigned int evas_object_textgrid_visual_id_get(Evas_Object *obj);
95 static void *evas_object_textgrid_engine_data_get(Evas_Object *obj);
96
97 static int evas_object_textgrid_is_opaque(Evas_Object *obj);
98 static int evas_object_textgrid_was_opaque(Evas_Object *obj);
99
100 static void evas_object_textgrid_scale_update(Evas_Object *obj);
101
102 static const Evas_Object_Func object_func =
103 {
104    /* methods (compulsory) */
105    evas_object_textgrid_free,
106    evas_object_textgrid_render,
107    evas_object_textgrid_render_pre,
108    evas_object_textgrid_render_post,
109    evas_object_textgrid_id_get,
110    evas_object_textgrid_visual_id_get,
111    evas_object_textgrid_engine_data_get,
112    /* these are optional. NULL = nothing */
113    NULL,
114    NULL,
115    NULL,
116    NULL,
117    evas_object_textgrid_is_opaque,
118    evas_object_textgrid_was_opaque,
119    NULL,
120    NULL,
121    NULL,
122    evas_object_textgrid_scale_update,
123    NULL,
124    NULL,
125    NULL
126 };
127
128 EVAS_MEMPOOL(_mp_obj);
129
130 /* all nice and private */
131 static void
132 evas_object_textgrid_init(Evas_Object *obj)
133 {
134    /* alloc textgrid ob, setup methods and default values */
135    obj->object_data = evas_object_textgrid_new();
136    /* set up default settings for this kind of object */
137    obj->cur.color.r = 255;
138    obj->cur.color.g = 255;
139    obj->cur.color.b = 255;
140    obj->cur.color.a = 255;
141    obj->cur.geometry.x = 0;
142    obj->cur.geometry.y = 0;
143    obj->cur.geometry.w = 0;
144    obj->cur.geometry.h = 0;
145    obj->cur.layer = 0;
146    /* set up object-specific settings */
147    obj->prev = obj->cur;
148    /* set up methods (compulsory) */
149    obj->func = &object_func;
150    obj->type = o_type;
151 }
152
153 static void *
154 evas_object_textgrid_new(void)
155 {
156    Evas_Object_Textgrid *o;
157
158    /* FIXME: using evas mempool like text ? */
159    EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_textgrid", Evas_Object_Textgrid, 4, NULL);
160    o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Textgrid);
161    EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Textgrid);
162    o->magic = MAGIC_OBJ_TEXTGRID;
163    o->prev = o->cur;
164    o->cur.palette_standard = eina_array_new(16);
165    o->cur.palette_extended = eina_array_new(16);
166    return o;
167 }
168
169 static void
170 evas_object_textgrid_row_clear(Evas_Object_Textgrid_Row *r)
171 {
172    int i;
173    
174    if (r->rects)
175      {
176         free(r->rects);
177         r->rects = NULL;
178         r->rects_num = 0;
179         r->rects_alloc = 0;
180      }
181    if (r->texts)
182      {
183         for (i = 0; i < r->texts_num; i++)
184           evas_common_text_props_content_unref(&(r->texts[i].text_props));
185         free(r->texts);
186         r->texts = NULL;
187         r->texts_num = 0;
188         r->texts_alloc = 0;
189      }
190    if (r->lines)
191      {
192         free(r->lines);
193         r->lines = NULL;
194         r->lines_num = 0;
195         r->lines_alloc = 0;
196      }
197 }
198
199 static void
200 evas_object_textgrid_rows_clear(Evas_Object *obj)
201 {
202    Evas_Object_Textgrid *o;
203    int i;
204
205    o = (Evas_Object_Textgrid *)(obj->object_data);
206    if (!o->cur.rows) return;
207    for (i = 0; i < o->cur.h; i++)
208      {
209         evas_object_textgrid_row_clear(&(o->cur.rows[i]));
210         o->cur.rows[i].ch1 = 0;
211         o->cur.rows[i].ch2 = o->cur.w - 1;
212      }
213 }
214
215 static void
216 evas_object_textgrid_free(Evas_Object *obj)
217 {
218    Evas_Object_Textgrid *o;
219    unsigned int i;
220
221    /* frees private object data. very simple here */
222    o = (Evas_Object_Textgrid *)(obj->object_data);
223    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
224    return;
225    MAGIC_CHECK_END();
226
227    /* free obj */
228    evas_object_textgrid_rows_clear(obj);
229    if (o->cur.rows) free(o->cur.rows);
230    if (o->cur.font_name) eina_stringshare_del(o->cur.font_name);
231    if (o->cur.font_source) eina_stringshare_del(o->cur.font_source);
232    if (o->cur.font_description) evas_font_desc_unref(o->cur.font_description);
233    if (o->font) evas_font_free(obj->layer->evas, o->font);
234    if (o->cur.cells) free(o->cur.cells);
235    for (i = 0; i < eina_array_count(o->cur.palette_standard); i++)
236      free(eina_array_data_get(o->cur.palette_standard, i));
237    eina_array_free(o->cur.palette_standard);
238    for (i = 0; i < eina_array_count(o->cur.palette_extended); i++)
239      free(eina_array_data_get(o->cur.palette_extended, i));
240    eina_array_free(o->cur.palette_extended);
241    o->magic = 0;
242    /* FIXME: using evas mempool like text ? */
243    EVAS_MEMPOOL_FREE(_mp_obj, o);
244 }
245
246
247 static void
248 evas_object_textgrid_row_rect_append(Evas_Object_Textgrid_Row *row, int x, int w, int r, int g, int b, int a)
249 {
250    row->rects_num++;
251    if (row->rects_num > row->rects_alloc)
252      {
253         Evas_Object_Textgrid_Rect *t;
254         
255         row->rects_alloc += 8; // dont expect many rects per line
256         t = realloc(row->rects, sizeof(Evas_Object_Textgrid_Rect) * row->rects_alloc);
257         if (!t)
258           {
259              row->rects_num--;
260              return;
261           }
262         row->rects = t;
263      }
264    row->rects[row->rects_num - 1].x = x;
265    row->rects[row->rects_num - 1].w = w;
266    row->rects[row->rects_num - 1].r = r;
267    row->rects[row->rects_num - 1].g = g;
268    row->rects[row->rects_num - 1].b = b;
269    row->rects[row->rects_num - 1].a = a;
270 }
271
272 static void
273 evas_object_textgrid_row_text_append(Evas_Object_Textgrid_Row *row, Evas_Object *obj, Evas_Object_Textgrid *o, int x, Eina_Unicode codepoint, int r, int g, int b, int a)
274 {
275    Evas_Script_Type script;
276    Evas_Font_Instance *script_fi = NULL;
277    Evas_Font_Instance *cur_fi = NULL;
278    
279    row->texts_num++;
280    if (row->texts_num > row->texts_alloc)
281      {
282         Evas_Object_Textgrid_Text *t;
283         
284         row->texts_alloc += 32; // expect more text per line
285         t = realloc(row->texts, sizeof(Evas_Object_Textgrid_Text) * row->texts_alloc);
286         if (!t)
287           {
288              row->texts_num--;
289              return;
290           }
291         row->texts = t;
292      }
293    
294    script = evas_common_language_script_type_get(&codepoint, 1);
295    ENFN->font_run_end_get(ENDT, o->font, &script_fi, &cur_fi,
296                           script, &codepoint, 1);
297    memset(&(row->texts[row->texts_num - 1].text_props), 0,
298           sizeof(Evas_Text_Props));
299    evas_common_text_props_script_set
300      (&(row->texts[row->texts_num - 1].text_props), script);
301    ENFN->font_text_props_info_create
302      (ENDT, script_fi, &codepoint,
303          &(row->texts[row->texts_num - 1].text_props), NULL, 0, 1,
304          EVAS_TEXT_PROPS_MODE_NONE);
305    row->texts[row->texts_num - 1].x = x;
306    row->texts[row->texts_num - 1].r = r;
307    row->texts[row->texts_num - 1].g = g;
308    row->texts[row->texts_num - 1].b = b;
309    row->texts[row->texts_num - 1].a = a;
310 }
311
312 static void
313 evas_object_textgrid_row_line_append(Evas_Object_Textgrid_Row *row, int x, int w, int y, int r, int g, int b, int a)
314 {
315    row->lines_num++;
316    if (row->lines_num > row->lines_alloc)
317      {
318         Evas_Object_Textgrid_Line *t;
319         
320         row->lines_alloc += 8; // dont expect many lines per line
321         t = realloc(row->lines, sizeof(Evas_Object_Textgrid_Line) * row->lines_alloc);
322         if (!t)
323           {
324              row->lines_num--;
325              return;
326           }
327         row->lines = t;
328      }
329    row->lines[row->lines_num - 1].x = x;
330    row->lines[row->lines_num - 1].w = w;
331    row->lines[row->lines_num - 1].y = y;
332    row->lines[row->lines_num - 1].r = r;
333    row->lines[row->lines_num - 1].g = g;
334    row->lines[row->lines_num - 1].b = b;
335    row->lines[row->lines_num - 1].a = a;
336 }
337
338 static void
339 evas_object_textgrid_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
340 {
341    Evas_Object_Textgrid *o;
342    Evas_Textgrid_Cell *cells;
343    Evas_Object_Textgrid_Color *c;
344    Eina_Array *palette;
345    int xx, yy, xp, yp, w, h, ww, hh;
346    int rr = 0, rg = 0, rb = 0, ra = 0, rx = 0, rw = 0, run;
347
348    /* render object to surface with context, and offxet by x,y */
349    o = (Evas_Object_Textgrid *)(obj->object_data);
350    ENFN->context_multiplier_unset(output, context);
351    ENFN->context_render_op_set(output, context, obj->cur.render_op);
352
353    if (!(o->font) || (!o->cur.cells)) return;
354    
355    w = o->cur.char_width;
356    h = o->cur.char_height;
357    ww = obj->cur.geometry.w;
358    hh = obj->cur.geometry.h;
359
360    // generate row data from cells (and only deal with rows that updated)
361    for (yy = 0, cells = o->cur.cells; yy < o->cur.h; yy++)
362      {
363         Evas_Object_Textgrid_Row *row = &(o->cur.rows[yy]);
364         
365         if (row->ch1 < 0)
366           {
367              cells += o->cur.w;
368              continue;
369           }
370         row->ch1 = -1;
371         row->ch2 = 0;
372         run = 0;
373         xp = obj->cur.geometry.x;
374         for (xx = 0; xx < o->cur.w; xx++, cells++)
375           {
376              if (cells->bg_extended) palette = o->cur.palette_extended;
377              else palette = o->cur.palette_standard;
378              c = eina_array_data_get(palette, cells->bg);
379              if ((c) && (c->a > 0))
380                {
381                   if (!run)
382                     {
383                        run = 1;
384                        rr = c->r;
385                        rg = c->g;
386                        rb = c->b;
387                        ra = c->a;
388                        rx = xp;
389                        rw = w;
390                     }
391                   else if ((c->r != rr) || (c->g != rg) ||
392                            (c->b != rb) || (c->a != ra))
393                     {
394                        evas_object_textgrid_row_rect_append(row, rx, rw,
395                                                             rr, rg, rb, ra);
396                        rr = c->r;
397                        rg = c->g;
398                        rb = c->b;
399                        ra = c->a;
400                        rx = xp;
401                        rw = w;
402                     }
403                   else rw += w;
404                }
405              else if (run)
406                {
407                   run = 0;
408                   evas_object_textgrid_row_rect_append(row, rx, rw,
409                                                        rr, rg, rb, ra);
410                }
411              if (cells->codepoint > 0)
412                {
413                   if (cells->fg_extended) palette = o->cur.palette_extended;
414                   else palette = o->cur.palette_standard;
415                   c = eina_array_data_get(palette, cells->fg);
416                   if ((c) && (c->a > 0))
417                     {
418                        evas_object_textgrid_row_text_append(row, obj, o, xp,
419                                                             cells->codepoint,
420                                                             c->r, c->g, c->b, c->a);
421                        // XXX: underlines and strikethroughs dont get
422                        // merghed into horizontal runs like bg rects above
423                        if (cells->underline)
424                          evas_object_textgrid_row_line_append(row, rx, rw,
425                                                               o->max_ascent + 1,
426                                                               rr, rg, rb, ra);
427                        if (cells->strikethrough)
428                          evas_object_textgrid_row_line_append(row, rx, rw,
429                                                               ((3 * o->max_ascent) / 4),
430                                                               rr, rg, rb, ra);
431                     }
432                }
433              xp += w;
434           }
435         if (run)
436           {
437              run = 0;
438              evas_object_textgrid_row_rect_append(row, rx, rw,
439                                                   rr, rg, rb, ra);
440           }
441      }
442    yp = obj->cur.geometry.y + y;
443    // draw the row data that is generated from the cell array
444    for (yy = 0, cells = o->cur.cells; yy < o->cur.h; yy++)
445      {
446         Evas_Object_Textgrid_Row *row = &(o->cur.rows[yy]);
447
448         xp = obj->cur.geometry.x + x;
449         for (xx = 0; xx < row->rects_num; xx++)
450           {
451              ENFN->context_color_set(output, context,
452                                      row->rects[xx].r, row->rects[xx].g,
453                                      row->rects[xx].b, row->rects[xx].a); 
454              ENFN->rectangle_draw(output, context, surface,
455                                   xp + row->rects[xx].x, yp,
456                                   row->rects[xx].w, h);
457           }
458         for (xx = 0; xx < row->texts_num; xx++)
459           {
460              ENFN->context_color_set(output, context,
461                                      row->texts[xx].r, row->texts[xx].g,
462                                      row->texts[xx].b, row->texts[xx].a); 
463              ENFN->font_draw(output, context, surface, o->font,
464                              xp + row->texts[xx].x, yp + o->max_ascent,
465                              ww, hh, ww, hh, &(row->texts[xx].text_props));
466           }
467         for (xx = 0; xx < row->lines_num; xx++)
468           {
469              ENFN->context_color_set(output, context,
470                                      row->lines[xx].r, row->lines[xx].g,
471                                      row->lines[xx].b, row->lines[xx].a); 
472              ENFN->rectangle_draw(output, context, surface,
473                                   xp + row->lines[xx].x, yp + row->lines[xx].y,
474                                   row->lines[xx].w, h);
475           }
476         yp += h;
477      }
478 }
479
480 static void
481 evas_object_textgrid_render_pre(Evas_Object *obj)
482 {
483    Evas_Object_Textgrid *o;
484    int is_v, was_v;
485
486    /* dont pre-render the obj twice! */
487    if (obj->pre_render_done) return;
488    obj->pre_render_done = 1;
489    /* pre-render phase. this does anything an object needs to do just before */
490    /* rendering. this could mean loading the image data, retrieving it from */
491    /* elsewhere, decoding video etc. */
492    /* then when this is done the object needs to figure if it changed and */
493    /* if so what and where and add thr appropriate redraw rectangles */
494    o = (Evas_Object_Textgrid *)(obj->object_data);
495    /* if someone is clipping this obj - go calculate the clipper */
496    if (obj->cur.clipper)
497      {
498         if (obj->cur.cache.clip.dirty)
499           evas_object_clip_recalc(obj->cur.clipper);
500         obj->cur.clipper->func->render_pre(obj->cur.clipper);
501      }
502    /* now figure what changed and add draw rects */
503    /* if it just became visible or invisible */
504    is_v = evas_object_is_visible(obj);
505    was_v = evas_object_was_visible(obj);
506    if (is_v != was_v)
507      {
508         evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
509         goto done;
510      }
511    if (obj->changed_map)
512      {
513         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
514                                             obj);
515         goto done;
516      }
517    /* its not visible - we accounted for it appearing or not so just abort */
518    if (!is_v) goto done;
519    /* clipper changed this is in addition to anything else for obj */
520    evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
521    /* if we restacked (layer or just within a layer) and dont clip anyone */
522    if (obj->restack)
523      {
524         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
525         goto done;
526      }
527    /* if it changed color */
528    if ((obj->cur.color.r != obj->prev.color.r) ||
529        (obj->cur.color.g != obj->prev.color.g) ||
530        (obj->cur.color.b != obj->prev.color.b) ||
531        (obj->cur.color.a != obj->prev.color.a))
532      {
533         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
534         goto done;
535      }
536    /* if it changed geometry - and obviously not visibility or color */
537    /* calculate differences since we have a constant color fill */
538    /* we really only need to update the differences */
539    if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
540        (obj->cur.geometry.y != obj->prev.geometry.y) ||
541        (obj->cur.geometry.w != obj->prev.geometry.w) ||
542        (obj->cur.geometry.h != obj->prev.geometry.h))
543      {
544         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
545         goto done;
546      }
547    if (obj->cur.render_op != obj->prev.render_op)
548      {
549         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
550         goto done;
551      }
552    if (obj->cur.scale != obj->prev.scale)
553      {
554         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
555         goto done;
556      }
557
558    if (o->changed)
559      {
560         if (o->core_change)
561           {
562              if ((o->cur.h != o->prev.h) ||
563                  (o->cur.w != o->prev.w) ||
564                  (o->cur.font_size != o->prev.font_size) ||
565                  ((o->cur.font_name) && (o->prev.font_name) &&
566                      (strcmp(o->cur.font_name, o->prev.font_name))) ||
567                  ((o->cur.font_name) && (!o->prev.font_name)) ||
568                  ((!o->cur.font_name) && (o->prev.font_name)))
569                {
570                   evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
571                                                       obj);
572                   goto done;
573                }
574           }
575         if (o->pal_change)
576           {
577              unsigned int i;
578              
579              if (eina_array_count(o->cur.palette_standard) != eina_array_count(o->prev.palette_standard))
580                {
581                   evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
582                   goto done;
583                }
584              for (i = 0; i < eina_array_count(o->cur.palette_standard); i++)
585                {
586                   Evas_Object_Textgrid_Color *c_cur;
587                   Evas_Object_Textgrid_Color *c_prev;
588                   
589                   c_cur = eina_array_data_get(o->cur.palette_standard, i);
590                   c_prev = eina_array_data_get(o->prev.palette_standard, i);
591                   if ((c_cur->a != c_prev->a) ||
592                       (c_cur->r != c_prev->r) ||
593                       (c_cur->g != c_prev->g) ||
594                       (c_cur->b != c_prev->b))
595                     {
596                        evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
597                        goto done;
598                     }
599                }
600              if (eina_array_count(o->cur.palette_extended) != eina_array_count(o->prev.palette_extended))
601                {
602                   evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
603                   goto done;
604                }
605              for (i = 0; i < eina_array_count(o->cur.palette_extended); i++)
606                {
607                   Evas_Object_Textgrid_Color *c_cur;
608                   Evas_Object_Textgrid_Color *c_prev;
609                   
610                   c_cur = eina_array_data_get(o->cur.palette_extended, i);
611                   c_prev = eina_array_data_get(o->prev.palette_extended, i);
612                   if ((c_cur->a != c_prev->a) ||
613                       (c_cur->r != c_prev->r) ||
614                       (c_cur->g != c_prev->g) ||
615                       (c_cur->b != c_prev->b))
616                     {
617                        evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
618                        goto done;
619                     }
620                }
621           }
622         if (o->row_change)
623           {
624              int i;
625              
626              for (i = 0; i < o->cur.h; i++)
627                {
628                   Evas_Object_Textgrid_Row *r = &(o->cur.rows[i]);
629                   if (r->ch1 >= 0)
630                     evas_add_rect(&obj->layer->evas->clip_changes,
631                                   obj->cur.geometry.x + 
632                                   (r->ch1 * o->cur.char_width),
633                                   obj->cur.geometry.y + 
634                                   (i * o->cur.char_height),
635                                   (r->ch2 - r->ch1 + 1) * o->cur.char_width,
636                                   o->cur.char_height);
637                }
638           }
639      }
640    
641    done:
642    o->core_change = 0;
643    o->row_change = 0;
644    o->pal_change = 0;
645    evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
646 }
647
648 static void
649 evas_object_textgrid_render_post(Evas_Object *obj)
650 {
651    Evas_Object_Textgrid *o;
652
653    /* this moves the current data to the previous state parts of the object */
654    /* in whatever way is safest for the object. also if we don't need object */
655    /* data anymore we can free it if the object deems this is a good idea */
656    o = (Evas_Object_Textgrid *)(obj->object_data);
657    /* remove those pesky changes */
658    evas_object_clip_changes_clean(obj);
659    /* move cur to prev safely for object data */
660    obj->prev = obj->cur;
661    o->prev = o->cur;
662    o->changed = 0;
663 }
664
665 static unsigned int
666 evas_object_textgrid_id_get(Evas_Object *obj)
667 {
668    Evas_Object_Textgrid *o;
669
670    o = (Evas_Object_Textgrid *)(obj->object_data);
671    if (!o) return 0;
672    return MAGIC_OBJ_TEXTGRID;
673 }
674
675 static unsigned int
676 evas_object_textgrid_visual_id_get(Evas_Object *obj)
677 {
678    Evas_Object_Textgrid *o;
679
680    o = (Evas_Object_Textgrid *)(obj->object_data);
681    if (!o) return 0;
682    return MAGIC_OBJ_SHAPE;
683 }
684
685 static void *
686 evas_object_textgrid_engine_data_get(Evas_Object *obj)
687 {
688    Evas_Object_Textgrid *o;
689
690    o = (Evas_Object_Textgrid *)(obj->object_data);
691    if (!o) return NULL;
692    return o->font;
693 }
694
695 static int
696 evas_object_textgrid_is_opaque(Evas_Object *obj __UNUSED__)
697 {
698    /* this returns 1 if the internal object data implies that the object is
699     currently fully opaque over the entire gradient it occupies */
700    return 0;
701 }
702
703 static int
704 evas_object_textgrid_was_opaque(Evas_Object *obj __UNUSED__)
705 {
706    /* this returns 1 if the internal object data implies that the object was
707     currently fully opaque over the entire gradient it occupies */
708    return 0;
709 }
710
711 static void
712 evas_object_textgrid_scale_update(Evas_Object *obj)
713 {
714    Evas_Object_Textgrid *o;
715    int font_size;
716    const char *font_name;
717
718    o = (Evas_Object_Textgrid *)(obj->object_data);
719    font_name = eina_stringshare_add(o->cur.font_name);
720    font_size = o->cur.font_size;
721    if (o->cur.font_name) eina_stringshare_del(o->cur.font_name);
722    o->cur.font_name = NULL;
723    o->prev.font_name = NULL;
724    o->cur.font_size = 0;
725    o->prev.font_size = 0;
726    evas_object_textgrid_font_set(obj, font_name, font_size);
727 }
728
729 /*********************  LOCAL *********************/
730
731 /*********************  API *********************/
732
733 EAPI Evas_Object *
734 evas_object_textgrid_add(Evas *e)
735 {
736    Evas_Object *obj;
737
738    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
739    return NULL;
740    MAGIC_CHECK_END();
741
742    obj = evas_object_new(e);
743    evas_object_textgrid_init(obj);
744    evas_object_inject(obj, e);
745    return obj;
746 }
747
748 EAPI void
749 evas_object_textgrid_size_set(Evas_Object *obj, int w, int h)
750 {
751    Evas_Object_Textgrid *o;
752    int i;
753
754    if ((h <= 0) || (w <= 0)) return;
755
756    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
757    return;
758    MAGIC_CHECK_END();
759    o = (Evas_Object_Textgrid *)(obj->object_data);
760    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
761    return;
762    MAGIC_CHECK_END();
763
764    if ((o->cur.w == w) && (o->cur.h == h)) return;
765
766    evas_object_textgrid_rows_clear(obj);
767    if (o->cur.rows)
768      {
769         free(o->cur.rows);
770         o->cur.rows = NULL;
771      }
772    if (o->cur.cells)
773      {
774         free(o->cur.cells);
775         o->cur.cells = NULL;
776      }
777    o->cur.cells = calloc(w * h, sizeof(Evas_Textgrid_Cell));
778    if (!o->cur.cells) return;
779    o->cur.rows = calloc(h, sizeof(Evas_Object_Textgrid_Row));
780    if (!o->cur.rows)
781      {
782         free(o->cur.cells);
783         o->cur.cells = NULL;
784         return;
785      }
786    for (i = 0; i < h; i++)
787      {
788         o->cur.rows[i].ch1 = 0;
789         o->cur.rows[i].ch2 = w - 1;
790      }
791    o->cur.w = w;
792    o->cur.h = h;
793    o->changed = 1;
794    o->core_change = 1;
795    evas_object_change(obj);
796 }
797
798 EAPI void
799 evas_object_textgrid_size_get(const Evas_Object *obj, int *w, int *h)
800 {
801    Evas_Object_Textgrid *o;
802
803    if (h) *h = 0;
804    if (w) *w = 0;
805
806    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
807    return;
808    MAGIC_CHECK_END();
809    o = (Evas_Object_Textgrid *)(obj->object_data);
810    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
811    return;
812    MAGIC_CHECK_END();
813
814    if (w) *w = o->cur.w;
815    if (h) *h = o->cur.h;
816 }
817
818 EAPI void
819 evas_object_textgrid_font_source_set(Evas_Object *obj, const char *font_source)
820 {
821    Evas_Object_Textgrid *o;
822
823    if ((!font_source) || (!*font_source))
824      return;
825
826    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
827    return;
828    MAGIC_CHECK_END();
829    o = (Evas_Object_Textgrid *)(obj->object_data);
830    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
831    return;
832    MAGIC_CHECK_END();
833    
834    if ((o->cur.font_source) && (font_source) &&
835        (!strcmp(o->cur.font_source, font_source))) return;
836
837    eina_stringshare_replace(&o->cur.font_source, font_source);
838    o->changed = 1;
839    o->core_change = 1;
840    evas_object_change(obj);
841 }
842
843 EAPI const char *
844 evas_object_textgrid_font_source_get(const Evas_Object *obj)
845 {
846    Evas_Object_Textgrid *o;
847
848    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
849    return NULL;
850    MAGIC_CHECK_END();
851    o = (Evas_Object_Textgrid *)(obj->object_data);
852    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
853    return NULL;
854    MAGIC_CHECK_END();
855
856    return o->cur.font_source;
857 }
858
859 EAPI void
860 evas_object_textgrid_font_set(Evas_Object *obj, const char *font_name, Evas_Font_Size font_size)
861 {
862    Evas_Object_Textgrid *o;
863    int is, was = 0, pass = 0, freeze = 0;
864    Evas_Font_Description *font_description;
865    
866    if ((!font_name) || (!*font_name) || (font_size <= 0))
867      return;
868
869    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
870    return;
871    MAGIC_CHECK_END();
872    o = (Evas_Object_Textgrid *)(obj->object_data);
873    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
874    return;
875    MAGIC_CHECK_END();
876
877    font_description = evas_font_desc_new();
878    evas_font_name_parse(font_description, font_name);
879    if (o->cur.font_description &&
880        !evas_font_desc_cmp(font_description, o->cur.font_description) &&
881        (font_size == o->cur.font_size))
882      {
883         evas_font_desc_unref(font_description);
884         return;
885      }
886
887    if (o->cur.font_description) evas_font_desc_unref(o->cur.font_description);
888    o->cur.font_description = font_description;
889
890    o->cur.font_size = font_size;
891    eina_stringshare_replace(&o->cur.font_name, font_name);
892    o->prev.font_name = NULL;
893
894    if (obj->layer->evas->events_frozen <= 0)
895      {
896         pass = evas_event_passes_through(obj);
897         freeze = evas_event_freezes_through(obj);
898         if ((!pass) && (!freeze))
899           was = evas_object_is_in_output_rect(obj,
900                                               obj->layer->evas->pointer.x,
901                                               obj->layer->evas->pointer.y,
902                                               1, 1);
903      }
904    
905    /* DO IT */
906    if (o->font)
907      {
908         evas_font_free(obj->layer->evas, o->font);
909         o->font = NULL;
910      }
911    
912    o->font = evas_font_load(obj->layer->evas, o->cur.font_description,
913                             o->cur.font_source,
914                             (int)(((double) o->cur.font_size) * 
915                                   obj->cur.scale));
916    if (o->font)
917      {
918         Eina_Unicode W[2] = { 'W', 0 };
919         Evas_Font_Instance *script_fi = NULL;
920         Evas_Font_Instance *cur_fi = NULL;
921         Evas_Text_Props text_props;
922         Evas_Script_Type script;
923         
924         script = evas_common_language_script_type_get(W, 1);
925         ENFN->font_run_end_get(ENDT, o->font, &script_fi, &cur_fi,
926                                script, W, 1);
927         memset(&text_props, 0, sizeof(Evas_Text_Props));
928         evas_common_text_props_script_set(&text_props, script);
929         ENFN->font_text_props_info_create(ENDT, script_fi, W, &text_props,
930                                           NULL, 0, 1,
931                                           EVAS_TEXT_PROPS_MODE_NONE);
932         ENFN->font_string_size_get(ENDT, o->font, &text_props,
933                                    &o->cur.char_width, &o->cur.char_height);
934         o->max_ascent = ENFN->font_max_ascent_get(ENDT, o->font);
935         evas_common_text_props_content_unref(&text_props);
936      }
937    else
938      {
939         obj->cur.geometry.w = 0;
940         obj->cur.geometry.h = 0;
941         o->max_ascent = 0;
942      }
943
944    o->changed = 1;
945    evas_object_change(obj);
946    evas_object_clip_dirty(obj);
947    evas_object_coords_recalc(obj);
948    if (obj->layer->evas->events_frozen <= 0)
949      {
950         if ((!pass) && (!freeze))
951           {
952              is = evas_object_is_in_output_rect(obj,
953                                                 obj->layer->evas->pointer.x,
954                                                 obj->layer->evas->pointer.y,
955                                                 1, 1);
956              if ((is ^ was) && obj->cur.visible)
957                evas_event_feed_mouse_move(obj->layer->evas,
958                                           obj->layer->evas->pointer.x,
959                                           obj->layer->evas->pointer.y,
960                                           obj->layer->evas->last_timestamp,
961                                           NULL);
962           }
963      }
964    evas_object_inform_call_resize(obj);
965    o->changed = 1;
966    o->core_change = 1;
967    evas_object_textgrid_rows_clear(obj);
968    evas_object_change(obj);
969 }
970
971 EAPI void
972 evas_object_textgrid_font_get(const Evas_Object *obj, const char **font_name, Evas_Font_Size *font_size)
973 {
974    Evas_Object_Textgrid *o;
975    
976    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
977    if (font_name) *font_name = "";
978    if (font_size) *font_size = 0;
979    return;
980    MAGIC_CHECK_END();
981    o = (Evas_Object_Textgrid *)(obj->object_data);
982    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
983    if (font_name) *font_name = "";
984    if (font_size) *font_size = 0;
985    return;
986    MAGIC_CHECK_END();
987
988    if (font_name) *font_name = o->cur.font_name;
989    if (font_size) *font_size = o->cur.font_size;
990 }
991
992 EAPI void
993 evas_object_textgrid_cell_size_get(const Evas_Object *obj, int *width, int *height)
994 {
995    Evas_Object_Textgrid *o;
996
997    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
998    if (width) *width = 0;
999    if (height) *height = 0;
1000    return;
1001    MAGIC_CHECK_END();
1002    o = (Evas_Object_Textgrid *)(obj->object_data);
1003    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
1004    if (width) *width = 0;
1005    if (height) *height = 0;
1006    return;
1007    MAGIC_CHECK_END();
1008
1009    if (width) *width = o->cur.char_width;
1010    if (height) *height = o->cur.char_height;
1011 }
1012
1013 EAPI void
1014 evas_object_textgrid_palette_set(Evas_Object *obj, Evas_Textgrid_Palette pal, int idx, int r, int g, int b, int a)
1015 {
1016    Evas_Object_Textgrid *o;
1017    Eina_Array *palette;
1018    Evas_Object_Textgrid_Color *color, *c;
1019    int count, i;
1020
1021    if ((idx < 0) || (idx > 255)) return;
1022
1023    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1024    return;
1025    MAGIC_CHECK_END();
1026    o = (Evas_Object_Textgrid *)(obj->object_data);
1027    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
1028    return;
1029    MAGIC_CHECK_END();
1030
1031    if (a > 255) a = 255; if (a < 0) a = 0;
1032    if (r > 255) r = 255; if (r < 0) r = 0;
1033    if (g > 255) g = 255; if (g < 0) g = 0;
1034    if (b > 255) b = 255; if (b < 0) b = 0;
1035    if (r > a)
1036      {
1037         r = a;
1038         ERR("Evas only handles pre multiplied colors!");
1039      }
1040    if (g > a)
1041      {
1042         g = a;
1043         ERR("Evas only handles pre multiplied colors!");
1044      }
1045    if (b > a)
1046      {
1047         b = a;
1048         ERR("Evas only handles pre multiplied colors!");
1049      }
1050
1051    switch (pal)
1052      {
1053      case EVAS_TEXTGRID_PALETTE_STANDARD:
1054        palette = o->cur.palette_standard;
1055        break;
1056      case EVAS_TEXTGRID_PALETTE_EXTENDED:
1057        palette = o->cur.palette_extended;
1058        break;
1059      default:
1060        return;
1061      }
1062
1063    color = malloc(sizeof(Evas_Object_Textgrid_Color));
1064    if (!color) return;
1065
1066    color->a = a;
1067    color->r = r;
1068    color->g = g;
1069    color->b = b;
1070
1071    count = eina_array_count(palette);
1072    if (idx < count) eina_array_data_set(palette, idx, color);
1073    else if (idx == count) eina_array_push(palette, color);
1074    else
1075      {
1076         for (i = count; i < idx; i++)
1077           {
1078              c = calloc(1, sizeof(Evas_Object_Textgrid_Color));
1079              if (!c)
1080                {
1081                   ERR("Evas can not allocate memory");
1082                   return;
1083                }
1084              eina_array_push(palette, c);
1085           }
1086         eina_array_push(palette, color);
1087      }
1088    o->changed = 1;
1089    o->pal_change = 1;
1090    evas_object_textgrid_rows_clear(obj);
1091    evas_object_change(obj);
1092 }
1093
1094 EAPI void
1095 evas_object_textgrid_palette_get(const Evas_Object *obj, Evas_Textgrid_Palette pal, int idx, int *r, int *g, int *b, int *a)
1096 {
1097    Evas_Object_Textgrid *o;
1098    Eina_Array *palette;
1099    Evas_Object_Textgrid_Color *color;
1100
1101    if (idx < 0) return;
1102
1103    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1104    if (a) *a = 0;
1105    if (r) *r = 0;
1106    if (g) *g = 0;
1107    if (b) *b = 0;
1108    return;
1109    MAGIC_CHECK_END();
1110    o = (Evas_Object_Textgrid *)(obj->object_data);
1111    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
1112    if (a) *a = 0;
1113    if (r) *r = 0;
1114    if (g) *g = 0;
1115    if (b) *b = 0;
1116    return;
1117    MAGIC_CHECK_END();
1118    
1119    switch (pal)
1120      {
1121       case EVAS_TEXTGRID_PALETTE_STANDARD:
1122         palette = o->cur.palette_standard;
1123         break;
1124       case EVAS_TEXTGRID_PALETTE_EXTENDED:
1125         palette = o->cur.palette_extended;
1126         break;
1127       default:
1128         return;
1129      }
1130    
1131    if (idx >= (int)eina_array_count(palette)) return;
1132    color = eina_array_data_get(palette, idx);
1133    if (!color) return;
1134
1135    if (a) *a = color->a;
1136    if (r) *r = color->r;
1137    if (g) *g = color->g;
1138    if (b) *b = color->b;
1139 }
1140
1141
1142 EAPI void
1143 evas_object_textgrid_supported_font_styles_set(Evas_Object *obj, Evas_Textgrid_Font_Style styles)
1144 {
1145    Evas_Object_Textgrid *o;
1146    
1147    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1148    return;
1149    MAGIC_CHECK_END();
1150    o = (Evas_Object_Textgrid *)(obj->object_data);
1151    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
1152    return;
1153    MAGIC_CHECK_END();
1154
1155    /* FIXME: to do */
1156    if (styles)
1157      {
1158         o->changed = 1;
1159         evas_object_change(obj);
1160      }
1161 }
1162
1163 EAPI Evas_Textgrid_Font_Style
1164 evas_object_textgrid_supported_font_styles_get(const Evas_Object *obj)
1165 {
1166    Evas_Object_Textgrid *o;
1167
1168    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1169    return EVAS_TEXTGRID_FONT_STYLE_NORMAL;
1170    MAGIC_CHECK_END();
1171    o = (Evas_Object_Textgrid *)(obj->object_data);
1172    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
1173    return EVAS_TEXTGRID_FONT_STYLE_NORMAL;
1174    MAGIC_CHECK_END();
1175
1176    /* FIXME: to do */
1177    return 0;
1178 }
1179
1180 EAPI void
1181 evas_object_textgrid_cellrow_set(Evas_Object *obj, int y, const Evas_Textgrid_Cell *row)
1182 {
1183    Evas_Object_Textgrid *o;
1184    
1185    if (!row) return;
1186
1187    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1188    return;
1189    MAGIC_CHECK_END();
1190    o = (Evas_Object_Textgrid *)(obj->object_data);
1191    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
1192    return;
1193    MAGIC_CHECK_END();
1194
1195    if ((y < 0) || (y >= o->cur.h)) return;
1196 }
1197
1198 EAPI Evas_Textgrid_Cell *
1199 evas_object_textgrid_cellrow_get(const Evas_Object *obj, int y)
1200 {
1201    Evas_Object_Textgrid *o;
1202    
1203    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1204    return NULL;
1205    MAGIC_CHECK_END();
1206    o = (Evas_Object_Textgrid *)(obj->object_data);
1207    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
1208    return NULL;
1209    MAGIC_CHECK_END();
1210
1211    if ((y < 0) || (y >= o->cur.h)) return NULL;
1212
1213    return o->cur.cells + (y * o->cur.w);
1214 }
1215
1216 EAPI void
1217 evas_object_textgrid_update_add(Evas_Object *obj, int x, int y, int w, int h)
1218 {
1219    Evas_Object_Textgrid *o;
1220    int i, x2;
1221    
1222    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1223    return;
1224    MAGIC_CHECK_END();
1225    o = (Evas_Object_Textgrid *)(obj->object_data);
1226    MAGIC_CHECK(o, Evas_Object_Textgrid, MAGIC_OBJ_TEXTGRID);
1227    return;
1228    MAGIC_CHECK_END();
1229
1230    RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, o->cur.w, o->cur.h);
1231    if ((w <= 0) || (h <= 0)) return;
1232    
1233    x2 = x + w - 1;
1234    for (i = 0; i < h; i++)
1235      {
1236         Evas_Object_Textgrid_Row *r = &(o->cur.rows[y + i]);
1237         
1238         if (r->ch1 < 0)
1239           {
1240              evas_object_textgrid_row_clear(r);
1241              r->ch1 = x;
1242              r->ch2 = x2;
1243           }
1244         else
1245           {
1246              if (x < r->ch1) r->ch1 = x;
1247              if (x2 > r->ch2) r->ch2 = x2;
1248           }
1249      }
1250    o->row_change = 1;
1251    o->changed = 1;
1252    evas_object_change(obj);
1253 }