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        if (layout->onion_image) {
426          skin_image_unref( &layout->onion_image );
427        }
428        AFREE(layout);
429    }
430}
431
432SkinDisplay*
433skin_layout_get_display( SkinLayout*  layout )
434{
435    SKIN_LAYOUT_LOOP_LOCS(layout,loc)
436        SkinPart*  part = loc->part;
437        if (part->display->valid) {
438            return part->display;
439        }
440    SKIN_LAYOUT_LOOP_END
441    return NULL;
442}
443
444SkinRotation
445skin_layout_get_dpad_rotation( SkinLayout*  layout )
446{
447    if (layout->has_dpad_rotation)
448        return layout->dpad_rotation;
449
450    SKIN_LAYOUT_LOOP_LOCS(layout, loc)
451        SkinPart*  part = loc->part;
452        SKIN_PART_LOOP_BUTTONS(part,button)
453            if (button->keycode == kKeyCodeDpadUp)
454                return loc->rotation;
455        SKIN_PART_LOOP_END
456    SKIN_LAYOUT_LOOP_END
457
458    return SKIN_ROTATION_0;
459}
460
461
462static int
463skin_layout_event_decode( const char*  event, int  *ptype, int  *pcode, int *pvalue )
464{
465    typedef struct {
466        const char*  name;
467        int          value;
468    } EventName;
469
470    static const EventName  _event_names[] = {
471        { "EV_SW", 0x05 },
472        { NULL, 0 },
473    };
474
475    const char*       x = strchr(event, ':');
476    const char*       y = NULL;
477    const EventName*  ev = _event_names;
478
479    if (x != NULL)
480        y = strchr(x+1, ':');
481
482    if (x == NULL || y == NULL) {
483        dprint( "### WARNING: invalid skin layout event format: '%s', should be '<TYPE>:<CODE>:<VALUE>'", event );
484        return -1;
485    }
486
487    for ( ; ev->name != NULL; ev++ )
488        if (!memcmp( event, ev->name, x - event ) && ev->name[x-event] == 0)
489            break;
490
491    if (!ev->name) {
492        dprint( "### WARNING: unrecognized skin layout event name: %.*s", x-event, event );
493        return -1;
494    }
495
496    *ptype  = ev->value;
497    *pcode  = strtol(x+1, NULL, 0);
498    *pvalue = strtol(y+1, NULL, 0);
499    return 0;
500}
501
502static SkinLayout*
503skin_layout_create_from_v2( AConfig*  root, SkinPart*  parts, const char*  basepath )
504{
505    SkinLayout*    layout;
506    int            width, height;
507    SkinLocation** ptail;
508    AConfig*       node;
509
510    ANEW0(layout);
511
512    width  = aconfig_int( root, "width", 400 );
513    height = aconfig_int( root, "height", 400 );
514
515    node = aconfig_find( root, "event" );
516    if (node != NULL) {
517        skin_layout_event_decode( node->value,
518                                  &layout->event_type,
519                                  &layout->event_code,
520                                  &layout->event_value );
521    } else {
522        layout->event_type  = 0x05;  /* close keyboard by default */
523        layout->event_code  = 0;
524        layout->event_value = 1;
525    }
526
527    layout->name  = root->name;
528    layout->color = aconfig_unsigned( root, "color", 0x808080 ) | 0xff000000;
529    ptail         = &layout->locations;
530
531    node = aconfig_find( root, "dpad-rotation" );
532    if (node != NULL) {
533        layout->dpad_rotation     = aconfig_int( root, "dpad-rotation", 0 );
534        layout->has_dpad_rotation = 1;
535    }
536
537    node = aconfig_find( root, "onion" );
538    if (node != NULL) {
539        const char* img = aconfig_str(node, "image", NULL);
540        layout->onion_image = skin_image_find_in( basepath, img );
541        if (layout->onion_image == SKIN_IMAGE_NONE) {
542            layout->onion_image = NULL;
543        }
544        // In layout file, alpha is specified in range 0-100. Convert to
545        // internal range 0-256 with default=128.
546        int alpha = aconfig_int( node, "alpha", 50 );
547        layout->onion_alpha = (256*alpha)/100;
548        layout->onion_rotation = aconfig_int( node, "rotation", 0 );
549    }
550
551    for (node = root->first_child; node; node = node->next)
552    {
553        if (!memcmp(node->name, "part", 4)) {
554            SkinLocation*  location = skin_location_create_from_v2( node, parts );
555            if (location == NULL) {
556                continue;
557            }
558            *ptail = location;
559            ptail  = &location->next;
560        }
561    }
562
563    if (layout->locations == NULL)
564        goto Fail;
565
566    layout->size.w = width;
567    layout->size.h = height;
568
569    return layout;
570
571Fail:
572    skin_layout_free(layout);
573    return NULL;
574}
575
576/** SKIN FILE
577 **/
578
579static int
580skin_file_load_from_v1( SkinFile*  file, AConfig*  aconfig, const char*  basepath )
581{
582    SkinPart*      part;
583    SkinLayout*    layout;
584    SkinLayout**   ptail = &file->layouts;
585    SkinLocation*  location;
586    int            nn;
587
588    file->parts = part = skin_part_create_from_v1( aconfig, basepath );
589    if (part == NULL)
590        return -1;
591
592    for (nn = 0; nn < 2; nn++)
593    {
594        ANEW0(layout);
595
596        layout->color = 0xff808080;
597
598        ANEW0(location);
599
600        layout->event_type  = 0x05;  /* close keyboard by default */
601        layout->event_code  = 0;
602        layout->event_value = 1;
603
604        location->part     = part;
605        switch (nn) {
606            case 0:
607                location->anchor.x = 0;
608                location->anchor.y = 0;
609                location->rotation = SKIN_ROTATION_0;
610                layout->size       = part->rect.size;
611                break;
612
613#if 0
614            case 1:
615                location->anchor.x = part->rect.size.h;
616                location->anchor.y = 0;
617                location->rotation = SKIN_ROTATION_90;
618                layout->size.w     = part->rect.size.h;
619                layout->size.h     = part->rect.size.w;
620                layout->event_value = 0;
621                break;
622
623            case 2:
624                location->anchor.x = part->rect.size.w;
625                location->anchor.y = part->rect.size.h;
626                location->rotation = SKIN_ROTATION_180;
627                layout->size       = part->rect.size;
628                break;
629#endif
630            default:
631                location->anchor.x = 0;
632                location->anchor.y = part->rect.size.w;
633                location->rotation = SKIN_ROTATION_270;
634                layout->size.w     = part->rect.size.h;
635                layout->size.h     = part->rect.size.w;
636                layout->event_value = 0;
637                break;
638        }
639        layout->locations = location;
640
641        *ptail = layout;
642        ptail  = &layout->next;
643    }
644    file->version = 1;
645    return 0;
646}
647
648static int
649skin_file_load_from_v2( SkinFile*  file, AConfig*  aconfig, const char*  basepath )
650{
651    AConfig*  node;
652
653    /* first, load all parts */
654    node = aconfig_find(aconfig, "parts");
655    if (node == NULL)
656        return -1;
657    else
658    {
659        SkinPart**  ptail = &file->parts;
660        for (node = node->first_child; node != NULL; node = node->next)
661        {
662            SkinPart*  part = skin_part_create_from_v2( node, basepath );
663            if (part == NULL) {
664                dprint( "## WARNING: can't load part '%s' from skin\n", node->name ? "<NULL>" : node->name );
665                continue;
666            }
667            part->next = NULL;
668            *ptail     = part;
669            ptail      = &part->next;
670        }
671    }
672
673    if (file->parts == NULL)
674        return -1;
675
676    /* then load all layouts */
677    node = aconfig_find(aconfig, "layouts");
678    if (node == NULL)
679        return -1;
680    else
681    {
682        SkinLayout**  ptail = &file->layouts;
683        for (node = node->first_child; node != NULL; node = node->next)
684        {
685            SkinLayout*  layout = skin_layout_create_from_v2( node, file->parts, basepath );
686            if (layout == NULL) {
687                dprint( "## WARNING: ignoring layout in skin file" );
688                continue;
689            }
690            *ptail = layout;
691            layout->next = NULL;
692            ptail        = &layout->next;
693        }
694    }
695    if (file->layouts == NULL)
696        return -1;
697
698    file->version = 2;
699    return 0;
700}
701
702SkinFile*
703skin_file_create_from_aconfig( AConfig*   aconfig, const char*  basepath )
704{
705    SkinFile*  file;
706
707    ANEW0(file);
708
709    if ( aconfig_find(aconfig, "parts") != NULL) {
710        if (skin_file_load_from_v2( file, aconfig, basepath ) < 0) {
711            goto BAD_FILE;
712        }
713        file->version = aconfig_int(aconfig, "version", 2);
714        /* The file version must be 1 or higher */
715        if (file->version <= 0) {
716            dprint( "## WARNING: invalid skin version: %d", file->version);
717            goto BAD_FILE;
718        }
719    }
720    else {
721        if (skin_file_load_from_v1( file, aconfig, basepath ) < 0) {
722            goto BAD_FILE;
723        }
724        file->version = 1;
725    }
726    return file;
727
728BAD_FILE:
729    skin_file_free( file );
730    return NULL;
731}
732
733void
734skin_file_free( SkinFile*  file )
735{
736    if (file) {
737        SKIN_FILE_LOOP_LAYOUTS(file,layout)
738            skin_layout_free(layout);
739        SKIN_FILE_LOOP_END_LAYOUTS
740        file->layouts = NULL;
741
742        SKIN_FILE_LOOP_PARTS(file,part)
743            skin_part_free(part);
744        SKIN_FILE_LOOP_END_PARTS
745        file->parts = NULL;
746
747        AFREE(file);
748    }
749}
750