static DFBResult
IDirectFBImageProvider_GIF_RenderTo( IDirectFBImageProvider *thiz,
                                     IDirectFBSurface       *destination,
                                     const DFBRectangle     *dest_rect )
{
     DFBResult              ret;
     DFBRegion              clip;
     DFBRectangle           rect;
     DFBSurfacePixelFormat  format;
     IDirectFBSurface_data *dst_data;
     CoreSurface           *dst_surface;

     DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_GIF)

     dst_data = (IDirectFBSurface_data*) destination->priv;
     if (!dst_data)
          return DFB_DEAD;

     dst_surface = dst_data->surface;
     if (!dst_surface)
          return DFB_DESTROYED;

     dfb_region_from_rectangle( &clip, &dst_data->area.current );

     if (dest_rect) {
          if (dest_rect->w < 1 || dest_rect->h < 1)
               return DFB_INVARG;
          rect = *dest_rect;
          rect.x += dst_data->area.wanted.x;
          rect.y += dst_data->area.wanted.y;
     }
     else {
          rect = dst_data->area.wanted;
     }

     ret = destination->GetPixelFormat( destination, &format );
     if (ret)
          return ret;

     /* actual loading and rendering */
     if (dfb_rectangle_region_intersects( &rect, &clip )) {
          CoreSurfaceBufferLock lock;

          ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
          if (ret)
               return ret;

          dfb_scale_linear_32( data->image, data->image_width, data->image_height,
                               lock.addr, lock.pitch, &rect, dst_surface, &clip );

          dfb_surface_unlock_buffer( dst_surface, &lock );

          if (data->base.render_callback) {
               DIRenderCallbackResult r;

               rect.x = 0;
               rect.y = 0;
               rect.w = data->image_width;
               rect.h = data->image_height;

               r = data->base.render_callback( &rect,
                                               data->base.render_callback_context );

               if (r != DIRCR_OK)
                       return DFB_INTERRUPTED;
          }
     }

     return DFB_OK;
}
static DFBResult
IDirectFBImageProvider_JPEG2000_RenderTo( IDirectFBImageProvider *thiz,
                                          IDirectFBSurface       *destination,
                                          const DFBRectangle     *dest_rect )
{
     IDirectFBSurface_data  *dst_data;
     CoreSurface            *dst_surface;
     CoreSurfaceBufferLock   lock;
     DFBRectangle            rect;
     DFBRegion               clip;
     DIRenderCallbackResult  cb_result = DIRCR_OK;
     DFBResult               ret       = DFB_OK;
     
     DIRECT_INTERFACE_GET_DATA( IDirectFBImageProvider_JPEG2000 )
     
     if (!destination)
          return DFB_INVARG;
          
     dst_data = destination->priv;
     if (!dst_data || !dst_data->surface)
          return DFB_DESTROYED;
          
     dst_surface = dst_data->surface;
     
     if (dest_rect) {
          if (dest_rect->w < 1 || dest_rect->h < 1)
               return DFB_INVARG;
          rect = *dest_rect;
          rect.x += dst_data->area.wanted.x;
          rect.y += dst_data->area.wanted.y;
     }
     else {
          rect = dst_data->area.wanted;
     }
     
     dfb_region_from_rectangle( &clip, &dst_data->area.current );
     if (!dfb_rectangle_region_intersects( &rect, &clip ))
          return DFB_OK;

     ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
     if (ret)
          return ret;
     
     if (!data->buf) {
          int  cmptlut[3];
          int  width, height;
          int  tlx, tly;
          int  hs, vs;
          int  i, j;
          bool direct, mono;
     
          if (jas_image_numcmpts(data->image) > 1) {
               cmptlut[0] = jas_image_getcmptbytype(data->image,
                              JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
               cmptlut[1] = jas_image_getcmptbytype(data->image,
                              JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
               cmptlut[2] = jas_image_getcmptbytype(data->image,
                              JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
               if (cmptlut[0] < 0 || cmptlut[1] < 0 || cmptlut[2] < 0) {
                    dfb_surface_unlock_buffer( dst_surface, &lock );
                    return DFB_UNSUPPORTED;
               }
               mono = false;
          }
          else {
               cmptlut[0] = cmptlut[1] = cmptlut[2] = 0;
               mono = true;
          }
     
          width = jas_image_width(data->image);
          height = jas_image_height(data->image);
          tlx = jas_image_cmpttlx(data->image, 0);
          tly = jas_image_cmpttly(data->image, 0);
          hs = jas_image_cmpthstep(data->image, 0);
          vs = jas_image_cmptvstep(data->image, 0);
          
          data->buf = D_MALLOC( width*height*4 );
          if (!data->buf) {
               dfb_surface_unlock_buffer( dst_surface, &lock );
               return D_OOM();
          }
          
          direct = (rect.w == width && rect.h == height && data->render_callback);
          
#define GET_SAMPLE( n, x, y ) ({ \
     int _s; \
     _s = jas_image_readcmptsample(data->image, cmptlut[n], x, y); \
     _s >>= jas_image_cmptprec(data->image, cmptlut[n]) - 8; \
     if (_s > 255) \
          _s = 255; \
     else if (_s < 0) \
          _s = 0; \
     _s; \
})
            
          for (i = 0; i < height; i++) {
               u32 *dst = data->buf + i * width;
               int  x, y;
               
               y = (i - tly) / vs;
               if (y >= 0 && y < height) {     
                    for (j = 0; j < width; j++) {
                         x = (j - tlx) / hs;
                         if (x >= 0 && x < width) {
                              unsigned int r, g, b;
                              if (mono) {
                                   r = g = b = GET_SAMPLE(0, x, y);
                              }
                              else {
                                   r = GET_SAMPLE(0, x, y);
                                   g = GET_SAMPLE(1, x, y);
                                   b = GET_SAMPLE(2, x, y);
                              }
                              *dst++ = 0xff000000 | (r << 16) | (g << 8) | b;
                         }
                         else {
                              *dst++ = 0;
                         }
                    }
               }
               else {
                    memset( dst, 0, width*4 );
               }
               
               if (direct) {
                    DFBRectangle r = { rect.x, rect.y+i, width, 1 };
                    
                    dfb_copy_buffer_32( data->buf + i*width,
                                        lock.addr, lock.pitch, &r, dst_surface, &clip );
                    
                    if (data->render_callback) {                    
                         r = (DFBRectangle) { 0, i, width, 1 };
                         cb_result = data->render_callback( &r, data->render_callback_ctx );
                         if (cb_result != DIRCR_OK)
                              break;
                    }
               }
          }
          
          if (!direct) {
               dfb_scale_linear_32( data->buf, width, height,
                                    lock.addr, lock.pitch, &rect, dst_surface, &clip );

               if (data->render_callback) {
                    DFBRectangle r = { 0, 0, width, height };
                    data->render_callback( &r, data->render_callback_ctx );
               }
          }
          
          if (cb_result != DIRCR_OK) {
               D_FREE( data->buf );
               data->buf = NULL;
               ret = DFB_INTERRUPTED;
          }
     }
     else {
          int width  = jas_image_width(data->image);
          int height = jas_image_height(data->image);
          
          dfb_scale_linear_32( data->buf, width, height,
                               lock.addr, lock.pitch, &rect, dst_surface, &clip );
          
          if (data->render_callback) {
               DFBRectangle r = {0, 0, width, height};
               data->render_callback( &r, data->render_callback_ctx );
          }
     }
     
     dfb_surface_unlock_buffer( dst_surface, &lock );
     
     return ret;
}
static DFBResult
IDirectFBImageProvider_ANDROID_RenderTo( IDirectFBImageProvider *thiz,
                                         IDirectFBSurface       *destination,
                                         const DFBRectangle     *dest_rect )
{
     DFBResult              ret;
     bool                   direct = false;
     DFBRegion              clip;
     DFBRectangle           rect;
     DFBSurfacePixelFormat  format;
     IDirectFBSurface_data *dst_data;
     CoreSurface           *dst_surface;
     CoreSurfaceBufferLock  lock;
     DIRenderCallbackResult cb_result = DIRCR_OK;

     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_ANDROID)

     dst_data = (IDirectFBSurface_data*) destination->priv;
     if (!dst_data)
          return DFB_DEAD;

     dst_surface = dst_data->surface;
     if (!dst_surface)
          return DFB_DESTROYED;

     ret = decodeImage( data );
     if (ret)
          return ret;

     ret = destination->GetPixelFormat( destination, &format );
     if (ret)
          return ret;

     dfb_region_from_rectangle( &clip, &dst_data->area.current );

     if (dest_rect) {
          if (dest_rect->w < 1 || dest_rect->h < 1)
               return DFB_INVARG;

          rect = *dest_rect;
          rect.x += dst_data->area.wanted.x;
          rect.y += dst_data->area.wanted.y;

          if (!dfb_rectangle_region_intersects( &rect, &clip ))
               return DFB_OK;
     }
     else {
          rect = dst_data->area.wanted;
     }

     ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
     if (ret)
          return ret;

     dfb_scale_linear_32( (u32 *)data->image, data->width, data->height, lock.addr, lock.pitch, &rect, dst_surface, &clip );
     if (data->base.render_callback) {
          DFBRectangle r = { 0, 0, data->width, data->height };
          data->base.render_callback( &r, data->base.render_callback_context );
     }

     dfb_surface_unlock_buffer( dst_surface, &lock );

     return DFB_OK;
}
static DFBResult
IDirectFBImageProvider_MPEG2_RenderTo( IDirectFBImageProvider *thiz,
                                       IDirectFBSurface       *destination,
                                       const DFBRectangle     *dest_rect )
{
     DFBResult              ret;
     IDirectFBSurface_data *dst_data;
     CoreSurface           *dst_surface;
     DFBRegion              clip;
     DFBRectangle           rect;

     DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_MPEG2)

     dst_data = (IDirectFBSurface_data*) destination->priv;
     if (!dst_data)
          return DFB_DEAD;

     dst_surface = dst_data->surface;
     if (!dst_surface)
          return DFB_DESTROYED;

     dfb_region_from_rectangle( &clip, &dst_data->area.current );

     if (dest_rect) {
          if (dest_rect->w < 1 || dest_rect->h < 1)
               return DFB_INVARG;
          rect = *dest_rect;
          rect.w += dst_data->area.wanted.w;
          rect.h += dst_data->area.wanted.h;
     }
     else {
          rect = dst_data->area.wanted;
     }

     switch (data->stage) {
          case STAGE_END:
               break;
          case STAGE_IMAGE:
               if (MPEG2_Decode( data->dec, mpeg2_write_func, data )) {
                    data->stage = STAGE_ERROR;
                    return DFB_FAILURE;
               }
               data->stage = STAGE_END;
               break;
          default:
               return DFB_FAILURE;
     }

     /* actual rendering */
     if (dfb_rectangle_region_intersects( &rect, &clip )) {
          CoreSurfaceBufferLock lock;

          ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
          if (ret)
               return ret;

          dfb_scale_linear_32( data->image, data->width, data->height,
                               lock.addr, lock.pitch, &rect, dst_surface, &clip );

          dfb_surface_unlock_buffer( dst_surface, &lock );
     }

     return DFB_OK;
}
static DFBResult
IDirectFBImageProvider_WebP_RenderTo( IDirectFBImageProvider *thiz,
                                      IDirectFBSurface       *destination,
                                      const DFBRectangle     *dest_rect )
{
     DFBResult               ret;

     DFBRegion               clip;
     CoreSurface            *dst_surface;
     CardState               state;

     CoreSurfaceBufferLock   lock;

     IDirectFBSurface_data  *dst_data;
     DIRenderCallbackResult  cb_result = DIRCR_OK;

     DFBRectangle           src_rect;
     DFBRectangle           rect;

     DIRECT_INTERFACE_GET_DATA( IDirectFBImageProvider_WebP )

     if (!destination)
          return DFB_INVARG;

     dst_data = destination->priv;
     if (!dst_data || !dst_data->surface)
          return DFB_DESTROYED;

     dst_surface = dst_data->surface;

     if (dest_rect) {
          if (dest_rect->w < 1 || dest_rect->h < 1)
               return DFB_INVARG;

          rect = *dest_rect;
          rect.x += dst_data->area.wanted.x;
          rect.y += dst_data->area.wanted.y;
     }
     else {
          rect = dst_data->area.wanted;
     }

     dfb_region_from_rectangle( &clip, &dst_data->area.current );
     if (!dfb_rectangle_region_intersects( &rect, &clip ))
          return DFB_OK;


     ret = dfb_surface_create_simple( data->base.core, data->width, data->height, data->pixelformat,
                                      DSCS_RGB, DSCAPS_NONE, CSTF_NONE,
                                      0, NULL, &data->decode_surface );
     if (ret) {
          D_ERROR( "Failed to create surface : '%s'\n", DirectResultString(ret) );
          goto error;
     }

     ret = dfb_surface_lock_buffer( data->decode_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
     if (ret) {
          D_ERROR( "Failed to lock the surface : '%s'\n", DirectResultString(ret) );
          goto error;
     }

     ret = WebP_decode_image( data, &lock );
     if (ret) {
          D_ERROR( "Failed to decode the image : '%s'\n", DirectResultString(ret) );
          goto error;
     }

     dfb_surface_unlock_buffer( data->decode_surface, &lock );

     dfb_state_init( &state, data->base.core );

     state.modified |= SMF_CLIP;

     state.clip =  DFB_REGION_INIT_FROM_RECTANGLE_VALS( rect.x, rect.y, rect.w, rect.h );
     src_rect = (DFBRectangle){0, 0, data->width, data->height};

     dfb_state_set_source( &state, data->decode_surface );
     dfb_state_set_destination( &state, dst_surface );

     dfb_gfxcard_batchstretchblit( &src_rect, &rect, 1, &state );

     data->serial = &state.serial;

     dfb_state_set_source(&state, NULL);
     dfb_state_set_destination(&state, NULL);

     dfb_state_destroy(&state);

     if (data->base.render_callback) {
          DFBRectangle r = { 0, 0, data->width, data->height };
          cb_result=data->base.render_callback( &r, data->base.render_callback_context );
     }

     if (cb_result == DIRCR_OK) {
          data->base.buffer->Release( data->base.buffer );
          data->base.buffer = NULL;
     }

     return DFB_OK;

error:
     if (data->decode_surface && lock.pitch)
          dfb_surface_unlock_buffer( data->decode_surface, &lock );

     dfb_surface_unref( data->decode_surface );

     data->base.buffer->Release( data->base.buffer );
     data->base.buffer = NULL;

     return ret;
}