• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 ** GNU General Public License for more details.
11 */
12 #include "android/skin/file.h"
13 #include "android/utils/path.h"
14 #include "android/charmap.h"
15 #include "android/utils/bufprint.h"
16 #include "android/utils/system.h"
17 #include "android/utils/debug.h"
18 
19 //#include "qemu-common.h"
20 
21 /** UTILITY ROUTINES
22  **/
23 static SkinImage*
skin_image_find_in(const char * dirname,const char * filename)24 skin_image_find_in( const char*  dirname, const char*  filename )
25 {
26     char   buffer[1024];
27     char*  p   = buffer;
28     char*  end = p + sizeof(buffer);
29 
30     p = bufprint( p, end, "%s" PATH_SEP "%s", dirname, filename );
31     if (p >= end)
32         return SKIN_IMAGE_NONE;
33 
34     return skin_image_find_simple(buffer);
35 }
36 
37 /** SKIN BACKGROUND
38  **/
39 
40 static void
skin_background_done(SkinBackground * background)41 skin_background_done( SkinBackground*  background )
42 {
43     if (background->image)
44         skin_image_unref(&background->image);
45 }
46 
47 static int
skin_background_init_from(SkinBackground * background,AConfig * node,const char * basepath)48 skin_background_init_from( SkinBackground*  background,
49                            AConfig*         node,
50                            const char*      basepath )
51 {
52     const char* img = aconfig_str(node, "image", NULL);
53     int         x   = aconfig_int(node, "x", 0);
54     int         y   = aconfig_int(node, "y", 0);
55 
56     background->valid = 0;
57 
58     if (img == NULL)   /* no background */
59         return -1;
60 
61     background->image = skin_image_find_in( basepath, img );
62     if (background->image == SKIN_IMAGE_NONE) {
63         background->image = NULL;
64         return -1;
65     }
66 
67     background->rect.pos.x  = x;
68     background->rect.pos.y  = y;
69     background->rect.size.w = skin_image_w( background->image );
70     background->rect.size.h = skin_image_h( background->image );
71 
72     background->valid = 1;
73 
74     return 0;
75 }
76 
77 /** SKIN DISPLAY
78  **/
79 
80 static void
skin_display_done(SkinDisplay * display)81 skin_display_done( SkinDisplay*  display )
82 {
83     qframebuffer_done( display->qfbuff );
84 }
85 
86 static int
skin_display_init_from(SkinDisplay * display,AConfig * node)87 skin_display_init_from( SkinDisplay*  display, AConfig*  node )
88 {
89     display->rect.pos.x  = aconfig_int(node, "x", 0);
90     display->rect.pos.y  = aconfig_int(node, "y", 0);
91     display->rect.size.w = aconfig_int(node, "width", 0);
92     display->rect.size.h = aconfig_int(node, "height", 0);
93     display->rotation    = aconfig_unsigned(node, "rotation", SKIN_ROTATION_0);
94     display->bpp         = aconfig_int(node, "bpp", 16);
95 
96     display->valid = ( display->rect.size.w > 0 && display->rect.size.h > 0 );
97 
98     if (display->valid) {
99         SkinRect  r;
100         skin_rect_rotate( &r, &display->rect, -display->rotation );
101         qframebuffer_init( display->qfbuff,
102                            r.size.w,
103                            r.size.h,
104                            0,
105                            display->bpp == 32 ? QFRAME_BUFFER_RGBX_8888
106                                               : QFRAME_BUFFER_RGB565 );
107 
108         qframebuffer_fifo_add( display->qfbuff );
109     }
110     return display->valid ? 0 : -1;
111 }
112 
113 /** SKIN BUTTON
114  **/
115 
116 typedef struct
117 {
118     const char*     name;
119     AndroidKeyCode  code;
120 } KeyInfo;
121 
122 static KeyInfo  _keyinfo_table[] = {
123     { "dpad-up",      kKeyCodeDpadUp },
124     { "dpad-down",    kKeyCodeDpadDown },
125     { "dpad-left",    kKeyCodeDpadLeft },
126     { "dpad-right",   kKeyCodeDpadRight },
127     { "dpad-center",  kKeyCodeDpadCenter },
128     { "soft-left",    kKeyCodeSoftLeft },
129     { "soft-right",   kKeyCodeSoftRight },
130     { "search",       kKeyCodeSearch },
131     { "camera",       kKeyCodeCamera },
132     { "volume-up",    kKeyCodeVolumeUp },
133     { "volume-down",  kKeyCodeVolumeDown },
134     { "power",        kKeyCodePower },
135     { "home",         kKeyCodeHome },
136     { "back",         kKeyCodeBack },
137     { "del",          kKeyCodeDel },
138     { "0",            kKeyCode0 },
139     { "1",            kKeyCode1 },
140     { "2",            kKeyCode2 },
141     { "3",            kKeyCode3 },
142     { "4",            kKeyCode4 },
143     { "5",            kKeyCode5 },
144     { "6",            kKeyCode6 },
145     { "7",            kKeyCode7 },
146     { "8",            kKeyCode8 },
147     { "9",            kKeyCode9 },
148     { "star",         kKeyCodeStar },
149     { "pound",        kKeyCodePound },
150     { "phone-dial",   kKeyCodeCall },
151     { "phone-hangup", kKeyCodeEndCall },
152     { "q",            kKeyCodeQ },
153     { "w",            kKeyCodeW },
154     { "e",            kKeyCodeE },
155     { "r",            kKeyCodeR },
156     { "t",            kKeyCodeT },
157     { "y",            kKeyCodeY },
158     { "u",            kKeyCodeU },
159     { "i",            kKeyCodeI },
160     { "o",            kKeyCodeO },
161     { "p",            kKeyCodeP },
162     { "a",            kKeyCodeA },
163     { "s",            kKeyCodeS },
164     { "d",            kKeyCodeD },
165     { "f",            kKeyCodeF },
166     { "g",            kKeyCodeG },
167     { "h",            kKeyCodeH },
168     { "j",            kKeyCodeJ },
169     { "k",            kKeyCodeK },
170     { "l",            kKeyCodeL },
171     { "DEL",          kKeyCodeDel },
172     { "z",            kKeyCodeZ },
173     { "x",            kKeyCodeX },
174     { "c",            kKeyCodeC },
175     { "v",            kKeyCodeV },
176     { "b",            kKeyCodeB },
177     { "n",            kKeyCodeN },
178     { "m",            kKeyCodeM },
179     { "COMMA",        kKeyCodeComma },
180     { "PERIOD",       kKeyCodePeriod },
181     { "ENTER",        kKeyCodeNewline },
182     { "AT",           kKeyCodeAt },
183     { "SPACE",        kKeyCodeSpace },
184     { "SLASH",        kKeyCodeSlash },
185     { "CAP",          kKeyCodeCapLeft },
186     { "SYM",          kKeyCodeSym },
187     { "ALT",          kKeyCodeAltLeft },
188     { "ALT2",         kKeyCodeAltRight },
189     { "CAP2",         kKeyCodeCapRight },
190     { "tv",           kKeyCodeTV },
191     { "epg",          kKeyCodeEPG },
192     { "dvr",          kKeyCodeDVR },
193     { "prev",         kKeyCodePrevious },
194     { "next",         kKeyCodeNext },
195     { "play",         kKeyCodePlay },
196     { "pause",        kKeyCodePause },
197     { "stop",         kKeyCodeStop },
198     { "rev",          kKeyCodeRewind },
199     { "ffwd",         kKeyCodeFastForward },
200     { "bookmarks",    kKeyCodeBookmarks },
201     { "window",       kKeyCodeCycleWindows },
202     { "channel-up",   kKeyCodeChannelUp },
203     { "channel-down", kKeyCodeChannelDown },
204     { 0, 0 },
205 };
206 
207 static unsigned
keyinfo_lookup_code(const char * name)208 keyinfo_lookup_code(const char *name)
209 {
210     KeyInfo *ki = _keyinfo_table;
211     while(ki->name) {
212         if(!strcmp(name, ki->name))
213             return ki->code;
214         ki++;
215     }
216     return 0;
217 }
218 
219 
220 static void
skin_button_free(SkinButton * button)221 skin_button_free( SkinButton*  button )
222 {
223     if (button) {
224         skin_image_unref( &button->image );
225         AFREE(button);
226     }
227 }
228 
229 static SkinButton*
skin_button_create_from(AConfig * node,const char * basepath)230 skin_button_create_from( AConfig*   node, const char*  basepath )
231 {
232     SkinButton*  button;
233     ANEW0(button);
234     if (button) {
235         const char*  img = aconfig_str(node, "image", NULL);
236         int          x   = aconfig_int(node, "x", 0);
237         int          y   = aconfig_int(node, "y", 0);
238 
239         button->name       = node->name;
240         button->rect.pos.x = x;
241         button->rect.pos.y = y;
242 
243         if (img != NULL)
244             button->image = skin_image_find_in( basepath, img );
245 
246         if (button->image == SKIN_IMAGE_NONE) {
247             skin_button_free(button);
248             return NULL;
249         }
250 
251         button->rect.size.w = skin_image_w( button->image );
252         button->rect.size.h = skin_image_h( button->image );
253 
254         button->keycode = keyinfo_lookup_code( button->name );
255         if (button->keycode == 0) {
256             dprint( "Warning: skin file button uses unknown key name '%s'", button->name );
257         }
258     }
259     return button;
260 }
261 
262 /** SKIN PART
263  **/
264 
265 static void
skin_part_free(SkinPart * part)266 skin_part_free( SkinPart*  part )
267 {
268     if (part) {
269         skin_background_done( part->background );
270         skin_display_done( part->display );
271 
272         SKIN_PART_LOOP_BUTTONS(part,button)
273             skin_button_free(button);
274         SKIN_PART_LOOP_END
275         part->buttons = NULL;
276         AFREE(part);
277     }
278 }
279 
280 static SkinLocation*
skin_location_create_from_v2(AConfig * node,SkinPart * parts)281 skin_location_create_from_v2( AConfig*  node, SkinPart*  parts )
282 {
283     const char*    partname = aconfig_str(node, "name", NULL);
284     int            x        = aconfig_int(node, "x", 0);
285     int            y        = aconfig_int(node, "y", 0);
286     SkinRotation   rot      = aconfig_int(node, "rotation", SKIN_ROTATION_0);
287     SkinPart*      part;
288     SkinLocation*  location;
289 
290     if (partname == NULL) {
291         dprint( "### WARNING: ignoring part location without 'name' element" );
292         return NULL;
293     }
294 
295     for (part = parts; part; part = part->next)
296         if (!strcmp(part->name, partname))
297             break;
298 
299     if (part == NULL) {
300         dprint( "### WARNING: ignoring part location with unknown name '%s'", partname );
301         return NULL;
302     }
303 
304     ANEW0(location);
305     location->part     = part;
306     location->anchor.x = x;
307     location->anchor.y = y;
308     location->rotation = rot;
309 
310     return location;
311 }
312 
313 static SkinPart*
skin_part_create_from_v1(AConfig * root,const char * basepath)314 skin_part_create_from_v1( AConfig*  root, const char*  basepath )
315 {
316     SkinPart*  part;
317     AConfig*  node;
318     SkinBox   box;
319 
320     ANEW0(part);
321     part->name = root->name;
322 
323     node = aconfig_find(root, "background");
324     if (node)
325         skin_background_init_from(part->background, node, basepath);
326 
327     node = aconfig_find(root, "display");
328     if (node)
329         skin_display_init_from(part->display, node);
330 
331     node = aconfig_find(root, "button");
332     if (node) {
333         for (node = node->first_child; node != NULL; node = node->next)
334         {
335             SkinButton*  button = skin_button_create_from(node, basepath);
336 
337             if (button != NULL) {
338                 button->next  = part->buttons;
339                 part->buttons = button;
340             }
341         }
342     }
343 
344     skin_box_minmax_init( &box );
345 
346     if (part->background->valid)
347         skin_box_minmax_update( &box, &part->background->rect );
348 
349     if (part->display->valid)
350         skin_box_minmax_update( &box, &part->display->rect );
351 
352     SKIN_PART_LOOP_BUTTONS(part, button)
353         skin_box_minmax_update( &box, &button->rect );
354     SKIN_PART_LOOP_END
355 
356     if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) {
357         skin_part_free(part);
358         part = NULL;
359     }
360 
361     return part;
362 }
363 
364 static SkinPart*
skin_part_create_from_v2(AConfig * root,const char * basepath)365 skin_part_create_from_v2( AConfig*  root, const char*  basepath )
366 {
367     SkinPart*  part;
368     AConfig*  node;
369     SkinBox   box;
370 
371     ANEW0(part);
372     part->name = root->name;
373 
374     node = aconfig_find(root, "background");
375     if (node)
376         skin_background_init_from(part->background, node, basepath);
377 
378     node = aconfig_find(root, "display");
379     if (node)
380         skin_display_init_from(part->display, node);
381 
382     node = aconfig_find(root, "buttons");
383     if (node) {
384         for (node = node->first_child; node != NULL; node = node->next)
385         {
386             SkinButton*  button = skin_button_create_from(node, basepath);
387 
388             if (button != NULL) {
389                 button->next  = part->buttons;
390                 part->buttons = button;
391             }
392         }
393     }
394 
395     skin_box_minmax_init( &box );
396 
397     if (part->background->valid)
398         skin_box_minmax_update( &box, &part->background->rect );
399 
400     if (part->display->valid)
401         skin_box_minmax_update( &box, &part->display->rect );
402 
403     SKIN_PART_LOOP_BUTTONS(part, button)
404         skin_box_minmax_update( &box, &button->rect );
405     SKIN_PART_LOOP_END
406 
407     if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) {
408         skin_part_free(part);
409         part = NULL;
410     }
411     return part;
412 }
413 
414 /** SKIN LAYOUT
415  **/
416 
417 static void
skin_layout_free(SkinLayout * layout)418 skin_layout_free( SkinLayout*  layout )
419 {
420     if (layout) {
421         SKIN_LAYOUT_LOOP_LOCS(layout,loc)
422             AFREE(loc);
423         SKIN_LAYOUT_LOOP_END
424         layout->locations = NULL;
425         AFREE(layout);
426     }
427 }
428 
429 SkinDisplay*
skin_layout_get_display(SkinLayout * layout)430 skin_layout_get_display( SkinLayout*  layout )
431 {
432     SKIN_LAYOUT_LOOP_LOCS(layout,loc)
433         SkinPart*  part = loc->part;
434         if (part->display->valid) {
435             return part->display;
436         }
437     SKIN_LAYOUT_LOOP_END
438     return NULL;
439 }
440 
441 SkinRotation
skin_layout_get_dpad_rotation(SkinLayout * layout)442 skin_layout_get_dpad_rotation( SkinLayout*  layout )
443 {
444     if (layout->has_dpad_rotation)
445         return layout->dpad_rotation;
446 
447     SKIN_LAYOUT_LOOP_LOCS(layout, loc)
448         SkinPart*  part = loc->part;
449         SKIN_PART_LOOP_BUTTONS(part,button)
450             if (button->keycode == kKeyCodeDpadUp)
451                 return loc->rotation;
452         SKIN_PART_LOOP_END
453     SKIN_LAYOUT_LOOP_END
454 
455     return SKIN_ROTATION_0;
456 }
457 
458 
459 static int
skin_layout_event_decode(const char * event,int * ptype,int * pcode,int * pvalue)460 skin_layout_event_decode( const char*  event, int  *ptype, int  *pcode, int *pvalue )
461 {
462     typedef struct {
463         const char*  name;
464         int          value;
465     } EventName;
466 
467     static const EventName  _event_names[] = {
468         { "EV_SW", 0x05 },
469         { NULL, 0 },
470     };
471 
472     const char*       x = strchr(event, ':');
473     const char*       y = NULL;
474     const EventName*  ev = _event_names;
475 
476     if (x != NULL)
477         y = strchr(x+1, ':');
478 
479     if (x == NULL || y == NULL) {
480         dprint( "### WARNING: invalid skin layout event format: '%s', should be '<TYPE>:<CODE>:<VALUE>'", event );
481         return -1;
482     }
483 
484     for ( ; ev->name != NULL; ev++ )
485         if (!memcmp( event, ev->name, x - event ) && ev->name[x-event] == 0)
486             break;
487 
488     if (!ev->name) {
489         dprint( "### WARNING: unrecognized skin layout event name: %.*s", x-event, event );
490         return -1;
491     }
492 
493     *ptype  = ev->value;
494     *pcode  = strtol(x+1, NULL, 0);
495     *pvalue = strtol(y+1, NULL, 0);
496     return 0;
497 }
498 
499 static SkinLayout*
skin_layout_create_from_v2(AConfig * root,SkinPart * parts)500 skin_layout_create_from_v2( AConfig*  root, SkinPart*  parts )
501 {
502     SkinLayout*    layout;
503     int            width, height;
504     SkinLocation** ptail;
505     AConfig*       node;
506 
507     ANEW0(layout);
508 
509     width  = aconfig_int( root, "width", 400 );
510     height = aconfig_int( root, "height", 400 );
511 
512     node = aconfig_find( root, "event" );
513     if (node != NULL) {
514         skin_layout_event_decode( node->value,
515                                   &layout->event_type,
516                                   &layout->event_code,
517                                   &layout->event_value );
518     } else {
519         layout->event_type  = 0x05;  /* close keyboard by default */
520         layout->event_code  = 0;
521         layout->event_value = 1;
522     }
523 
524     layout->name  = root->name;
525     layout->color = aconfig_unsigned( root, "color", 0x808080 ) | 0xff000000;
526     ptail         = &layout->locations;
527 
528     node = aconfig_find( root, "dpad-rotation" );
529     if (node != NULL) {
530         layout->dpad_rotation     = aconfig_int( root, "dpad-rotation", 0 );
531         layout->has_dpad_rotation = 1;
532     }
533 
534     for (node = root->first_child; node; node = node->next)
535     {
536         if (!memcmp(node->name, "part", 4)) {
537             SkinLocation*  location = skin_location_create_from_v2( node, parts );
538             if (location == NULL) {
539                 continue;
540             }
541             *ptail = location;
542             ptail  = &location->next;
543         }
544     }
545 
546     if (layout->locations == NULL)
547         goto Fail;
548 
549     layout->size.w = width;
550     layout->size.h = height;
551 
552     return layout;
553 
554 Fail:
555     skin_layout_free(layout);
556     return NULL;
557 }
558 
559 /** SKIN FILE
560  **/
561 
562 static int
skin_file_load_from_v1(SkinFile * file,AConfig * aconfig,const char * basepath)563 skin_file_load_from_v1( SkinFile*  file, AConfig*  aconfig, const char*  basepath )
564 {
565     SkinPart*      part;
566     SkinLayout*    layout;
567     SkinLayout**   ptail = &file->layouts;
568     SkinLocation*  location;
569     int            nn;
570 
571     file->parts = part = skin_part_create_from_v1( aconfig, basepath );
572     if (part == NULL)
573         return -1;
574 
575     for (nn = 0; nn < 2; nn++)
576     {
577         ANEW0(layout);
578 
579         layout->color = 0xff808080;
580 
581         ANEW0(location);
582 
583         layout->event_type  = 0x05;  /* close keyboard by default */
584         layout->event_code  = 0;
585         layout->event_value = 1;
586 
587         location->part     = part;
588         switch (nn) {
589             case 0:
590                 location->anchor.x = 0;
591                 location->anchor.y = 0;
592                 location->rotation = SKIN_ROTATION_0;
593                 layout->size       = part->rect.size;
594                 break;
595 
596 #if 0
597             case 1:
598                 location->anchor.x = part->rect.size.h;
599                 location->anchor.y = 0;
600                 location->rotation = SKIN_ROTATION_90;
601                 layout->size.w     = part->rect.size.h;
602                 layout->size.h     = part->rect.size.w;
603                 layout->event_value = 0;
604                 break;
605 
606             case 2:
607                 location->anchor.x = part->rect.size.w;
608                 location->anchor.y = part->rect.size.h;
609                 location->rotation = SKIN_ROTATION_180;
610                 layout->size       = part->rect.size;
611                 break;
612 #endif
613             default:
614                 location->anchor.x = 0;
615                 location->anchor.y = part->rect.size.w;
616                 location->rotation = SKIN_ROTATION_270;
617                 layout->size.w     = part->rect.size.h;
618                 layout->size.h     = part->rect.size.w;
619                 layout->event_value = 0;
620                 break;
621         }
622         layout->locations = location;
623 
624         *ptail = layout;
625         ptail  = &layout->next;
626     }
627     file->version = 1;
628     return 0;
629 }
630 
631 static int
skin_file_load_from_v2(SkinFile * file,AConfig * aconfig,const char * basepath)632 skin_file_load_from_v2( SkinFile*  file, AConfig*  aconfig, const char*  basepath )
633 {
634     AConfig*  node;
635 
636     /* first, load all parts */
637     node = aconfig_find(aconfig, "parts");
638     if (node == NULL)
639         return -1;
640     else
641     {
642         SkinPart**  ptail = &file->parts;
643         for (node = node->first_child; node != NULL; node = node->next)
644         {
645             SkinPart*  part = skin_part_create_from_v2( node, basepath );
646             if (part == NULL) {
647                 dprint( "## WARNING: can't load part '%s' from skin\n", node->name ? "<NULL>" : node->name );
648                 continue;
649             }
650             part->next = NULL;
651             *ptail     = part;
652             ptail      = &part->next;
653         }
654     }
655 
656     if (file->parts == NULL)
657         return -1;
658 
659     /* then load all layouts */
660     node = aconfig_find(aconfig, "layouts");
661     if (node == NULL)
662         return -1;
663     else
664     {
665         SkinLayout**  ptail = &file->layouts;
666         for (node = node->first_child; node != NULL; node = node->next)
667         {
668             SkinLayout*  layout = skin_layout_create_from_v2( node, file->parts );
669             if (layout == NULL) {
670                 dprint( "## WARNING: ignoring layout in skin file" );
671                 continue;
672             }
673             *ptail = layout;
674             layout->next = NULL;
675             ptail        = &layout->next;
676         }
677     }
678     if (file->layouts == NULL)
679         return -1;
680 
681     file->version = 2;
682     return 0;
683 }
684 
685 SkinFile*
skin_file_create_from_aconfig(AConfig * aconfig,const char * basepath)686 skin_file_create_from_aconfig( AConfig*   aconfig, const char*  basepath )
687 {
688     SkinFile*  file;
689 
690     ANEW0(file);
691 
692     if ( aconfig_find(aconfig, "parts") != NULL) {
693         if (skin_file_load_from_v2( file, aconfig, basepath ) < 0) {
694             goto BAD_FILE;
695         }
696         file->version = aconfig_int(aconfig, "version", 2);
697         /* The file version must be 1 or higher */
698         if (file->version <= 0) {
699             dprint( "## WARNING: invalid skin version: %d", file->version);
700             goto BAD_FILE;
701         }
702     }
703     else {
704         if (skin_file_load_from_v1( file, aconfig, basepath ) < 0) {
705             goto BAD_FILE;
706         }
707         file->version = 1;
708     }
709     return file;
710 
711 BAD_FILE:
712     skin_file_free( file );
713     return NULL;
714 }
715 
716 void
skin_file_free(SkinFile * file)717 skin_file_free( SkinFile*  file )
718 {
719     if (file) {
720         SKIN_FILE_LOOP_LAYOUTS(file,layout)
721             skin_layout_free(layout);
722         SKIN_FILE_LOOP_END_LAYOUTS
723         file->layouts = NULL;
724 
725         SKIN_FILE_LOOP_PARTS(file,part)
726             skin_part_free(part);
727         SKIN_FILE_LOOP_END_PARTS
728         file->parts = NULL;
729 
730         AFREE(file);
731     }
732 }
733