aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules/evas/engines/gl_common/evas_gl_font.c
blob: 968168d9b5f6597de350be1e6f86a0b95381026f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#include "evas_gl_private.h"

void *
evas_gl_font_texture_new(void *context, RGBA_Font_Glyph *fg)
{
   Evas_Engine_GL_Context *gc = context;
   Evas_GL_Texture *tex;
   int w, h, j, nw, fh, x, y;
   DATA8 *ndata, *data, *p1, *p2;

   if (fg->ext_dat) return fg->ext_dat; // FIXME: one engine at a time can do this :(

   w = fg->glyph_out->bitmap.width;
   h = fg->glyph_out->bitmap.rows;
   if ((w == 0) || (h == 0)) return NULL;

   if (!fg->glyph_out->rle) return NULL;
   data = evas_common_font_glyph_uncompress(fg, &w, &h);
   if (!data) return NULL;
   j = w;
   if (j < w) j = w;

   // expand to 32bit (4 byte) aligned rows for texture upload
   nw = ((w + 3) / 4) * 4;
   ndata = alloca(nw *h);
   if (!ndata) return NULL;
   for (y = 0; y < h; y++)
     {
        p1 = data + (j * y);
        p2 = ndata + (nw * y);
        for (x = 0; x < w; x++)
          {
             *p2 = *p1;
             p1++;
             p2++;
          }
     }
   fh = fg->fi->max_h;
   tex = evas_gl_common_texture_alpha_new(gc, ndata, w, h, fh);
   if (!tex) goto done;
   tex->sx1 = ((double)(tex->x)) / (double)tex->pt->w;
   tex->sy1 = ((double)(tex->y)) / (double)tex->pt->h;
   tex->sx2 = ((double)(tex->x + tex->w)) / (double)tex->pt->w;
   tex->sy2 = ((double)(tex->y + tex->h)) / (double)tex->pt->h;
   tex->fglyph = fg;
   gc->font_glyph_textures = eina_list_append(gc->font_glyph_textures, tex);
done:
   free(data);
   return tex;
}

void
evas_gl_font_texture_free(void *tex)
{
   if (!tex) return;
   evas_gl_common_texture_free(tex, EINA_TRUE);
}

void
evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_context, RGBA_Font_Glyph *fg, int x, int y)
{
   Evas_Engine_GL_Context *gc = context;
   RGBA_Draw_Context *dc = draw_context;
   Evas_GL_Image *mask = gc->dc->clip.mask;
   Evas_GL_Texture *tex, *mtex = NULL;
   Cutout_Rect  *rct;
   int r, g, b, a;
   double ssx, ssy, ssw, ssh;
   int c, cx, cy, cw, ch;
   int i;
   int sx, sy, sw, sh;
   double mx = 0.0, my = 0.0, mw = 0.0, mh = 0.0;
   Eina_Bool mask_smooth = EINA_FALSE;

   if (dc != gc->dc) return;
   tex = fg->ext_dat;
   if (!tex) return;
   a = (dc->col.col >> 24) & 0xff;
   if (a == 0) return;
   r = (dc->col.col >> 16) & 0xff;
   g = (dc->col.col >> 8 ) & 0xff;
   b = (dc->col.col      ) & 0xff;
   sx = 0; sy = 0; sw = tex->w, sh = tex->h;

   if (mask)
     {
        evas_gl_common_image_update(gc, mask);
        mtex = mask->tex;
        if (mtex && mtex->pt && mtex->pt->w && mtex->pt->h)
          {
             // canvas coords
             mx = gc->dc->clip.mask_x;
             my = gc->dc->clip.mask_y;
             mw = mask->w;
             mh = mask->h;
             mask_smooth = mask->scaled.smooth;
          }
        else mtex = NULL;
     }

   if ((!gc->dc->cutout.rects) ||
       ((gc->shared->info.tune.cutout.max > 0) &&
           (gc->dc->cutout.active > gc->shared->info.tune.cutout.max)))
     {
        if (gc->dc->clip.use)
          {
             int nx, ny, nw, nh;

             nx = x; ny = y; nw = tex->w; nh = tex->h;
             RECTS_CLIP_TO_RECT(nx, ny, nw, nh,
                                gc->dc->clip.x, gc->dc->clip.y,
                                gc->dc->clip.w, gc->dc->clip.h);
             if ((nw < 1) || (nh < 1)) return;
             if ((nx == x) && (ny == y) && (nw == tex->w) && (nh == tex->h))
               {
                  evas_gl_common_context_font_push(gc, tex,
                                                   0.0, 0.0, 0.0, 0.0,
//                                                   sx, sy, sw, sh,
                                                   x, y, tex->w, tex->h,
                                                   mtex, mx, my, mw, mh, mask_smooth,
                                                   r, g, b, a);
                  return;
               }
             ssx = (double)sx + ((double)(sw * (nx - x)) / (double)(tex->w));
             ssy = (double)sy + ((double)(sh * (ny - y)) / (double)(tex->h));
             ssw = ((double)sw * (double)(nw)) / (double)(tex->w);
             ssh = ((double)sh * (double)(nh)) / (double)(tex->h);
             evas_gl_common_context_font_push(gc, tex,
                                              ssx, ssy, ssw, ssh,
                                              nx, ny, nw, nh,
                                              mtex, mx, my, mw, mh, mask_smooth,
                                              r, g, b, a);
          }
        else
          {
             evas_gl_common_context_font_push(gc, tex,
                                              0.0, 0.0, 0.0, 0.0,
//                                              sx, sy, sw, sh,
                                              x, y, tex->w, tex->h,
                                              mtex, mx, my, mw, mh, mask_smooth,
                                              r, g, b, a);
          }
        return;
     }
   /* save out clip info */
   c = gc->dc->clip.use; cx = gc->dc->clip.x; cy = gc->dc->clip.y; cw = gc->dc->clip.w; ch = gc->dc->clip.h;
   evas_common_draw_context_clip_clip(gc->dc, 0, 0, gc->shared->w, gc->shared->h);
   evas_common_draw_context_clip_clip(gc->dc, x, y, tex->w, tex->h);
   /* our clip is 0 size.. abort */
   if ((gc->dc->clip.w <= 0) || (gc->dc->clip.h <= 0))
     {
        gc->dc->clip.use = c; gc->dc->clip.x = cx; gc->dc->clip.y = cy; gc->dc->clip.w = cw; gc->dc->clip.h = ch;
        return;
     }
   _evas_gl_common_cutout_rects = evas_common_draw_context_apply_cutouts(dc, _evas_gl_common_cutout_rects);
   for (i = 0; i < _evas_gl_common_cutout_rects->active; ++i)
     {
        int nx, ny, nw, nh;

        rct = _evas_gl_common_cutout_rects->rects + i;
        nx = x; ny = y; nw = tex->w; nh = tex->h;
        RECTS_CLIP_TO_RECT(nx, ny, nw, nh, rct->x, rct->y, rct->w, rct->h);
        if ((nw < 1) || (nh < 1)) continue;
        if ((nx == x) && (ny == y) && (nw == tex->w) && (nh == tex->h))
          {
             evas_gl_common_context_font_push(gc, tex,
                                              0.0, 0.0, 0.0, 0.0,
//                                              sx, sy, sw, sh,
                                              x, y, tex->w, tex->h,
                                              mtex, mx, my, mw, mh, mask_smooth,
                                              r, g, b, a);
             continue;
          }
        ssx = (double)sx + ((double)(sw * (nx - x)) / (double)(tex->w));
        ssy = (double)sy + ((double)(sh * (ny - y)) / (double)(tex->h));
        ssw = ((double)sw * (double)(nw)) / (double)(tex->w);
        ssh = ((double)sh * (double)(nh)) / (double)(tex->h);
        evas_gl_common_context_font_push(gc, tex,
                                         ssx, ssy, ssw, ssh,
                                         nx, ny, nw, nh,
                                         mtex, mx, my, mw, mh, mask_smooth,
                                         r, g, b, a);
     }
   evas_common_draw_context_cutouts_free(_evas_gl_common_cutout_rects);
   /* restore clip info */
   gc->dc->clip.use = c; gc->dc->clip.x = cx; gc->dc->clip.y = cy; gc->dc->clip.w = cw; gc->dc->clip.h = ch;
}