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* 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 41 skin_background_done( SkinBackground* background ) 42 { 43 if (background->image) 44 skin_image_unref(&background->image); 45 } 46 47 static int 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 81 skin_display_done( SkinDisplay* display ) 82 { 83 qframebuffer_done( display->qfbuff ); 84 } 85 86 static int 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 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 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* 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 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* 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* 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* 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 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* 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 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 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* 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 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 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* 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 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