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