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