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 **/
23static SkinImage*
24skin_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
40static void
41skin_background_done( SkinBackground*  background )
42{
43    if (background->image)
44        skin_image_unref(&background->image);
45}
46
47static int
48skin_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
80static void
81skin_display_done( SkinDisplay*  display )
82{
83    qframebuffer_done( display->qfbuff );
84}
85
86static int
87skin_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
116typedef struct
117{
118    const char*     name;
119    AndroidKeyCode  code;
120} KeyInfo;
121
122static 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
207static unsigned
208keyinfo_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
220static void
221skin_button_free( SkinButton*  button )
222{
223    if (button) {
224        skin_image_unref( &button->image );
225        AFREE(button);
226    }
227}
228
229static SkinButton*
230skin_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
265static void
266skin_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
280static SkinLocation*
281skin_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
313static SkinPart*
314skin_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
364static SkinPart*
365skin_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
417static void
418skin_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
429SkinDisplay*
430skin_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
441SkinRotation
442skin_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
459static int
460skin_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
499static SkinLayout*
500skin_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
554Fail:
555    skin_layout_free(layout);
556    return NULL;
557}
558
559/** SKIN FILE
560 **/
561
562static int
563skin_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
631static int
632skin_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
685SkinFile*
686skin_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
711BAD_FILE:
712    skin_file_free( file );
713    return NULL;
714}
715
716void
717skin_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