ector_software_rasterizer: Support gradient mask blending 57/205657/1
authorJunsuChoi <jsuya.choi@samsung.com>
Wed, 8 May 2019 07:57:19 +0000 (16:57 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Wed, 8 May 2019 08:07:48 +0000 (17:07 +0900)
Summary: This patch supports mask blending of gradient shapes.

Test Plan: N/A

Reviewers: Hermet, kimcinoo

Reviewed By: Hermet

Subscribers: cedric, #reviewers, smohanty, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D8855

Change-Id: I536b6f325734f4606ba5b736c750491dcf8cb61e

src/lib/ector/software/ector_software_rasterizer.c

index b2b5779..42a5e8e 100644 (file)
@@ -293,6 +293,120 @@ _blend_gradient(int count, const SW_FT_Span *spans, void *user_data)
      }
 }
 
+static void
+_blend_gradient_alpha(int count, const SW_FT_Span *spans, void *user_data)
+{
+   RGBA_Comp_Func comp_func;
+   Span_Data *data = (Span_Data *)(user_data);
+   src_fetch fetchfunc = NULL;
+   uint32_t *buffer;
+   const int pix_stride = data->raster_buffer->stride / 4;
+   uint32_t gradientbuffer[BLEND_GRADIENT_BUFFER_SIZE];
+
+   // FIXME: Get the proper composition function using ,color, ECTOR_OP etc.
+   if (data->type == LinearGradient) fetchfunc = &fetch_linear_gradient;
+   if (data->type == RadialGradient) fetchfunc = &fetch_radial_gradient;
+
+   if (!fetchfunc)
+     return;
+
+   Ector_Software_Buffer_Base_Data *mask = data->mask;
+   uint32_t *mbuffer = mask->pixels.u32;
+
+   //Temp buffer for intermediate processing
+   uint32_t *tbuffer = malloc(sizeof(uint32_t) * data->raster_buffer->generic->w);
+
+   comp_func = efl_draw_func_span_get(data->op, data->mul_col, data->gradient->alpha);
+
+   // move to the offset location
+   buffer = data->raster_buffer->pixels.u32 + ((pix_stride * data->offy) + data->offx);
+
+   while (count--)
+     {
+        uint32_t *target = buffer + ((data->raster_buffer->generic->w * spans->y) + spans->x);
+        uint32_t *mtarget = mbuffer + ((mask->generic->w * spans->y) + spans->x);
+        uint32_t *temp = tbuffer;
+        int length = spans->len;
+        memset(temp, 0x00, sizeof(uint32_t) * spans->len);
+        while (length)
+          {
+             int l = MIN(length, BLEND_GRADIENT_BUFFER_SIZE);
+             fetchfunc(gradientbuffer, data, spans->y, spans->x, l);
+             comp_func(temp, gradientbuffer, l, data->mul_col, spans->coverage);
+
+             for (int i = 0; i < l; i++)
+               {
+                  *temp = draw_mul_256(((*mtarget)>>24), *temp);
+                  int alpha = 255 - ((*temp) >> 24);
+                  *target = *temp + draw_mul_256(alpha, *target);
+                  ++temp;
+                  ++mtarget;
+                  ++target;
+               }
+             length -= l;
+          }
+        ++spans;
+     }
+   free(tbuffer);
+}
+
+static void
+_blend_gradient_alpha_inv(int count, const SW_FT_Span *spans, void *user_data)
+{
+   RGBA_Comp_Func comp_func;
+   Span_Data *data = (Span_Data *)(user_data);
+   src_fetch fetchfunc = NULL;
+   uint32_t *buffer;
+   const int pix_stride = data->raster_buffer->stride / 4;
+   uint32_t gradientbuffer[BLEND_GRADIENT_BUFFER_SIZE];
+
+   // FIXME: Get the proper composition function using ,color, ECTOR_OP etc.
+   if (data->type == LinearGradient) fetchfunc = &fetch_linear_gradient;
+   if (data->type == RadialGradient) fetchfunc = &fetch_radial_gradient;
+
+   if (!fetchfunc)
+     return;
+
+   Ector_Software_Buffer_Base_Data *mask = data->mask;
+   uint32_t *mbuffer = mask->pixels.u32;
+
+   //Temp buffer for intermediate processing
+   uint32_t *tbuffer = malloc(sizeof(uint32_t) * data->raster_buffer->generic->w);
+
+   comp_func = efl_draw_func_span_get(data->op, data->mul_col, data->gradient->alpha);
+
+   // move to the offset location
+   buffer = data->raster_buffer->pixels.u32 + ((pix_stride * data->offy) + data->offx);
+
+   while (count--)
+     {
+        uint32_t *target = buffer + ((data->raster_buffer->generic->w * spans->y) + spans->x);
+        uint32_t *mtarget = mbuffer + ((mask->generic->w * spans->y) + spans->x);
+        uint32_t *temp = tbuffer;
+        int length = spans->len;
+        memset(temp, 0x00, sizeof(uint32_t) * spans->len);
+        while (length)
+          {
+             int l = MIN(length, BLEND_GRADIENT_BUFFER_SIZE);
+             fetchfunc(gradientbuffer, data, spans->y, spans->x, l);
+             comp_func(temp, gradientbuffer, l, data->mul_col, spans->coverage);
+
+             for (int i = 0; i < l; i++)
+               {
+                  if (*mtarget)
+                    *temp = draw_mul_256((255 - ((*mtarget)>>24)), *temp);
+                  int alpha = 255 - ((*temp) >> 24);
+                  *target = *temp + draw_mul_256(alpha, *target);
+                  ++temp;
+                  ++mtarget;
+                  ++target;
+               }
+             length -= l;
+          }
+        ++spans;
+     }
+   free(tbuffer);
+}
 /*!
     \internal
     spans must be sorted on y
@@ -485,46 +599,49 @@ static void
 _adjust_span_fill_methods(Span_Data *spdata)
 {
    //Blending Function
-   switch(spdata->type)
+   if (spdata->mask)
      {
-        case None:
-          spdata->unclipped_blend = NULL;
-          break;
-        case Solid:
+        switch (spdata->mask_op)
           {
-             if (spdata->mask)
-               {
-                  switch (spdata->mask_op)
-                    {
-                     default:
-                     case EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA:
-                        spdata->unclipped_blend = &_blend_alpha;
-                        break;
-                     case EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA_INV:
-                        spdata->unclipped_blend = &_blend_alpha_inv;
-                        break;
-                     case EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_ADD:
-                        spdata->unclipped_blend = &_blend_mask_add;
-                        break;
-                     case EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_SUBSTRACT:
-                        spdata->unclipped_blend = &_blend_mask_sub;
-                        break;
-                     case EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_INTERSECT:
-                        spdata->unclipped_blend = &_blend_mask_ins;
-                        break;
-                     case EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_DIFFERENCE:
-                        spdata->unclipped_blend = &_blend_mask_diff;
-                        break;
-                    }
-               }
-             else
-                spdata->unclipped_blend = &_blend_argb;
-           }
-          break;
-        case LinearGradient:
-        case RadialGradient:
+           default:
+           case EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA:
+              if (spdata->type == Solid)
+                spdata->unclipped_blend = &_blend_alpha;
+              else if (spdata->type == LinearGradient || spdata->type == RadialGradient)
+                spdata->unclipped_blend = &_blend_gradient_alpha;
+              else //None
+                spdata->unclipped_blend = NULL;
+              break;
+           case EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA_INV:
+              if (spdata->type == Solid)
+                spdata->unclipped_blend = &_blend_alpha_inv;
+              else if (spdata->type == LinearGradient || spdata->type == RadialGradient)
+                spdata->unclipped_blend = &_blend_gradient_alpha_inv;
+              else //None
+                spdata->unclipped_blend = NULL;
+              break;
+           case EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_ADD:
+              spdata->unclipped_blend = &_blend_mask_add;
+              break;
+           case EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_SUBSTRACT:
+              spdata->unclipped_blend = &_blend_mask_sub;
+              break;
+           case EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_INTERSECT:
+              spdata->unclipped_blend = &_blend_mask_ins;
+              break;
+           case EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_DIFFERENCE:
+              spdata->unclipped_blend = &_blend_mask_diff;
+              break;
+          }
+     }
+   else
+     {
+        if (spdata->type == Solid)
+          spdata->unclipped_blend = &_blend_argb;
+        else if (spdata->type == LinearGradient || spdata->type == RadialGradient)
           spdata->unclipped_blend = &_blend_gradient;
-          break;
+        else //None
+          spdata->unclipped_blend = NULL;
      }
 
   //FIXME: Mask and mask case is not use clipping.