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 95 display->valid = ( display->rect.size.w > 0 && display->rect.size.h > 0 ); 96 97 if (display->valid) { 98 SkinRect r; 99 skin_rect_rotate( &r, &display->rect, -display->rotation ); 100 qframebuffer_init( display->qfbuff, 101 r.size.w, 102 r.size.h, 103 0, 104 QFRAME_BUFFER_RGB565 ); 105 106 qframebuffer_fifo_add( display->qfbuff ); 107 } 108 return display->valid ? 0 : -1; 109 } 110 111 /** SKIN BUTTON 112 **/ 113 114 typedef struct 115 { 116 const char* name; 117 AndroidKeyCode code; 118 } KeyInfo; 119 120 static KeyInfo _keyinfo_table[] = { 121 { "dpad-up", kKeyCodeDpadUp }, 122 { "dpad-down", kKeyCodeDpadDown }, 123 { "dpad-left", kKeyCodeDpadLeft }, 124 { "dpad-right", kKeyCodeDpadRight }, 125 { "dpad-center", kKeyCodeDpadCenter }, 126 { "soft-left", kKeyCodeSoftLeft }, 127 { "soft-right", kKeyCodeSoftRight }, 128 { "search", kKeyCodeSearch }, 129 { "volume-up", kKeyCodeVolumeUp }, 130 { "volume-down", kKeyCodeVolumeDown }, 131 { "power", kKeyCodePower }, 132 { "home", kKeyCodeHome }, 133 { "back", kKeyCodeBack }, 134 { "del", kKeyCodeDel }, 135 { "0", kKeyCode0 }, 136 { "1", kKeyCode1 }, 137 { "2", kKeyCode2 }, 138 { "3", kKeyCode3 }, 139 { "4", kKeyCode4 }, 140 { "5", kKeyCode5 }, 141 { "6", kKeyCode6 }, 142 { "7", kKeyCode7 }, 143 { "8", kKeyCode8 }, 144 { "9", kKeyCode9 }, 145 { "star", kKeyCodeStar }, 146 { "pound", kKeyCodePound }, 147 { "phone-dial", kKeyCodeCall }, 148 { "phone-hangup", kKeyCodeEndCall }, 149 { "q", kKeyCodeQ }, 150 { "w", kKeyCodeW }, 151 { "e", kKeyCodeE }, 152 { "r", kKeyCodeR }, 153 { "t", kKeyCodeT }, 154 { "y", kKeyCodeY }, 155 { "u", kKeyCodeU }, 156 { "i", kKeyCodeI }, 157 { "o", kKeyCodeO }, 158 { "p", kKeyCodeP }, 159 { "a", kKeyCodeA }, 160 { "s", kKeyCodeS }, 161 { "d", kKeyCodeD }, 162 { "f", kKeyCodeF }, 163 { "g", kKeyCodeG }, 164 { "h", kKeyCodeH }, 165 { "j", kKeyCodeJ }, 166 { "k", kKeyCodeK }, 167 { "l", kKeyCodeL }, 168 { "DEL", kKeyCodeDel }, 169 { "z", kKeyCodeZ }, 170 { "x", kKeyCodeX }, 171 { "c", kKeyCodeC }, 172 { "v", kKeyCodeV }, 173 { "b", kKeyCodeB }, 174 { "n", kKeyCodeN }, 175 { "m", kKeyCodeM }, 176 { "COMMA", kKeyCodeComma }, 177 { "PERIOD", kKeyCodePeriod }, 178 { "ENTER", kKeyCodeNewline }, 179 { "AT", kKeyCodeAt }, 180 { "SPACE", kKeyCodeSpace }, 181 { "SLASH", kKeyCodeSlash }, 182 { "CAP", kKeyCodeCapLeft }, 183 { "SYM", kKeyCodeSym }, 184 { "ALT", kKeyCodeAltLeft }, 185 { "ALT2", kKeyCodeAltRight }, 186 { "CAP2", kKeyCodeCapRight }, 187 { 0, 0 }, 188 }; 189 190 static unsigned 191 keyinfo_lookup_code(const char *name) 192 { 193 KeyInfo *ki = _keyinfo_table; 194 while(ki->name) { 195 if(!strcmp(name, ki->name)) 196 return ki->code; 197 ki++; 198 } 199 return 0; 200 } 201 202 203 static void 204 skin_button_free( SkinButton* button ) 205 { 206 if (button) { 207 skin_image_unref( &button->image ); 208 AFREE(button); 209 } 210 } 211 212 static SkinButton* 213 skin_button_create_from( AConfig* node, const char* basepath ) 214 { 215 SkinButton* button; 216 ANEW0(button); 217 if (button) { 218 const char* img = aconfig_str(node, "image", NULL); 219 int x = aconfig_int(node, "x", 0); 220 int y = aconfig_int(node, "y", 0); 221 222 button->name = node->name; 223 button->rect.pos.x = x; 224 button->rect.pos.y = y; 225 226 if (img != NULL) 227 button->image = skin_image_find_in( basepath, img ); 228 229 if (button->image == SKIN_IMAGE_NONE) { 230 skin_button_free(button); 231 return NULL; 232 } 233 234 button->rect.size.w = skin_image_w( button->image ); 235 button->rect.size.h = skin_image_h( button->image ); 236 237 button->keycode = keyinfo_lookup_code( button->name ); 238 if (button->keycode == 0) { 239 dprint( "Warning: skin file button uses unknown key name '%s'", button->name ); 240 } 241 } 242 return button; 243 } 244 245 /** SKIN PART 246 **/ 247 248 static void 249 skin_part_free( SkinPart* part ) 250 { 251 if (part) { 252 skin_background_done( part->background ); 253 skin_display_done( part->display ); 254 255 SKIN_PART_LOOP_BUTTONS(part,button) 256 skin_button_free(button); 257 SKIN_PART_LOOP_END 258 part->buttons = NULL; 259 AFREE(part); 260 } 261 } 262 263 static SkinLocation* 264 skin_location_create_from_v2( AConfig* node, SkinPart* parts ) 265 { 266 const char* partname = aconfig_str(node, "name", NULL); 267 int x = aconfig_int(node, "x", 0); 268 int y = aconfig_int(node, "y", 0); 269 SkinRotation rot = aconfig_int(node, "rotation", SKIN_ROTATION_0); 270 SkinPart* part; 271 SkinLocation* location; 272 273 if (partname == NULL) { 274 dprint( "### WARNING: ignoring part location without 'name' element" ); 275 return NULL; 276 } 277 278 for (part = parts; part; part = part->next) 279 if (!strcmp(part->name, partname)) 280 break; 281 282 if (part == NULL) { 283 dprint( "### WARNING: ignoring part location with unknown name '%s'", partname ); 284 return NULL; 285 } 286 287 ANEW0(location); 288 location->part = part; 289 location->anchor.x = x; 290 location->anchor.y = y; 291 location->rotation = rot; 292 293 return location; 294 } 295 296 static SkinPart* 297 skin_part_create_from_v1( AConfig* root, const char* basepath ) 298 { 299 SkinPart* part; 300 AConfig* node; 301 SkinBox box; 302 303 ANEW0(part); 304 part->name = root->name; 305 306 node = aconfig_find(root, "background"); 307 if (node) 308 skin_background_init_from(part->background, node, basepath); 309 310 node = aconfig_find(root, "display"); 311 if (node) 312 skin_display_init_from(part->display, node); 313 314 node = aconfig_find(root, "button"); 315 if (node) { 316 for (node = node->first_child; node != NULL; node = node->next) 317 { 318 SkinButton* button = skin_button_create_from(node, basepath); 319 320 if (button != NULL) { 321 button->next = part->buttons; 322 part->buttons = button; 323 } 324 } 325 } 326 327 skin_box_minmax_init( &box ); 328 329 if (part->background->valid) 330 skin_box_minmax_update( &box, &part->background->rect ); 331 332 if (part->display->valid) 333 skin_box_minmax_update( &box, &part->display->rect ); 334 335 SKIN_PART_LOOP_BUTTONS(part, button) 336 skin_box_minmax_update( &box, &button->rect ); 337 SKIN_PART_LOOP_END 338 339 if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) { 340 skin_part_free(part); 341 part = NULL; 342 } 343 344 return part; 345 } 346 347 static SkinPart* 348 skin_part_create_from_v2( AConfig* root, const char* basepath ) 349 { 350 SkinPart* part; 351 AConfig* node; 352 SkinBox box; 353 354 ANEW0(part); 355 part->name = root->name; 356 357 node = aconfig_find(root, "background"); 358 if (node) 359 skin_background_init_from(part->background, node, basepath); 360 361 node = aconfig_find(root, "display"); 362 if (node) 363 skin_display_init_from(part->display, node); 364 365 node = aconfig_find(root, "buttons"); 366 if (node) { 367 for (node = node->first_child; node != NULL; node = node->next) 368 { 369 SkinButton* button = skin_button_create_from(node, basepath); 370 371 if (button != NULL) { 372 button->next = part->buttons; 373 part->buttons = button; 374 } 375 } 376 } 377 378 skin_box_minmax_init( &box ); 379 380 if (part->background->valid) 381 skin_box_minmax_update( &box, &part->background->rect ); 382 383 if (part->display->valid) 384 skin_box_minmax_update( &box, &part->display->rect ); 385 386 SKIN_PART_LOOP_BUTTONS(part, button) 387 skin_box_minmax_update( &box, &button->rect ); 388 SKIN_PART_LOOP_END 389 390 if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) { 391 skin_part_free(part); 392 part = NULL; 393 } 394 return part; 395 } 396 397 /** SKIN LAYOUT 398 **/ 399 400 static void 401 skin_layout_free( SkinLayout* layout ) 402 { 403 if (layout) { 404 SKIN_LAYOUT_LOOP_LOCS(layout,loc) 405 AFREE(loc); 406 SKIN_LAYOUT_LOOP_END 407 layout->locations = NULL; 408 AFREE(layout); 409 } 410 } 411 412 SkinDisplay* 413 skin_layout_get_display( SkinLayout* layout ) 414 { 415 SKIN_LAYOUT_LOOP_LOCS(layout,loc) 416 SkinPart* part = loc->part; 417 if (part->display->valid) { 418 return part->display; 419 } 420 SKIN_LAYOUT_LOOP_END 421 return NULL; 422 } 423 424 SkinRotation 425 skin_layout_get_dpad_rotation( SkinLayout* layout ) 426 { 427 if (layout->has_dpad_rotation) 428 return layout->dpad_rotation; 429 430 SKIN_LAYOUT_LOOP_LOCS(layout, loc) 431 SkinPart* part = loc->part; 432 SKIN_PART_LOOP_BUTTONS(part,button) 433 if (button->keycode == kKeyCodeDpadUp) 434 return loc->rotation; 435 SKIN_PART_LOOP_END 436 SKIN_LAYOUT_LOOP_END 437 438 return SKIN_ROTATION_0; 439 } 440 441 442 static int 443 skin_layout_event_decode( const char* event, int *ptype, int *pcode, int *pvalue ) 444 { 445 typedef struct { 446 const char* name; 447 int value; 448 } EventName; 449 450 static const EventName _event_names[] = { 451 { "EV_SW", 0x05 }, 452 { NULL, 0 }, 453 }; 454 455 const char* x = strchr(event, ':'); 456 const char* y = NULL; 457 const EventName* ev = _event_names; 458 459 if (x != NULL) 460 y = strchr(x+1, ':'); 461 462 if (x == NULL || y == NULL) { 463 dprint( "### WARNING: invalid skin layout event format: '%s', should be '<TYPE>:<CODE>:<VALUE>'", event ); 464 return -1; 465 } 466 467 for ( ; ev->name != NULL; ev++ ) 468 if (!memcmp( event, ev->name, x - event ) && ev->name[x-event] == 0) 469 break; 470 471 if (!ev->name) { 472 dprint( "### WARNING: unrecognized skin layout event name: %.*s", x-event, event ); 473 return -1; 474 } 475 476 *ptype = ev->value; 477 *pcode = strtol(x+1, NULL, 0); 478 *pvalue = strtol(y+1, NULL, 0); 479 return 0; 480 } 481 482 static SkinLayout* 483 skin_layout_create_from_v2( AConfig* root, SkinPart* parts ) 484 { 485 SkinLayout* layout; 486 int width, height; 487 SkinLocation** ptail; 488 AConfig* node; 489 490 ANEW0(layout); 491 492 width = aconfig_int( root, "width", 400 ); 493 height = aconfig_int( root, "height", 400 ); 494 495 node = aconfig_find( root, "event" ); 496 if (node != NULL) { 497 skin_layout_event_decode( node->value, 498 &layout->event_type, 499 &layout->event_code, 500 &layout->event_value ); 501 } else { 502 layout->event_type = 0x05; /* close keyboard by default */ 503 layout->event_code = 0; 504 layout->event_value = 1; 505 } 506 507 layout->name = root->name; 508 layout->color = aconfig_unsigned( root, "color", 0x808080 ) | 0xff000000; 509 ptail = &layout->locations; 510 511 node = aconfig_find( root, "dpad-rotation" ); 512 if (node != NULL) { 513 layout->dpad_rotation = aconfig_int( root, "dpad-rotation", 0 ); 514 layout->has_dpad_rotation = 1; 515 } 516 517 for (node = root->first_child; node; node = node->next) 518 { 519 if (!memcmp(node->name, "part", 4)) { 520 SkinLocation* location = skin_location_create_from_v2( node, parts ); 521 if (location == NULL) { 522 continue; 523 } 524 *ptail = location; 525 ptail = &location->next; 526 } 527 } 528 529 if (layout->locations == NULL) 530 goto Fail; 531 532 layout->size.w = width; 533 layout->size.h = height; 534 535 return layout; 536 537 Fail: 538 skin_layout_free(layout); 539 return NULL; 540 } 541 542 /** SKIN FILE 543 **/ 544 545 static int 546 skin_file_load_from_v1( SkinFile* file, AConfig* aconfig, const char* basepath ) 547 { 548 SkinPart* part; 549 SkinLayout* layout; 550 SkinLayout** ptail = &file->layouts; 551 SkinLocation* location; 552 int nn; 553 554 file->parts = part = skin_part_create_from_v1( aconfig, basepath ); 555 if (part == NULL) 556 return -1; 557 558 for (nn = 0; nn < 2; nn++) 559 { 560 ANEW0(layout); 561 562 layout->color = 0xff808080; 563 564 ANEW0(location); 565 566 layout->event_type = 0x05; /* close keyboard by default */ 567 layout->event_code = 0; 568 layout->event_value = 1; 569 570 location->part = part; 571 switch (nn) { 572 case 0: 573 location->anchor.x = 0; 574 location->anchor.y = 0; 575 location->rotation = SKIN_ROTATION_0; 576 layout->size = part->rect.size; 577 break; 578 579 #if 0 580 case 1: 581 location->anchor.x = part->rect.size.h; 582 location->anchor.y = 0; 583 location->rotation = SKIN_ROTATION_90; 584 layout->size.w = part->rect.size.h; 585 layout->size.h = part->rect.size.w; 586 layout->event_value = 0; 587 break; 588 589 case 2: 590 location->anchor.x = part->rect.size.w; 591 location->anchor.y = part->rect.size.h; 592 location->rotation = SKIN_ROTATION_180; 593 layout->size = part->rect.size; 594 break; 595 #endif 596 default: 597 location->anchor.x = 0; 598 location->anchor.y = part->rect.size.w; 599 location->rotation = SKIN_ROTATION_270; 600 layout->size.w = part->rect.size.h; 601 layout->size.h = part->rect.size.w; 602 layout->event_value = 0; 603 break; 604 } 605 layout->locations = location; 606 607 *ptail = layout; 608 ptail = &layout->next; 609 } 610 return 0; 611 } 612 613 static int 614 skin_file_load_from_v2( SkinFile* file, AConfig* aconfig, const char* basepath ) 615 { 616 AConfig* node; 617 618 /* first, load all parts */ 619 node = aconfig_find(aconfig, "parts"); 620 if (node == NULL) 621 return -1; 622 else 623 { 624 SkinPart** ptail = &file->parts; 625 for (node = node->first_child; node != NULL; node = node->next) 626 { 627 SkinPart* part = skin_part_create_from_v2( node, basepath ); 628 if (part == NULL) { 629 dprint( "## WARNING: can't load part '%s' from skin\n", node->name ? "<NULL>" : node->name ); 630 continue; 631 } 632 part->next = NULL; 633 *ptail = part; 634 ptail = &part->next; 635 } 636 } 637 638 if (file->parts == NULL) 639 return -1; 640 641 /* then load all layouts */ 642 node = aconfig_find(aconfig, "layouts"); 643 if (node == NULL) 644 return -1; 645 else 646 { 647 SkinLayout** ptail = &file->layouts; 648 for (node = node->first_child; node != NULL; node = node->next) 649 { 650 SkinLayout* layout = skin_layout_create_from_v2( node, file->parts ); 651 if (layout == NULL) { 652 dprint( "## WARNING: ignoring layout in skin file" ); 653 continue; 654 } 655 *ptail = layout; 656 layout->next = NULL; 657 ptail = &layout->next; 658 } 659 } 660 if (file->layouts == NULL) 661 return -1; 662 663 return 0; 664 } 665 666 SkinFile* 667 skin_file_create_from_aconfig( AConfig* aconfig, const char* basepath ) 668 { 669 SkinFile* file; 670 671 ANEW0(file); 672 if ( aconfig_find(aconfig, "parts") != NULL) { 673 if (skin_file_load_from_v2( file, aconfig, basepath ) < 0) { 674 skin_file_free( file ); 675 file = NULL; 676 } 677 } 678 else { 679 if (skin_file_load_from_v1( file, aconfig, basepath ) < 0) { 680 skin_file_free( file ); 681 file = NULL; 682 } 683 } 684 return file; 685 } 686 687 void 688 skin_file_free( SkinFile* file ) 689 { 690 if (file) { 691 SKIN_FILE_LOOP_LAYOUTS(file,layout) 692 skin_layout_free(layout); 693 SKIN_FILE_LOOP_END_LAYOUTS 694 file->layouts = NULL; 695 696 SKIN_FILE_LOOP_PARTS(file,part) 697 skin_part_free(part); 698 SKIN_FILE_LOOP_END_PARTS 699 file->parts = NULL; 700 701 AFREE(file); 702 } 703 } 704