1 #include "evas_common_private.h"
2 #include "evas_blend_private.h"
3 
4 #include "Ecore.h"
5 
6 static Eina_Bool scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst, RGBA_Draw_Context *dc, int src_region_x, int src_region_y, int src_region_w, int src_region_h, int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h);
7 
8 typedef struct _Evas_Scale_Thread Evas_Scale_Thread;
9 typedef struct _Evas_Scale_Msg Evas_Scale_Msg;
10 
11 struct _Evas_Scale_Msg
12 {
13    Eina_Thread_Queue_Msg head;
14    Evas_Scale_Thread *task;
15 };
16 
17 struct _Evas_Scale_Thread
18 {
19    RGBA_Image *mask8;
20    DATA32 **row_ptr;
21    DATA32 *dptr;
22    int *lin_ptr;
23 
24    RGBA_Gfx_Func func;
25    RGBA_Gfx_Func func2;
26 
27    int dst_clip_x;
28    int dst_clip_y;
29    int dst_clip_h;
30    int dst_clip_w;
31    int dst_w;
32 
33    int mask_x;
34    int mask_y;
35 
36    unsigned int mul_col;
37 };
38 
39 static Eina_Bool use_thread = EINA_FALSE;
40 static Eina_Thread scaling_thread;
41 static Eina_Thread_Queue *thread_queue = NULL;
42 static Eina_Thread_Queue *main_queue = NULL;
43 
44 EAPI Eina_Bool
evas_common_scale_rgba_in_to_out_clip_sample(RGBA_Image * src,RGBA_Image * dst,RGBA_Draw_Context * dc,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h)45 evas_common_scale_rgba_in_to_out_clip_sample(RGBA_Image *src, RGBA_Image *dst,
46                                              RGBA_Draw_Context *dc,
47                                              int src_region_x, int src_region_y,
48                                              int src_region_w, int src_region_h,
49                                              int dst_region_x, int dst_region_y,
50                                              int dst_region_w, int dst_region_h)
51 {
52    return evas_common_scale_rgba_in_to_out_clip_cb
53      (src, dst, dc,
54       src_region_x, src_region_y, src_region_w, src_region_h,
55       dst_region_x, dst_region_y, dst_region_w, dst_region_h,
56       scale_rgba_in_to_out_clip_sample_internal);
57 }
58 
59 EAPI void
evas_common_scale_rgba_in_to_out_clip_sample_do(const Cutout_Rects * reuse,const Eina_Rectangle * clip,RGBA_Image * src,RGBA_Image * dst,RGBA_Draw_Context * dc,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h)60 evas_common_scale_rgba_in_to_out_clip_sample_do(const Cutout_Rects *reuse,
61                                                 const Eina_Rectangle *clip,
62                                                 RGBA_Image *src, RGBA_Image *dst,
63                                                 RGBA_Draw_Context *dc,
64                                                 int src_region_x, int src_region_y,
65                                                 int src_region_w, int src_region_h,
66                                                 int dst_region_x, int dst_region_y,
67                                                 int dst_region_w, int dst_region_h)
68 {
69    Eina_Rectangle area;
70    Cutout_Rect *r;
71    int i;
72 
73    if (!reuse)
74      {
75         evas_common_draw_context_clip_clip(dc, clip->x, clip->y, clip->w, clip->h);
76         scale_rgba_in_to_out_clip_sample_internal(src, dst, dc,
77                                                   src_region_x, src_region_y,
78                                                   src_region_w, src_region_h,
79                                                   dst_region_x, dst_region_y,
80                                                   dst_region_w, dst_region_h);
81         return;
82      }
83 
84    for (i = 0; i < reuse->active; ++i)
85      {
86         r = reuse->rects + i;
87 
88         EINA_RECTANGLE_SET(&area, r->x, r->y, r->w, r->h);
89         if (!eina_rectangle_intersection(&area, clip)) continue ;
90         evas_common_draw_context_set_clip(dc, area.x, area.y, area.w, area.h);
91         scale_rgba_in_to_out_clip_sample_internal(src, dst, dc,
92                                                   src_region_x, src_region_y,
93                                                   src_region_w, src_region_h,
94                                                   dst_region_x, dst_region_y,
95                                                   dst_region_w, dst_region_h);
96      }
97 }
98 
99 static void
_evas_common_scale_rgba_sample_scale_nomask(int y,int dst_clip_w,int dst_clip_h,int dst_w,DATA32 ** row_ptr,int * lin_ptr,DATA32 * dptr,RGBA_Gfx_Func func,unsigned int mul_col,DATA32 * srcptr,int src_w)100 _evas_common_scale_rgba_sample_scale_nomask(int y,
101                                             int dst_clip_w, int dst_clip_h, int dst_w,
102                                             DATA32 **row_ptr, int *lin_ptr,
103                                             DATA32 *dptr, RGBA_Gfx_Func func, unsigned int mul_col,
104                                             DATA32 *srcptr, int src_w)
105 {
106    int x;
107    dptr = dptr + dst_w * y;
108 
109    if (srcptr)
110      {
111         for (; y < dst_clip_h; y++)
112           {
113              /* * blend here [clip_w *] buf -> dptr * */
114              func(srcptr, NULL, mul_col, dptr, dst_clip_w);
115              dptr += dst_w;
116              srcptr += src_w;
117           }
118      }
119    else
120      {
121         DATA32 *buf = alloca(dst_clip_w * sizeof(DATA32));
122         for (; y < dst_clip_h; y++)
123           {
124              DATA32 *dst_ptr = buf;
125              for (x = 0; x < dst_clip_w; x++)
126                {
127                   DATA32 *ptr = row_ptr[y] + lin_ptr[x];
128                   *dst_ptr = *ptr;
129                   dst_ptr++;
130                }
131              /* * blend here [clip_w *] buf -> dptr * */
132              func(buf, NULL, mul_col, dptr, dst_clip_w);
133              dptr += dst_w;
134           }
135      }
136 }
137 
138 static void
_evas_common_scale_rgba_sample_scale_mask(int y,int dst_clip_x,int dst_clip_y,int dst_clip_w,int dst_clip_h,int dst_w,int mask_x,int mask_y,DATA32 ** row_ptr,int * lin_ptr,RGBA_Image * mask_ie,DATA32 * dptr,RGBA_Gfx_Func func,RGBA_Gfx_Func func2,unsigned int mul_col,DATA32 * srcptr,int src_w)139 _evas_common_scale_rgba_sample_scale_mask(int y,
140                                           int dst_clip_x, int dst_clip_y,
141                                           int dst_clip_w, int dst_clip_h, int dst_w,
142                                           int mask_x, int mask_y,
143                                           DATA32 **row_ptr, int *lin_ptr, RGBA_Image *mask_ie,
144                                           DATA32 *dptr, RGBA_Gfx_Func func, RGBA_Gfx_Func func2,
145                                           unsigned int mul_col,
146                                           DATA32 *srcptr, int src_w)
147 {
148    DATA32 *buf;
149    int x;
150 
151    /* clamp/map to mask geometry */
152    if (EINA_UNLIKELY(dst_clip_x < mask_x))
153      dst_clip_x = mask_x;
154    if (EINA_UNLIKELY(dst_clip_y < mask_y))
155      dst_clip_y = mask_y;
156    if (EINA_UNLIKELY(dst_clip_x + dst_clip_w > mask_x + (int)mask_ie->cache_entry.w))
157      dst_clip_w = mask_x + mask_ie->cache_entry.w - dst_clip_x;
158    if (EINA_UNLIKELY(dst_clip_y + dst_clip_h > mask_y + (int)mask_ie->cache_entry.h))
159      dst_clip_h = mask_y + mask_ie->cache_entry.h - dst_clip_y;
160 
161    /* a scanline buffer */
162    buf = alloca(dst_clip_w * sizeof(DATA32));
163 
164    dptr = dptr + dst_w * y;
165    for (; y < dst_clip_h; y++)
166      {
167         DATA8 *mask;
168 
169         mask = mask_ie->image.data8
170           + ((dst_clip_y - mask_y + y) * mask_ie->cache_entry.w)
171           + (dst_clip_x - mask_x);
172 
173         if (!srcptr)
174           {
175              DATA32 *dst_ptr = buf;
176              for (x = 0; x < dst_clip_w; x++)
177                {
178                   DATA32 *ptr;
179 
180                   ptr = row_ptr[y] + lin_ptr[x];
181                   *dst_ptr = *ptr;
182                   dst_ptr++;
183                }
184           }
185 
186         /* * blend here [clip_w *] buf -> dptr * */
187         if (mul_col != 0xFFFFFFFF)
188           {
189              func2(srcptr ?: buf, NULL, mul_col, buf, dst_clip_w);
190              func(buf, mask, 0, dptr, dst_clip_w);
191           }
192         else
193           func(srcptr ?: buf, mask, 0, dptr, dst_clip_w);
194 
195         dptr += dst_w;
196         if (srcptr) srcptr += src_w;
197      }
198 }
199 
200 EAPI void
evas_common_scale_rgba_sample_draw(RGBA_Image * src,RGBA_Image * dst,int dst_clip_x,int dst_clip_y,int dst_clip_w,int dst_clip_h,DATA32 mul_col,int render_op,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h,RGBA_Image * mask_ie,int mask_x,int mask_y)201 evas_common_scale_rgba_sample_draw(RGBA_Image *src, RGBA_Image *dst, int dst_clip_x, int dst_clip_y, int dst_clip_w, int dst_clip_h, DATA32 mul_col, int render_op, int src_region_x, int src_region_y, int src_region_w, int src_region_h, int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h, RGBA_Image *mask_ie, int mask_x, int mask_y)
202 {
203    int      x, y;
204    int     *lin_ptr;
205    DATA32 **row_ptr;
206    DATA32  *ptr, *dst_ptr, *src_data, *dst_data;
207    int      src_w, src_h, dst_w, dst_h;
208    RGBA_Gfx_Func func, func2 = NULL;
209 
210    if ((!src->image.data) || (!dst->image.data)) return;
211    if (!(RECTS_INTERSECT(dst_region_x, dst_region_y, dst_region_w, dst_region_h,
212                          0, 0, dst->cache_entry.w, dst->cache_entry.h))) return;
213    if (!(RECTS_INTERSECT(src_region_x, src_region_y, src_region_w, src_region_h,
214                          0, 0, src->cache_entry.w, src->cache_entry.h))) return;
215 
216    if ((src_region_w <= 0) || (src_region_h <= 0) ||
217        (dst_region_w <= 0) || (dst_region_h <= 0)) return;
218 
219    src_w = src->cache_entry.w;
220    if (src_region_x >= src_w) return;
221 
222    src_h = src->cache_entry.h;
223    if (src_region_y >= src_h) return;
224 
225    dst_w = dst->cache_entry.w;
226    dst_h = dst->cache_entry.h;
227 
228    src_data = src->image.data;
229    dst_data = dst->image.data;
230 
231    /* sanitise clip x */
232    if (dst_clip_x < 0)
233      {
234         dst_clip_w += dst_clip_x;
235         dst_clip_x = 0;
236      }
237 
238    if ((dst_clip_x + dst_clip_w) > dst_w)
239      dst_clip_w = dst_w - dst_clip_x;
240 
241    if (dst_clip_x < dst_region_x)
242      {
243         dst_clip_w += dst_clip_x - dst_region_x;
244         dst_clip_x = dst_region_x;
245      }
246 
247    if (dst_clip_x >= dst_w) return;
248 
249    if ((dst_clip_x + dst_clip_w) > (dst_region_x + dst_region_w))
250      dst_clip_w = dst_region_x + dst_region_w - dst_clip_x;
251 
252    if (dst_clip_w <= 0) return;
253 
254    /* sanitise clip y */
255    if (dst_clip_y < 0)
256      {
257         dst_clip_h += dst_clip_y;
258         dst_clip_y = 0;
259      }
260 
261    if ((dst_clip_y + dst_clip_h) > dst_h)
262      dst_clip_h = dst_h - dst_clip_y;
263 
264    if (dst_clip_y < dst_region_y)
265      {
266         dst_clip_h += dst_clip_y - dst_region_y;
267         dst_clip_y = dst_region_y;
268      }
269 
270    if (dst_clip_y >= dst_h) return;
271 
272    if ((dst_clip_y + dst_clip_h) > (dst_region_y + dst_region_h))
273      dst_clip_h = dst_region_y + dst_region_h - dst_clip_y;
274 
275    if (dst_clip_h <= 0) return;
276 
277    /* sanitise region x */
278    if (src_region_x < 0)
279      {
280         dst_region_x -= (src_region_x * dst_region_w) / src_region_w;
281         dst_region_w += (src_region_x * dst_region_w) / src_region_w;
282         src_region_w += src_region_x;
283         src_region_x = 0;
284 
285         if (dst_clip_x < dst_region_x)
286           {
287              dst_clip_w += (dst_clip_x - dst_region_x);
288              dst_clip_x = dst_region_x;
289           }
290      }
291 
292    if ((dst_clip_x + dst_clip_w) > dst_w)
293      dst_clip_w = dst_w - dst_clip_x;
294 
295    if (dst_clip_w <= 0) return;
296 
297    if ((src_region_x + src_region_w) > src_w)
298      {
299         dst_region_w = (dst_region_w * (src_w - src_region_x)) / (src_region_w);
300         src_region_w = src_w - src_region_x;
301      }
302 
303    if ((dst_region_w <= 0) || (src_region_w <= 0)) return;
304 
305    /* sanitise region y */
306    if (src_region_y < 0)
307      {
308         dst_region_y -= (src_region_y * dst_region_h) / src_region_h;
309         dst_region_h += (src_region_y * dst_region_h) / src_region_h;
310         src_region_h += src_region_y;
311         src_region_y = 0;
312 
313         if (dst_clip_y < dst_region_y)
314           {
315              dst_clip_h += (dst_clip_y - dst_region_y);
316              dst_clip_y = dst_region_y;
317           }
318      }
319 
320    if ((dst_clip_y + dst_clip_h) > dst_h)
321      dst_clip_h = dst_h - dst_clip_y;
322 
323    if (dst_clip_h <= 0) return;
324 
325    if ((src_region_y + src_region_h) > src_h)
326      {
327         dst_region_h = (dst_region_h * (src_h - src_region_y)) / (src_region_h);
328         src_region_h = src_h - src_region_y;
329      }
330 
331    if ((dst_region_h <= 0) || (src_region_h <= 0)) return;
332 
333    /* figure out dst jump */
334    //dst_jump = dst_w - dst_clip_w;
335 
336    /* figure out dest start ptr */
337    dst_ptr = dst_data + dst_clip_x + (dst_clip_y * dst_w);
338 
339    if (!mask_ie)
340      {
341          if (mul_col != 0xffffffff)
342            func = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, mul_col, dst->cache_entry.flags.alpha, dst_clip_w, render_op);
343          else
344            func = evas_common_gfx_func_composite_pixel_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, render_op);
345      }
346    else
347      {
348         if (mul_col != 0xffffffff)
349           {
350              func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, render_op);
351              func2 = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, mul_col, dst->cache_entry.flags.alpha, dst_clip_w, EVAS_RENDER_COPY);
352           }
353         else
354           func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, render_op);
355      }
356 
357    if ((dst_region_w == src_region_w) && (dst_region_h == src_region_h))
358      {
359         ptr = src_data + (((dst_clip_y - dst_region_y) + src_region_y) * src_w) + ((dst_clip_x - dst_region_x) + src_region_x);
360 
361 
362         if (mask_ie)
363           _evas_common_scale_rgba_sample_scale_mask(0,
364             dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h,
365             dst_w, mask_x, mask_y,
366             NULL, NULL,
367             mask_ie, dst_ptr,
368             func, func2, mul_col,
369             ptr, src_w);
370         else
371           _evas_common_scale_rgba_sample_scale_nomask(0,
372             dst_clip_w, dst_clip_h, dst_w,
373             NULL, NULL,
374             dst_ptr,
375             func, mul_col,
376             ptr, src_w);
377      }
378    else
379      {
380         /* allocate scale lookup tables */
381         lin_ptr = alloca(dst_clip_w * sizeof(int));
382         row_ptr = alloca(dst_clip_h * sizeof(DATA32 *));
383 
384         /* fill scale tables */
385         for (x = 0; x < dst_clip_w; x++)
386           lin_ptr[x] = (((x + dst_clip_x - dst_region_x) * src_region_w) / dst_region_w) + src_region_x;
387         for (y = 0; y < dst_clip_h; y++)
388           row_ptr[y] = src_data + (((((y + dst_clip_y - dst_region_y) * src_region_h) / dst_region_h)
389                                     + src_region_y) * src_w);
390 
391         if (mask_ie)
392           _evas_common_scale_rgba_sample_scale_mask(0,
393             dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h,
394             dst_w, mask_x, mask_y,
395             row_ptr, lin_ptr,
396             mask_ie, dst_ptr,
397             func, func2, mul_col,
398             NULL, 0);
399         else
400           _evas_common_scale_rgba_sample_scale_nomask(0,
401             dst_clip_w, dst_clip_h, dst_w,
402             row_ptr, lin_ptr,
403             dst_ptr,
404             func, mul_col,
405             NULL, 0);
406      }
407 }
408 
409 static Eina_Bool
scale_rgba_in_to_out_clip_sample_internal(RGBA_Image * src,RGBA_Image * dst,RGBA_Draw_Context * dc,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h)410 scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst,
411                                          RGBA_Draw_Context *dc,
412                                          int src_region_x, int src_region_y,
413                                          int src_region_w, int src_region_h,
414                                          int dst_region_x, int dst_region_y,
415                                          int dst_region_w, int dst_region_h)
416 {
417    int      x, y;
418    int     *lin_ptr;
419    DATA32 *dptr;
420    DATA32 **row_ptr;
421    DATA32  *ptr, *dst_ptr, *src_data, *dst_data;
422    int      dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h;
423    int      src_w, src_h, dst_w, dst_h, mask_x, mask_y;
424    RGBA_Gfx_Func func, func2 = NULL;
425    RGBA_Image *mask_ie = dc->clip.mask;
426 
427    if (!(RECTS_INTERSECT(dst_region_x, dst_region_y, dst_region_w, dst_region_h, 0, 0, dst->cache_entry.w, dst->cache_entry.h)))
428      return EINA_FALSE;
429    if (!(RECTS_INTERSECT(src_region_x, src_region_y, src_region_w, src_region_h, 0, 0, src->cache_entry.w, src->cache_entry.h)))
430      return EINA_FALSE;
431 
432    src_w = src->cache_entry.w;
433    src_h = src->cache_entry.h;
434    dst_w = dst->cache_entry.w;
435    dst_h = dst->cache_entry.h;
436 
437    src_data = src->image.data;
438    dst_data = dst->image.data;
439 
440    mask_x = dc->clip.mask_x;
441    mask_y = dc->clip.mask_y;
442 
443    if (dc->clip.use)
444      {
445         dst_clip_x = dc->clip.x;
446         dst_clip_y = dc->clip.y;
447         dst_clip_w = dc->clip.w;
448         dst_clip_h = dc->clip.h;
449         if (dst_clip_x < 0)
450           {
451              dst_clip_w += dst_clip_x;
452              dst_clip_x = 0;
453           }
454         if (dst_clip_y < 0)
455           {
456              dst_clip_h += dst_clip_y;
457              dst_clip_y = 0;
458           }
459         if ((dst_clip_x + dst_clip_w) > dst_w)
460           dst_clip_w = dst_w - dst_clip_x;
461         if ((dst_clip_y + dst_clip_h) > dst_h)
462           dst_clip_h = dst_h - dst_clip_y;
463      }
464    else
465      {
466         dst_clip_x = 0;
467         dst_clip_y = 0;
468         dst_clip_w = dst_w;
469         dst_clip_h = dst_h;
470      }
471 
472    if (dst_clip_x < dst_region_x)
473      {
474         dst_clip_w += dst_clip_x - dst_region_x;
475         dst_clip_x = dst_region_x;
476      }
477    if ((dst_clip_x + dst_clip_w) > (dst_region_x + dst_region_w))
478      dst_clip_w = dst_region_x + dst_region_w - dst_clip_x;
479    if (dst_clip_y < dst_region_y)
480      {
481         dst_clip_h += dst_clip_y - dst_region_y;
482         dst_clip_y = dst_region_y;
483      }
484    if ((dst_clip_y + dst_clip_h) > (dst_region_y + dst_region_h))
485      dst_clip_h = dst_region_y + dst_region_h - dst_clip_y;
486 
487    if ((src_region_w <= 0) || (src_region_h <= 0) ||
488        (dst_region_w <= 0) || (dst_region_h <= 0) ||
489        (dst_clip_w <= 0) || (dst_clip_h <= 0))
490      return EINA_FALSE;
491 
492    /* sanitise x */
493    if (src_region_x < 0)
494      {
495         dst_region_x -= (src_region_x * dst_region_w) / src_region_w;
496         dst_region_w += (src_region_x * dst_region_w) / src_region_w;
497         src_region_w += src_region_x;
498         src_region_x = 0;
499      }
500    if (src_region_x >= src_w) return EINA_FALSE;
501    if ((src_region_x + src_region_w) > src_w)
502      {
503         dst_region_w = (dst_region_w * (src_w - src_region_x)) / (src_region_w);
504         src_region_w = src_w - src_region_x;
505      }
506    if (dst_region_w <= 0) return EINA_FALSE;
507    if (src_region_w <= 0) return EINA_FALSE;
508    if (dst_clip_x >= dst_w) return EINA_FALSE;
509    if (dst_clip_x < dst_region_x)
510      {
511         dst_clip_w += (dst_clip_x - dst_region_x);
512         dst_clip_x = dst_region_x;
513      }
514    if ((dst_clip_x + dst_clip_w) > dst_w)
515      {
516         dst_clip_w = dst_w - dst_clip_x;
517      }
518    if (dst_clip_w <= 0) return EINA_FALSE;
519 
520    /* sanitise y */
521    if (src_region_y < 0)
522      {
523         dst_region_y -= (src_region_y * dst_region_h) / src_region_h;
524         dst_region_h += (src_region_y * dst_region_h) / src_region_h;
525         src_region_h += src_region_y;
526         src_region_y = 0;
527      }
528    if (src_region_y >= src_h) return EINA_FALSE;
529    if ((src_region_y + src_region_h) > src_h)
530      {
531         dst_region_h = (dst_region_h * (src_h - src_region_y)) / (src_region_h);
532         src_region_h = src_h - src_region_y;
533      }
534    if (dst_region_h <= 0) return EINA_FALSE;
535    if (src_region_h <= 0) return EINA_FALSE;
536    if (dst_clip_y >= dst_h) return EINA_FALSE;
537    if (dst_clip_y < dst_region_y)
538      {
539         dst_clip_h += (dst_clip_y - dst_region_y);
540         dst_clip_y = dst_region_y;
541      }
542    if ((dst_clip_y + dst_clip_h) > dst_h)
543      {
544         dst_clip_h = dst_h - dst_clip_y;
545      }
546    if (dst_clip_h <= 0) return EINA_FALSE;
547 
548    /* figure out dst jump */
549    //dst_jump = dst_w - dst_clip_w;
550 
551    /* figure out dest start ptr */
552    dst_ptr = dst_data + dst_clip_x + (dst_clip_y * dst_w);
553 
554    if (!mask_ie)
555      {
556         if (dc->mul.use)
557           func = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dc->mul.col, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op);
558         else
559           func = evas_common_gfx_func_composite_pixel_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op);
560      }
561    else
562      {
563         func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op);
564         if (dc->mul.use)
565           func2 = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dc->mul.col, dst->cache_entry.flags.alpha, dst_clip_w, EVAS_RENDER_COPY);
566      }
567 
568    if ((dst_region_w == src_region_w) && (dst_region_h == src_region_h))
569      {
570 #ifdef HAVE_PIXMAN
571 # ifdef PIXMAN_IMAGE_SCALE_SAMPLE
572         if ((src->pixman.im) && (dst->pixman.im) && (!dc->clip.mask) &&
573             ((!dc->mul.use) || ((dc->mul.use) && (dc->mul.col == 0xffffffff))) &&
574             ((dc->render_op == _EVAS_RENDER_COPY) ||
575              (dc->render_op == _EVAS_RENDER_BLEND)))
576           {
577              pixman_op_t op = PIXMAN_OP_SRC; // _EVAS_RENDER_COPY
578              if (dc->render_op == _EVAS_RENDER_BLEND)
579                op = PIXMAN_OP_OVER;
580 
581              pixman_image_composite(op,
582                                     src->pixman.im, NULL,
583                                     dst->pixman.im,
584                                     (dst_clip_x - dst_region_x) + src_region_x,
585                                     (dst_clip_y - dst_region_y) + src_region_y,
586                                     0, 0,
587                                     dst_clip_x, dst_clip_y,
588                                     dst_clip_w, dst_clip_h);
589           }
590         else
591 # endif
592 #endif
593           {
594              int mul_col = dc->mul.use ? dc->mul.col : 0xffffffff;
595              ptr = src_data + ((dst_clip_y - dst_region_y + src_region_y) * src_w) + (dst_clip_x - dst_region_x) + src_region_x;
596 
597              if (mask_ie)
598                _evas_common_scale_rgba_sample_scale_mask(0,
599                  dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h,
600                  dst_w, mask_x, mask_y,
601                  NULL, NULL,
602                  mask_ie, dst_ptr,
603                  func, func2, mul_col,
604                  ptr, src_w);
605              else
606                _evas_common_scale_rgba_sample_scale_nomask(0,
607                  dst_clip_w, dst_clip_h, dst_w,
608                  NULL, NULL,
609                  dst_ptr,
610                  func, mul_col,
611                  ptr, src_w);
612           }
613      }
614    else
615      {
616         /* allocate scale lookup tables */
617         lin_ptr = alloca(dst_clip_w * sizeof(int));
618         row_ptr = alloca(dst_clip_h * sizeof(DATA32 *));
619 
620         /* fill scale tables */
621         for (x = 0; x < dst_clip_w; x++)
622           lin_ptr[x] = (((x + dst_clip_x - dst_region_x) * src_region_w) / dst_region_w) + src_region_x;
623         for (y = 0; y < dst_clip_h; y++)
624           row_ptr[y] = src_data + (((((y + dst_clip_y - dst_region_y) * src_region_h) / dst_region_h)
625                                     + src_region_y) * src_w);
626         /* scale to dst */
627         dptr = dst_ptr;
628 #ifdef DIRECT_SCALE
629         if ((!src->cache_entry.flags.alpha) &&
630             (!dst->cache_entry.flags.alpha) &&
631             (!dc->mul.use) &&
632             (!dc->clip.mask))
633           {
634              for (y = 0; y < dst_clip_h; y++)
635                {
636 
637                   dst_ptr = dptr;
638                   for (x = 0; x < dst_clip_w; x++)
639                     {
640                        ptr = row_ptr[y] + lin_ptr[x];
641                        *dst_ptr = *ptr;
642                        dst_ptr++;
643                     }
644 
645                   dptr += dst_w;
646                }
647           }
648         else
649 #endif
650           {
651              unsigned int mul_col;
652 
653              mul_col = dc->mul.use ? dc->mul.col : 0xFFFFFFFF;
654 
655              /* do we have enough data to start some additional thread ? */
656              if (use_thread && dst_clip_h > 32 && dst_clip_w * dst_clip_h > 4096)
657                {
658                   /* Yes, we do ! */
659                   Evas_Scale_Msg *msg;
660                   void *ref;
661                   Evas_Scale_Thread local;
662 
663                   local.mask8 = dc->clip.mask;
664                   local.row_ptr = row_ptr;
665                   local.dptr = dptr;
666                   local.lin_ptr = lin_ptr;
667                   local.func = func;
668                   local.func2 = func2;
669                   local.dst_clip_x = dst_clip_x;
670                   local.dst_clip_y = dst_clip_y;
671                   local.dst_clip_h = dst_clip_h;
672                   local.dst_clip_w = dst_clip_w;
673                   local.dst_w = dst_w;
674                   local.mask_x = mask_x;
675                   local.mask_y = mask_y;
676                   local.mul_col = mul_col;
677 
678                   msg = eina_thread_queue_send(thread_queue, sizeof (Evas_Scale_Msg), &ref);
679                   msg->task = &local;
680                   eina_thread_queue_send_done(thread_queue, ref);
681 
682                   /* image masking */
683                   if (dc->clip.mask)
684                     {
685                        _evas_common_scale_rgba_sample_scale_mask(0,
686                                                                  dst_clip_x, dst_clip_y,
687                                                                  dst_clip_w, dst_clip_h >> 1, dst_w,
688                                                                  dc->clip.mask_x, dc->clip.mask_y,
689                                                                  row_ptr, lin_ptr, dc->clip.mask,
690                                                                  dptr, func, func2, mul_col,
691                                                                  NULL, 0);
692 
693                     }
694                   else
695                     {
696                        _evas_common_scale_rgba_sample_scale_nomask(0,
697                                                                    dst_clip_w, dst_clip_h >> 1, dst_w,
698                                                                    row_ptr, lin_ptr,
699                                                                    dptr, func, mul_col,
700                                                                    NULL, 0);
701                     }
702 
703                   msg = eina_thread_queue_wait(main_queue, &ref);
704                   if (msg) eina_thread_queue_wait_done(main_queue, ref);
705                }
706              else
707                {
708                   /* No we don't ! */
709 
710                   /* image masking */
711                   if (dc->clip.mask)
712                     {
713                        _evas_common_scale_rgba_sample_scale_mask(0,
714                                                                  dst_clip_x, dst_clip_y,
715                                                                  dst_clip_w, dst_clip_h, dst_w,
716                                                                  dc->clip.mask_x, dc->clip.mask_y,
717                                                                  row_ptr, lin_ptr, dc->clip.mask,
718                                                                  dptr, func, func2, mul_col,
719                                                                  NULL, 0);
720 
721                     }
722                   else
723                     {
724                        _evas_common_scale_rgba_sample_scale_nomask(0,
725                                                                    dst_clip_w, dst_clip_h, dst_w,
726                                                                    row_ptr, lin_ptr,
727                                                                    dptr, func, mul_col,
728                                                                    NULL, 0);
729                     }
730                }
731           }
732      }
733 
734    return EINA_TRUE;
735 }
736 
737 static void *
_evas_common_scale_sample_thread(void * data EINA_UNUSED,Eina_Thread t EINA_UNUSED)738 _evas_common_scale_sample_thread(void *data EINA_UNUSED,
739                                  Eina_Thread t EINA_UNUSED)
740 {
741    Evas_Scale_Msg *msg;
742    Evas_Scale_Thread *todo = NULL;
743 
744    eina_thread_name_set(eina_thread_self(), "Evas-scale-sam");
745    do
746      {
747         void *ref;
748 
749         todo = NULL;
750 
751         msg = eina_thread_queue_wait(thread_queue, &ref);
752         if (msg)
753           {
754              int h;
755 
756              todo = msg->task;
757              eina_thread_queue_wait_done(thread_queue, ref);
758 
759              if (!todo) goto end;
760 
761              h = todo->dst_clip_h >> 1;
762 
763              if (todo->mask8)
764                _evas_common_scale_rgba_sample_scale_mask(h,
765                                                          todo->dst_clip_x, todo->dst_clip_y,
766                                                          todo->dst_clip_w, todo->dst_clip_h,
767                                                          todo->dst_w,
768                                                          todo->mask_x, todo->mask_y,
769                                                          todo->row_ptr, todo->lin_ptr, todo->mask8,
770                                                          todo->dptr, todo->func, todo->func2,
771                                                          todo->mul_col,
772                                                          NULL, 0);
773              else
774                _evas_common_scale_rgba_sample_scale_nomask(h,
775                                                            todo->dst_clip_w, todo->dst_clip_h,
776                                                            todo->dst_w,
777                                                            todo->row_ptr, todo->lin_ptr,
778                                                            todo->dptr, todo->func, todo->mul_col,
779                                                            NULL, 0);
780           }
781 
782      end:
783         msg = eina_thread_queue_send(main_queue, sizeof (Evas_Scale_Msg), &ref);
784         msg->task = NULL;
785         eina_thread_queue_send_done(main_queue, ref);
786      }
787    while (todo);
788 
789    return NULL;
790 }
791 
792 static void
evas_common_scale_sample_fork_reset(void * data EINA_UNUSED)793 evas_common_scale_sample_fork_reset(void *data EINA_UNUSED)
794 {
795    eina_thread_queue_free(thread_queue);
796    eina_thread_queue_free(main_queue);
797 
798    thread_queue = eina_thread_queue_new();
799    main_queue = eina_thread_queue_new();
800 
801    if (!eina_thread_create(&scaling_thread, EINA_THREAD_NORMAL, -1,
802                            _evas_common_scale_sample_thread, NULL))
803      {
804         CRI("We failed to recreate the upscaling thread.");
805         use_thread = EINA_FALSE;
806      }
807 }
808 
809 EAPI void
evas_common_scale_sample_init(void)810 evas_common_scale_sample_init(void)
811 {
812    if (eina_cpu_count() <= 2) return ;
813 
814 //Eina_Thread_Queue doesn't work on WIN32.
815 #ifdef _WIN32
816    return;
817 #endif
818 
819    ecore_fork_reset_callback_add(evas_common_scale_sample_fork_reset, NULL);
820 
821    thread_queue = eina_thread_queue_new();
822    if (EINA_UNLIKELY(!thread_queue))
823      {
824         ERR("Failed to create thread queue");
825         goto cleanup;
826      }
827    main_queue = eina_thread_queue_new();
828    if (EINA_UNLIKELY(!thread_queue))
829      {
830         ERR("Failed to create thread queue");
831         goto cleanup;
832      }
833 
834    if (!eina_thread_create(&scaling_thread, EINA_THREAD_NORMAL, -1,
835                            _evas_common_scale_sample_thread, NULL))
836      {
837         CRI("We failed to create the upscaling thread.");
838         goto cleanup;
839      }
840 
841    use_thread = EINA_TRUE;
842    return;
843 
844 cleanup:
845    if (thread_queue) eina_thread_queue_free(thread_queue);
846    if (main_queue) eina_thread_queue_free(main_queue);
847 }
848 
849 EAPI void
evas_common_scale_sample_shutdown(void)850 evas_common_scale_sample_shutdown(void)
851 {
852    Evas_Scale_Msg *msg;
853    void *ref;
854 
855    if (!use_thread) return ;
856 
857    ecore_fork_reset_callback_del(evas_common_scale_sample_fork_reset, NULL);
858 
859    msg = eina_thread_queue_send(thread_queue, sizeof (Evas_Scale_Msg), &ref);
860    msg->task = NULL;
861    eina_thread_queue_send_done(thread_queue, ref);
862 
863    /* Here is the thread commiting succide*/
864 
865    msg = eina_thread_queue_wait(main_queue, &ref);
866    if (msg) eina_thread_queue_wait_done(main_queue, ref);
867 
868    eina_thread_join(scaling_thread);
869 
870    eina_thread_queue_free(thread_queue);
871    eina_thread_queue_free(main_queue);
872 }
873