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 if (layout->onion_image) {
426 skin_image_unref( &layout->onion_image );
427 }
428 AFREE(layout);
429 }
430 }
431
432 SkinDisplay*
skin_layout_get_display(SkinLayout * layout)433 skin_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
444 SkinRotation
skin_layout_get_dpad_rotation(SkinLayout * layout)445 skin_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
462 static int
skin_layout_event_decode(const char * event,int * ptype,int * pcode,int * pvalue)463 skin_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
502 static SkinLayout*
skin_layout_create_from_v2(AConfig * root,SkinPart * parts,const char * basepath)503 skin_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
571 Fail:
572 skin_layout_free(layout);
573 return NULL;
574 }
575
576 /** SKIN FILE
577 **/
578
579 static int
skin_file_load_from_v1(SkinFile * file,AConfig * aconfig,const char * basepath)580 skin_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
648 static int
skin_file_load_from_v2(SkinFile * file,AConfig * aconfig,const char * basepath)649 skin_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
702 SkinFile*
skin_file_create_from_aconfig(AConfig * aconfig,const char * basepath)703 skin_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
728 BAD_FILE:
729 skin_file_free( file );
730 return NULL;
731 }
732
733 void
skin_file_free(SkinFile * file)734 skin_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