1 /*
2    (c) Copyright 2001-2010  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    All rights reserved.
14 
15    This file is subject to the terms and conditions of the MIT License:
16 
17    Permission is hereby granted, free of charge, to any person
18    obtaining a copy of this software and associated documentation
19    files (the "Software"), to deal in the Software without restriction,
20    including without limitation the rights to use, copy, modify, merge,
21    publish, distribute, sublicense, and/or sell copies of the Software,
22    and to permit persons to whom the Software is furnished to do so,
23    subject to the following conditions:
24 
25    The above copyright notice and this permission notice shall be
26    included in all copies or substantial portions of the Software.
27 
28    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
31    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
32    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
33    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
34    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 */
36 
37 #include <config.h>
38 
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <sys/mman.h>
42 #include <sys/stat.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <stdarg.h>
46 
47 #include <directfb.h>
48 
49 #include <direct/debug.h>
50 #include <direct/interface.h>
51 #include <direct/messages.h>
52 #include <direct/util.h>
53 
54 #include <idirectfb.h>
55 
56 #include <display/idirectfbsurface.h>
57 
58 #include <misc/gfx_util.h>
59 
60 #include <media/idirectfbdatabuffer.h>
61 #include <media/idirectfbimageprovider.h>
62 
63 #include <dfiff.h>
64 
65 static DFBResult
66 Probe( IDirectFBImageProvider_ProbeContext *ctx );
67 
68 static DFBResult
69 Construct( IDirectFBImageProvider *thiz,
70            ... );
71 
72 #include <direct/interface_implementation.h>
73 
74 DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBImageProvider, DFIFF )
75 
76 
77 /*
78  * private data struct of IDirectFBImageProvider_DFIFF
79  */
80 typedef struct {
81      IDirectFBImageProvider_data base;
82 
83      void                *ptr;     /* pointer to raw file data (mapped) */
84      int                  len;     /* data length, i.e. file size */
85 } IDirectFBImageProvider_DFIFF_data;
86 
87 
88 
89 
90 
91 static void
IDirectFBImageProvider_DFIFF_Destruct(IDirectFBImageProvider * thiz)92 IDirectFBImageProvider_DFIFF_Destruct( IDirectFBImageProvider *thiz )
93 {
94      IDirectFBImageProvider_DFIFF_data *data = thiz->priv;
95 
96      munmap( data->ptr, data->len );
97 }
98 
99 static DFBResult
IDirectFBImageProvider_DFIFF_RenderTo(IDirectFBImageProvider * thiz,IDirectFBSurface * destination,const DFBRectangle * dest_rect)100 IDirectFBImageProvider_DFIFF_RenderTo( IDirectFBImageProvider *thiz,
101                                        IDirectFBSurface       *destination,
102                                        const DFBRectangle     *dest_rect )
103 {
104      DFBResult              ret;
105      IDirectFBSurface_data *dst_data;
106      CoreSurface           *dst_surface;
107      const DFIFFHeader     *header;
108      DFBRectangle           rect;
109      DFBRectangle           clipped;
110 
111      DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_DFIFF)
112 
113      if (!destination)
114           return DFB_INVARG;
115 
116      DIRECT_INTERFACE_GET_DATA_FROM (destination, dst_data, IDirectFBSurface);
117 
118      dst_surface = dst_data->surface;
119      if (!dst_surface)
120           return DFB_DEAD;
121 
122      if (dest_rect) {
123           rect.x = dest_rect->x + dst_data->area.wanted.x;
124           rect.y = dest_rect->y + dst_data->area.wanted.y;
125           rect.w = dest_rect->w;
126           rect.h = dest_rect->h;
127      }
128      else
129           rect = dst_data->area.wanted;
130 
131      if (rect.w < 1 || rect.h < 1)
132           return DFB_INVAREA;
133 
134      clipped = rect;
135 
136      if (!dfb_rectangle_intersect( &clipped, &dst_data->area.current ))
137           return DFB_INVAREA;
138 
139      header = data->ptr;
140 
141      if (DFB_RECTANGLE_EQUAL( rect, clipped ) &&
142          (unsigned)rect.w == header->width && (unsigned)rect.h == header->height &&
143          dst_surface->config.format == header->format)
144      {
145           ret = dfb_surface_write_buffer( dst_surface, CSBR_BACK,
146                                           (u8*)data->ptr + sizeof(DFIFFHeader), header->pitch, &rect );
147           if (ret)
148                return ret;
149      }
150      else {
151           IDirectFBSurface      *source;
152           DFBSurfaceDescription  desc;
153           DFBSurfaceCapabilities caps;
154           DFBRegion              clip = DFB_REGION_INIT_FROM_RECTANGLE( &clipped );
155           DFBRegion              old_clip;
156 
157           thiz->GetSurfaceDescription( thiz, &desc );
158 
159           desc.flags |= DSDESC_PREALLOCATED;
160           desc.preallocated[0].data  = (u8*)data->ptr + sizeof(DFIFFHeader);
161           desc.preallocated[0].pitch = header->pitch;
162 
163           ret = idirectfb_singleton->CreateSurface( idirectfb_singleton, &desc, &source );
164           if (ret)
165                return ret;
166 
167           destination->GetCapabilities( destination, &caps );
168 
169           if (caps & DSCAPS_PREMULTIPLIED && DFB_PIXELFORMAT_HAS_ALPHA(desc.pixelformat))
170                destination->SetBlittingFlags( destination, DSBLIT_SRC_PREMULTIPLY );
171           else
172                destination->SetBlittingFlags( destination, DSBLIT_NOFX );
173 
174           destination->GetClip( destination, &old_clip );
175           destination->SetClip( destination, &clip );
176 
177           destination->StretchBlit( destination, source, NULL, &rect );
178 
179           destination->SetClip( destination, &old_clip );
180 
181           destination->SetBlittingFlags( destination, DSBLIT_NOFX );
182 
183           destination->ReleaseSource( destination );
184 
185           source->Release( source );
186      }
187 
188      if (data->base.render_callback) {
189           DFBRectangle rect = { 0, 0, clipped.w, clipped.h };
190           data->base.render_callback( &rect,
191                                       data->base.render_callback_context );
192      }
193 
194      return DFB_OK;
195 }
196 
197 /* Loading routines */
198 
199 static DFBResult
IDirectFBImageProvider_DFIFF_GetSurfaceDescription(IDirectFBImageProvider * thiz,DFBSurfaceDescription * dsc)200 IDirectFBImageProvider_DFIFF_GetSurfaceDescription( IDirectFBImageProvider *thiz,
201                                                     DFBSurfaceDescription *dsc )
202 {
203      const DFIFFHeader *header;
204 
205      DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_DFIFF)
206 
207      header = data->ptr;
208 
209      dsc->flags       = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
210      dsc->width       = header->width;
211      dsc->height      = header->height;
212      dsc->pixelformat = header->format;
213 
214      return DFB_OK;
215 }
216 
217 static DFBResult
IDirectFBImageProvider_DFIFF_GetImageDescription(IDirectFBImageProvider * thiz,DFBImageDescription * desc)218 IDirectFBImageProvider_DFIFF_GetImageDescription( IDirectFBImageProvider *thiz,
219                                                   DFBImageDescription    *desc )
220 {
221      const DFIFFHeader *header;
222 
223      DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_DFIFF)
224 
225      if (!desc)
226           return DFB_INVARG;
227 
228      header = data->ptr;
229 
230      desc->caps = DICAPS_NONE;
231 
232      if (DFB_PIXELFORMAT_HAS_ALPHA( header->format ))
233           desc->caps |= DICAPS_ALPHACHANNEL;
234 
235      return DFB_OK;
236 }
237 
238 
239 
240 static DFBResult
Probe(IDirectFBImageProvider_ProbeContext * ctx)241 Probe( IDirectFBImageProvider_ProbeContext *ctx )
242 {
243      if (!strncmp( (const char*) ctx->header, "DFIFF", 5 ))
244           return DFB_OK;
245 
246      return DFB_UNSUPPORTED;
247 }
248 
249 static DFBResult
Construct(IDirectFBImageProvider * thiz,...)250 Construct( IDirectFBImageProvider *thiz,
251            ... )
252 {
253      DFBResult                 ret;
254      struct stat               stat;
255      void                     *ptr;
256      int                       fd = -1;
257      IDirectFBDataBuffer_data *buffer_data;
258 
259      IDirectFBDataBuffer *buffer;
260      CoreDFB             *core;
261      va_list              tag;
262 
263      DIRECT_ALLOCATE_INTERFACE_DATA(thiz, IDirectFBImageProvider_DFIFF)
264 
265      va_start( tag, thiz );
266      buffer = va_arg( tag, IDirectFBDataBuffer * );
267      core = va_arg( tag, CoreDFB * );
268      va_end( tag );
269 
270      D_MAGIC_ASSERT( (IAny*) buffer, DirectInterface );
271 
272      /* Get the buffer's private data. */
273      buffer_data = buffer->priv;
274      if (!buffer_data) {
275           ret = DFB_DEAD;
276           goto error;
277      }
278 
279      /* Check for valid filename. */
280      if (!buffer_data->filename) {
281           ret = DFB_UNSUPPORTED;
282           goto error;
283      }
284 
285      /* Open the file. */
286      fd = open( buffer_data->filename, O_RDONLY );
287      if (fd < 0) {
288           ret = errno2result( errno );
289           D_PERROR( "ImageProvider/DFIFF: Failure during open() of '%s'!\n", buffer_data->filename );
290           goto error;
291      }
292 
293      /* Query file size etc. */
294      if (fstat( fd, &stat ) < 0) {
295           ret = errno2result( errno );
296           D_PERROR( "ImageProvider/DFIFF: Failure during fstat() of '%s'!\n", buffer_data->filename );
297           goto error;
298      }
299 
300      /* Memory map the file. */
301      ptr = mmap( NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0 );
302      if (ptr == MAP_FAILED) {
303           ret = errno2result( errno );
304           D_PERROR( "ImageProvider/DFIFF: Failure during mmap() of '%s'!\n", buffer_data->filename );
305           goto error;
306      }
307 
308      /* Already close, we still have the map. */
309      close( fd );
310 
311      data->base.ref = 1;
312      data->base.core = core;
313 
314      data->ptr = ptr;
315      data->len = stat.st_size;
316 
317      data->base.Destruct = IDirectFBImageProvider_DFIFF_Destruct;
318 
319      thiz->RenderTo              = IDirectFBImageProvider_DFIFF_RenderTo;
320      thiz->GetImageDescription   = IDirectFBImageProvider_DFIFF_GetImageDescription;
321      thiz->GetSurfaceDescription = IDirectFBImageProvider_DFIFF_GetSurfaceDescription;
322 
323      return DFB_OK;
324 
325 error:
326      if (fd != -1)
327           close( fd );
328 
329      DIRECT_DEALLOCATE_INTERFACE(thiz);
330 
331      return ret;
332 }
333 
334