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