Merge remote-tracking branch 'origin/tizen' into new_text
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / tizen / image-loaders / loader-ico.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * Derived from Enlightenment file evas_image_load_ico.c[1]  which is licensed
19  * under the BSD 2-clause license[2] reproduced below.
20  *
21  * [1][http://web.archive.org/web/20141201151111/http://git.enlightenment.org/core/efl.git/tree/src/modules/evas/loaders/ico/evas_image_load_ico.c]
22  * [2][http://web.archive.org/web/20140717012400/https://git.enlightenment.org/core/efl.git/about/]
23  *
24  * Copyright (C) 2002-2012 Carsten Haitzler, Dan Sinclair, Mike Blumenkrantz,
25  * Samsung Electronics and various contributors (see AUTHORS)
26  *
27  * All rights reserved.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions are met:
31  *
32  *    1. Redistributions of source code must retain the above copyright
33  *       notice, this list of conditions and the following disclaimer.
34  *    2. Redistributions in binary form must reproduce the above copyright
35  *       notice, this list of conditions and the following disclaimer in the
36  *       documentation and/or other materials provided with the distribution.
37  *
38  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
40  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
41  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
42  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
44  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
46  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
47  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 // HEADER
51 #include "loader-ico.h"
52
53 // EXTERNAL INCLUDES
54 #include <cstring>
55 #include <dali/public-api/common/dali-vector.h>
56
57 // INTERNAL INCLUDES
58 #include <dali/integration-api/debug.h>
59 #include <dali/integration-api/bitmap.h>
60 #include <dali/public-api/images/image-attributes.h>
61
62 namespace Dali
63 {
64 using Integration::Bitmap;
65 using Dali::Integration::PixelBuffer;
66
67 namespace TizenPlatform
68 {
69
70 namespace
71 {
72 //reserved 2 bytes + type 2 bytes + count 2 bytes + count * 16 bytes
73 const unsigned char ICO_FILE_HEADER = 22;
74 // info header 40 bytes = size 4 bytes + width 4 bytes + height 4 bytes + planes 2 bytes + bitcount 2 bytes
75 // + compression 4 bytes + imagesize 4 bytes + xpixelsPerM 4 bytes + ypixelsPerM 4 bytes + colorsUsed 4 bytes + colorImportant 4 bytes
76 // besides, there are rgba color data = numberOfColors * 4 bytes
77 const unsigned char ICO_IMAGE_INFO_HEADER = 40;
78
79 typedef unsigned char  DATA8;
80 #define A_VAL(p) (((DATA8 *)(p))[3])
81
82 #define RGB_JOIN(r,g,b) \
83                 (((r) << 16) + ((g) << 8) + (b))
84
85 #define ARGB_JOIN(a,r,g,b) \
86                 (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
87 #define IMG_TOO_BIG(w, h) \
88        ((((unsigned long long)w) * ((unsigned long long)h)) >= \
89            ((1ULL << (29 * (sizeof(void *) / 4))) - 2048))
90
91 bool read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
92 {
93   unsigned char b[2];
94
95   if (*position + 2 > length)
96   {
97     return false;
98   }
99   b[0] = map[(*position)++];
100   b[1] = map[(*position)++];
101   *ret = (b[1] << 8) | b[0];
102   return true;
103 }
104
105 bool read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
106 {
107   unsigned char b[4];
108   unsigned int i;
109
110   if (*position + 4 > length)
111   {
112     return false;
113   }
114   for (i = 0; i < 4; i++)
115   {
116     b[i] = map[(*position)++];
117   }
118   *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
119   return true;
120 }
121
122 bool read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
123 {
124   if (*position + 1 > length)
125   {
126     return false;
127   }
128   *ret = map[(*position)++];
129   return true;
130 }
131
132 bool read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
133 {
134   if (*position + size > length)
135   {
136     return false;
137   }
138   memcpy(buffer, map + *position, size);
139   *position += size;
140   return true;
141 }
142
143 enum
144 {
145   SMALLEST,
146   BIGGEST,
147   SMALLER,
148   BIGGER
149 };
150
151 enum
152 {
153   ICON = 1,
154   CURSOR = 2
155 };
156
157 struct IcoData
158 {
159   int pdelta;
160   int w, h;
161   int cols;
162   int bpp, planes;
163   int hot_x, hot_y;
164   unsigned int bmoffset, bmsize;
165 };
166
167 bool LoadIcoHeaderHelper( FILE* fp,
168                           IcoData& chosen,
169                           Dali::Vector<unsigned char>& map,
170                           unsigned int& fsize )
171 {
172   memset( &chosen, 0, sizeof(chosen) );
173
174   if(fp == NULL)
175   {
176     DALI_LOG_ERROR("Error loading bitmap\n");
177     return false;
178   }
179   size_t position = 0;
180   unsigned short word;
181   unsigned char byte;
182
183   if( fseek(fp,0,SEEK_END) )
184   {
185     DALI_LOG_ERROR("Error seeking ICO data\n");
186     return false;
187   }
188
189   long positionIndicator = ftell(fp);
190   fsize = 0u;
191
192   if( positionIndicator > -1L )
193   {
194     fsize = static_cast<unsigned int>(positionIndicator);
195   }
196
197   if( 0u == fsize )
198   {
199     return false;
200   }
201
202   if( fseek(fp, 0, SEEK_SET) )
203   {
204     DALI_LOG_ERROR("Error seeking ICO data\n");
205     return false;
206   }
207
208   if (fsize < (ICO_FILE_HEADER + ICO_IMAGE_INFO_HEADER)) //6 + 16 + 40
209   {
210     return false;
211   }
212   map.Resize(fsize);
213
214   if(fread(&map[0], 1, fsize, fp) != fsize)
215   {
216     DALI_LOG_WARNING("image file read opeation error!");
217     return false;
218   }
219
220   int search = BIGGEST;
221   unsigned short reserved, type, count;
222   if (!read_ushort(&map[0], fsize, &position, &reserved))
223   {
224     return false;
225   }
226   if (!read_ushort(&map[0], fsize, &position, &type))
227   {
228     return false;
229   }
230   if (!read_ushort(&map[0], fsize, &position, &count))
231   {
232     return false;
233   }
234   if (!((reserved == 0) &&
235        ((type == ICON) || (type == CURSOR)) && (count != 0)))
236   {
237     return false;
238   }
239   search = BIGGEST;
240   chosen.pdelta = 0;
241   bool have_choice = false;
242
243   for (unsigned short i = 0; i < count; i++)
244   {
245     unsigned char tw = 0, th = 0, tcols = 0;
246     if (!read_uchar(&map[0], fsize, &position, &tw))
247     {
248       return false;
249     }
250     int w = tw;
251     if (w <= 0)
252     {
253       w = 256;
254     }
255     if (!read_uchar(&map[0], fsize, &position, &th))
256     {
257       return false;
258
259     }
260     int h = th;
261     if (h <= 0)
262     {
263       h = 256;
264     }
265     if (!read_uchar(&map[0], fsize, &position, &tcols))
266     {
267       return false;
268     }
269     int cols = tcols;
270     if (cols <= 0)
271     {
272       cols = 256;
273     }
274     if (!read_uchar(&map[0], fsize, &position, &byte))
275     {
276       return false;
277     }
278     if (!read_ushort(&map[0], fsize, &position, &word))
279     {
280       return false;
281     }
282     int planes=0;
283     if (type == 1)
284     {
285       planes = word;
286     }
287     //else hot_x = word;
288     if (!read_ushort(&map[0], fsize, &position, &word))
289     {
290       return false;
291     }
292     int bpp=0;
293     if (type == 1)
294     {
295       bpp = word;
296     }
297     //else hot_y = word;
298     unsigned int bmoffset, bmsize;
299     if (!read_uint(&map[0], fsize, &position, &bmsize))
300     {
301       return false;
302     }
303     if (!read_uint(&map[0], fsize, &position, &bmoffset))
304     {
305       return false;
306     }
307     if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize))
308     {
309       return false;
310     }
311     if (search == BIGGEST)
312     {
313       int pdelta = w * h;
314       if ((!have_choice) ||
315        ((pdelta >= chosen.pdelta) &&
316            (((bpp >= 3) && (bpp >= chosen.bpp)) ||
317                ((bpp < 3) && (cols >= chosen.cols)))))
318       {
319         have_choice = true;
320         chosen.pdelta = pdelta;
321         chosen.w = w;
322         chosen.h = h;
323         chosen.cols = cols;
324         chosen.bpp = bpp;
325         chosen.planes = planes;
326         chosen.bmsize = bmsize;
327         chosen.bmoffset = bmoffset;
328       }
329     }
330   }
331
332   if (chosen.bmoffset == 0)
333   {
334     return false;
335   }
336
337   return true;
338 }
339
340 }//unnamed namespace
341
342 bool LoadIcoHeader(FILE *fp, const ImageAttributes& attributes, unsigned int &width, unsigned int &height )
343 {
344   IcoData chosen;
345   Dali::Vector<unsigned char> map;
346   unsigned int fsize;
347
348   if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
349   {
350     return false;
351   }
352
353   width = chosen.w;
354   height = chosen.h;
355
356   return true;
357 }
358
359 bool LoadBitmapFromIco( FILE *fp, Integration::Bitmap& bitmap, ImageAttributes& attributes, const ResourceLoadingClient& client )
360 {
361   IcoData chosen;
362   Dali::Vector<unsigned char> map;
363   unsigned int fsize;
364
365   if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
366   {
367     return false;
368   }
369
370   Dali::Vector<unsigned int> pal;
371   Dali::Vector<unsigned int> surface;
372   Dali::Vector<unsigned char> maskbuf;
373   Dali::Vector<unsigned char> pixbuf;
374   pal.Resize(256 * 4);
375
376   unsigned int dword;
377   unsigned short word;
378
379   int diff_size = 0;
380   unsigned int* pix;
381   PixelBuffer* pixels = NULL;
382
383   size_t position = chosen.bmoffset;//22 == position
384
385   int w = chosen.w;
386   int h = chosen.h;
387   int cols = chosen.cols;
388
389   // read bmp header time... let's do some checking
390   if (!read_uint(&map[0], fsize, &position, &dword))
391   {
392     return false; // headersize - dont care
393   }
394   if (!read_uint(&map[0], fsize, &position, &dword))
395   {
396     return false; // width
397   }
398   if (dword > 0)
399   {
400     if ((int)dword != w)
401     {
402       w = dword;
403       diff_size = 1;
404     }
405   }
406   if (!read_uint(&map[0], fsize, &position, &dword))
407   {
408     return false; // height
409   }
410   if (dword > 0)
411   {
412     if ((int)dword != (h * 2))
413     {
414       h = dword / 2;
415       diff_size = 1;
416     }
417   }
418   if (diff_size)
419   {
420     DALI_LOG_WARNING("Broken ICO file!");
421   }
422   if (!read_ushort(&map[0], fsize, &position, &word))
423   {
424     return false; // planes
425   }
426   //planes2 = word;
427   if (!read_ushort(&map[0], fsize, &position, &word))
428   {
429     return false; // bitcount
430   }
431   unsigned int bitcount = word;
432   if (!read_uint(&map[0], fsize, &position, &dword))
433   {
434     return false; // compression
435   }
436   //compression = dword;
437   if (!read_uint(&map[0], fsize, &position, &dword))
438   {
439     return false; // imagesize
440   }
441   //imagesize = dword;
442   if (!read_uint(&map[0], fsize, &position, &dword))
443   {
444     return false; // z pixels per m
445   }
446   if (!read_uint(&map[0], fsize, &position, &dword))
447   {
448     return false; // y pizels per m
449   }
450   if (!read_uint(&map[0], fsize, &position, &dword))
451   {
452     return false; // colors used
453   }
454   //colorsused = dword;
455   if (!read_uint(&map[0], fsize, &position, &dword))
456   {
457     return false; // colors important
458   }
459   //colorsimportant = dword;
460   surface.Resize(w * h * 4);
461
462   memset(&surface[0], 0, w * h * 4);
463
464   for(int i = 0; i < cols ; i ++)
465   {
466     unsigned char a, r, g, b;
467
468     if (!read_uchar(&map[0], fsize, &position, &b))
469     {
470       return false;
471     }
472     if (!read_uchar(&map[0], fsize, &position, &g))
473     {
474       return false;
475     }
476     if (!read_uchar(&map[0], fsize, &position, &r))
477     {
478       return false;
479     }
480     if (!read_uchar(&map[0], fsize, &position, &a))
481     {
482       return false;
483     }
484     a = 0xff;
485     pal[i] = ARGB_JOIN(a, r, g, b);
486   }
487
488   if (!((bitcount == 1) || (bitcount == 4) || (bitcount == 8) ||
489        (bitcount == 24) || (bitcount == 32)))
490   {
491     return false;
492   }
493   int stride = ((w + 31) / 32);
494
495   maskbuf.Resize(stride * h);
496   pixbuf.Resize(stride * 32 * 4); // more than enough
497
498   unsigned int none_zero_alpha = 0;
499   if (bitcount == 1)
500   {
501     int pstride = stride * 4;
502     for (int i = 0; i < h; i++)
503     {
504       pix = &surface[0] + ((h - 1 - i) * w);
505
506       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
507       {
508         return false;
509       }
510       unsigned char* p = &pixbuf[0];
511       if (i >= (int)h)
512       {
513         continue;
514       }
515       for (int j = 0; j < w; j++)
516       {
517         if (j >= (int)w)
518         {
519           break;
520         }
521         if ((j & 0x7) == 0x0)
522         {
523           *pix = pal[*p >> 7];
524         }
525         else if ((j & 0x7) == 0x1)
526         {
527           *pix = pal[(*p >> 6) & 0x1];
528         }
529         else if ((j & 0x7) == 0x2)
530         {
531           *pix = pal[(*p >> 5) & 0x1];
532         }
533         else if ((j & 0x7) == 0x3)
534         {
535           *pix = pal[(*p >> 4) & 0x1];
536         }
537         else if ((j & 0x7) == 0x4)
538         {
539           *pix = pal[(*p >> 3) & 0x1];
540         }
541         else if ((j & 0x7) == 0x5)
542         {
543           *pix = pal[(*p >> 2) & 0x1];
544         }
545         else if ((j & 0x7) == 0x6)
546         {
547           *pix = pal[(*p >> 1) & 0x1];
548         }
549         else
550         {
551           *pix = pal[*p & 0x1];
552           p++;
553         }
554         pix++;
555       }
556     }
557   }
558   else if (bitcount == 4)
559   {
560     int pstride = ((w + 7) / 8) * 4;
561     for (int i = 0; i < h; i++)
562     {
563       pix = &surface[0] + ((h - 1 - i) * w);
564
565       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
566       {
567         return false;
568       }
569       unsigned char* p = &pixbuf[0];
570       if (i >= (int)h)
571       {
572         continue;
573       }
574       for (int j = 0; j < w; j++)
575       {
576         if (j >= (int)w)
577         {
578           break;
579         }
580         if ((j & 0x1) == 0x1)
581         {
582           *pix = pal[*p & 0x0f];
583           p++;
584         }
585         else
586         {
587           *pix = pal[*p >> 4];
588         }
589         pix++;
590       }
591     }
592   }
593   else if (bitcount == 8)
594   {
595     int pstride = ((w + 3) / 4) * 4;
596     for (int i = 0; i < h; i++)
597     {
598       pix = &surface[0] + ((h - 1 - i) * w);
599
600       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
601       {
602         return false;
603       }
604       unsigned char* p = &pixbuf[0];
605       if (i >= (int)h)
606       {
607         continue;
608       }
609       for (int j = 0; j < w; j++)
610       {
611         if (j >= (int)w)
612         {
613           break;
614         }
615         *pix = pal[*p];
616         p++;
617         pix++;
618       }
619     }
620   }
621   else if (bitcount == 24)
622   {
623     int pstride = w * 3;
624     for (int i = 0; i < h; i++)
625     {
626       pix = &surface[0] + ((h - 1 - i) * w);
627
628       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
629       {
630         return false;
631       }
632       unsigned char* p = &pixbuf[0];
633       if (i >= (int)h)
634       {
635         continue;
636       }
637       for (int j = 0; j < w; j++)
638       {
639         unsigned char a, r, g, b;
640
641         if (j >= (int)w)
642         {
643           break;
644         }
645         b = p[0];
646         g = p[1];
647         r = p[2];
648         p += 3;
649         a = 0xff;
650         *pix = ARGB_JOIN(a, r, g, b);
651         pix++;
652       }
653     }
654   }
655   else if (bitcount == 32)
656   {
657     int pstride = w * 4;
658     for (int i = 0; i < h; i++)
659     {
660       pix = &surface[0] + ((h - 1 - i) * w);
661
662       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
663       {
664         return false;
665       }
666       unsigned char* p = &pixbuf[0];
667       if (i >= (int)h)
668       {
669         continue;
670       }
671       for (int j = 0; j < w; j++)
672       {
673         unsigned char a, r, g, b;
674         if (j >= (int)w)
675         {
676           break;
677         }
678         b = p[0];
679         g = p[1];
680         r = p[2];
681         a = p[3];
682         p += 4;
683         if (a)
684         {
685           none_zero_alpha = 1;
686         }
687         *pix = ARGB_JOIN(a, r, g, b);
688         pix++;
689       }
690     }
691   }
692   if (!none_zero_alpha)
693   {
694     if (!read_mem(&map[0], fsize, &position, &maskbuf[0], stride * 4 * h))
695     {
696       return false;
697     }
698     // apply mask
699     for (int i = 0; i < h; i++)
700     {
701       unsigned char *m;
702
703       pix = &surface[0] + ((h - 1 - i) * w);
704
705       m = &maskbuf[0] + (stride * i * 4);
706       if (i >= (int)h)
707       {
708         continue;
709       }
710       for (int j = 0; j < w; j++)
711       {
712         if (j >= (int)w)
713         {
714           break;
715         }
716         if (*m & (1 << (7 - (j & 0x7))))
717         {
718           A_VAL(pix) = 0x00;
719         }
720         else
721         {
722           A_VAL(pix) = 0xff;
723         }
724         if ((j & 0x7) == 0x7)
725         {
726           m++;
727         }
728         pix++;
729       }
730     }
731   }
732   pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGBA8888, w, h);
733   memset(pixels, 0, w * h * 4);
734   memcpy(pixels, (unsigned char*)&surface[0], w * h * 4);
735
736   attributes.SetSize(w, h);
737
738   return true;
739 }
740
741 }
742
743 }