1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <fcntl.h> 18 #include <linux/fb.h> 19 #include <linux/kd.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <sys/ioctl.h> 24 #include <sys/mman.h> 25 #include <sys/types.h> 26 #include <unistd.h> 27 28 #include <memory> 29 #include <regex> 30 #include <string> 31 #include <vector> 32 33 #include <android-base/stringprintf.h> 34 #include <android-base/strings.h> 35 #include <png.h> 36 37 #include "minui/minui.h" 38 39 #define SURFACE_DATA_ALIGNMENT 8 40 41 static GRSurface* malloc_surface(size_t data_size) { 42 size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT; 43 unsigned char* temp = static_cast<unsigned char*>(malloc(size)); 44 if (temp == NULL) return NULL; 45 GRSurface* surface = reinterpret_cast<GRSurface*>(temp); 46 surface->data = temp + sizeof(GRSurface) + 47 (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT)); 48 return surface; 49 } 50 51 // This class handles the png file parsing. It also holds the ownership of the png pointer and the 52 // opened file pointer. Both will be destroyed/closed when this object goes out of scope. 53 class PngHandler { 54 public: 55 PngHandler(const std::string& name); 56 57 ~PngHandler(); 58 59 png_uint_32 width() const { 60 return width_; 61 } 62 63 png_uint_32 height() const { 64 return height_; 65 } 66 67 png_byte channels() const { 68 return channels_; 69 } 70 71 png_structp png_ptr() const { 72 return png_ptr_; 73 } 74 75 png_infop info_ptr() const { 76 return info_ptr_; 77 } 78 79 int error_code() const { 80 return error_code_; 81 }; 82 83 operator bool() const { 84 return error_code_ == 0; 85 } 86 87 private: 88 png_structp png_ptr_{ nullptr }; 89 png_infop info_ptr_{ nullptr }; 90 png_uint_32 width_; 91 png_uint_32 height_; 92 png_byte channels_; 93 94 // The |error_code_| is set to a negative value if an error occurs when opening the png file. 95 int error_code_; 96 // After initialization, we'll keep the file pointer open before destruction of PngHandler. 97 std::unique_ptr<FILE, decltype(&fclose)> png_fp_; 98 }; 99 100 PngHandler::PngHandler(const std::string& name) : error_code_(0), png_fp_(nullptr, fclose) { 101 std::string res_path = android::base::StringPrintf("/res/images/%s.png", name.c_str()); 102 png_fp_.reset(fopen(res_path.c_str(), "rbe")); 103 if (!png_fp_) { 104 error_code_ = -1; 105 return; 106 } 107 108 unsigned char header[8]; 109 size_t bytesRead = fread(header, 1, sizeof(header), png_fp_.get()); 110 if (bytesRead != sizeof(header)) { 111 error_code_ = -2; 112 return; 113 } 114 115 if (png_sig_cmp(header, 0, sizeof(header))) { 116 error_code_ = -3; 117 return; 118 } 119 120 png_ptr_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 121 if (!png_ptr_) { 122 error_code_ = -4; 123 return; 124 } 125 126 info_ptr_ = png_create_info_struct(png_ptr_); 127 if (!info_ptr_) { 128 error_code_ = -5; 129 return; 130 } 131 132 if (setjmp(png_jmpbuf(png_ptr_))) { 133 error_code_ = -6; 134 return; 135 } 136 137 png_init_io(png_ptr_, png_fp_.get()); 138 png_set_sig_bytes(png_ptr_, sizeof(header)); 139 png_read_info(png_ptr_, info_ptr_); 140 141 int color_type; 142 int bit_depth; 143 png_get_IHDR(png_ptr_, info_ptr_, &width_, &height_, &bit_depth, &color_type, nullptr, nullptr, 144 nullptr); 145 146 channels_ = png_get_channels(png_ptr_, info_ptr_); 147 148 if (bit_depth == 8 && channels_ == 3 && color_type == PNG_COLOR_TYPE_RGB) { 149 // 8-bit RGB images: great, nothing to do. 150 } else if (bit_depth <= 8 && channels_ == 1 && color_type == PNG_COLOR_TYPE_GRAY) { 151 // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. 152 png_set_expand_gray_1_2_4_to_8(png_ptr_); 153 } else if (bit_depth <= 8 && channels_ == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { 154 // paletted images: expand to 8-bit RGB. Note that we DON'T 155 // currently expand the tRNS chunk (if any) to an alpha 156 // channel, because minui doesn't support alpha channels in 157 // general. 158 png_set_palette_to_rgb(png_ptr_); 159 channels_ = 3; 160 } else { 161 fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", bit_depth, 162 channels_, color_type); 163 error_code_ = -7; 164 } 165 } 166 167 PngHandler::~PngHandler() { 168 if (png_ptr_) { 169 png_destroy_read_struct(&png_ptr_, &info_ptr_, nullptr); 170 } 171 } 172 173 // "display" surfaces are transformed into the framebuffer's required 174 // pixel format (currently only RGBX is supported) at load time, so 175 // gr_blit() can be nothing more than a memcpy() for each row. The 176 // next two functions are the only ones that know anything about the 177 // framebuffer pixel format; they need to be modified if the 178 // framebuffer format changes (but nothing else should). 179 180 // Allocate and return a GRSurface* sufficient for storing an image of 181 // the indicated size in the framebuffer pixel format. 182 static GRSurface* init_display_surface(png_uint_32 width, png_uint_32 height) { 183 GRSurface* surface = malloc_surface(width * height * 4); 184 if (surface == NULL) return NULL; 185 186 surface->width = width; 187 surface->height = height; 188 surface->row_bytes = width * 4; 189 surface->pixel_bytes = 4; 190 191 return surface; 192 } 193 194 // Copy 'input_row' to 'output_row', transforming it to the 195 // framebuffer pixel format. The input format depends on the value of 196 // 'channels': 197 // 198 // 1 - input is 8-bit grayscale 199 // 3 - input is 24-bit RGB 200 // 4 - input is 32-bit RGBA/RGBX 201 // 202 // 'width' is the number of pixels in the row. 203 static void transform_rgb_to_draw(unsigned char* input_row, 204 unsigned char* output_row, 205 int channels, int width) { 206 int x; 207 unsigned char* ip = input_row; 208 unsigned char* op = output_row; 209 210 switch (channels) { 211 case 1: 212 // expand gray level to RGBX 213 for (x = 0; x < width; ++x) { 214 *op++ = *ip; 215 *op++ = *ip; 216 *op++ = *ip; 217 *op++ = 0xff; 218 ip++; 219 } 220 break; 221 222 case 3: 223 // expand RGBA to RGBX 224 for (x = 0; x < width; ++x) { 225 *op++ = *ip++; 226 *op++ = *ip++; 227 *op++ = *ip++; 228 *op++ = 0xff; 229 } 230 break; 231 232 case 4: 233 // copy RGBA to RGBX 234 memcpy(output_row, input_row, width*4); 235 break; 236 } 237 } 238 239 int res_create_display_surface(const char* name, GRSurface** pSurface) { 240 *pSurface = nullptr; 241 242 PngHandler png_handler(name); 243 if (!png_handler) return png_handler.error_code(); 244 245 png_structp png_ptr = png_handler.png_ptr(); 246 png_uint_32 width = png_handler.width(); 247 png_uint_32 height = png_handler.height(); 248 249 GRSurface* surface = init_display_surface(width, height); 250 if (!surface) { 251 return -8; 252 } 253 254 #if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) 255 png_set_bgr(png_ptr); 256 #endif 257 258 for (png_uint_32 y = 0; y < height; ++y) { 259 std::vector<unsigned char> p_row(width * 4); 260 png_read_row(png_ptr, p_row.data(), nullptr); 261 transform_rgb_to_draw(p_row.data(), surface->data + y * surface->row_bytes, 262 png_handler.channels(), width); 263 } 264 265 *pSurface = surface; 266 267 return 0; 268 } 269 270 int res_create_multi_display_surface(const char* name, int* frames, int* fps, 271 GRSurface*** pSurface) { 272 *pSurface = nullptr; 273 *frames = -1; 274 275 PngHandler png_handler(name); 276 if (!png_handler) return png_handler.error_code(); 277 278 png_structp png_ptr = png_handler.png_ptr(); 279 png_uint_32 width = png_handler.width(); 280 png_uint_32 height = png_handler.height(); 281 282 *frames = 1; 283 *fps = 20; 284 png_textp text; 285 int num_text; 286 if (png_get_text(png_ptr, png_handler.info_ptr(), &text, &num_text)) { 287 for (int i = 0; i < num_text; ++i) { 288 if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) { 289 *frames = atoi(text[i].text); 290 } else if (text[i].key && strcmp(text[i].key, "FPS") == 0 && text[i].text) { 291 *fps = atoi(text[i].text); 292 } 293 } 294 printf(" found frames = %d\n", *frames); 295 printf(" found fps = %d\n", *fps); 296 } 297 298 int result = 0; 299 GRSurface** surface = nullptr; 300 if (*frames <= 0 || *fps <= 0) { 301 printf("bad number of frames (%d) and/or FPS (%d)\n", *frames, *fps); 302 result = -10; 303 goto exit; 304 } 305 306 if (height % *frames != 0) { 307 printf("bad height (%d) for frame count (%d)\n", height, *frames); 308 result = -9; 309 goto exit; 310 } 311 312 surface = static_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*))); 313 if (!surface) { 314 result = -8; 315 goto exit; 316 } 317 for (int i = 0; i < *frames; ++i) { 318 surface[i] = init_display_surface(width, height / *frames); 319 if (!surface[i]) { 320 result = -8; 321 goto exit; 322 } 323 } 324 325 #if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) 326 png_set_bgr(png_ptr); 327 #endif 328 329 for (png_uint_32 y = 0; y < height; ++y) { 330 std::vector<unsigned char> p_row(width * 4); 331 png_read_row(png_ptr, p_row.data(), nullptr); 332 int frame = y % *frames; 333 unsigned char* out_row = surface[frame]->data + (y / *frames) * surface[frame]->row_bytes; 334 transform_rgb_to_draw(p_row.data(), out_row, png_handler.channels(), width); 335 } 336 337 *pSurface = surface; 338 339 exit: 340 if (result < 0) { 341 if (surface) { 342 for (int i = 0; i < *frames; ++i) { 343 free(surface[i]); 344 } 345 free(surface); 346 } 347 } 348 return result; 349 } 350 351 int res_create_alpha_surface(const char* name, GRSurface** pSurface) { 352 *pSurface = nullptr; 353 354 PngHandler png_handler(name); 355 if (!png_handler) return png_handler.error_code(); 356 357 if (png_handler.channels() != 1) { 358 return -7; 359 } 360 361 png_structp png_ptr = png_handler.png_ptr(); 362 png_uint_32 width = png_handler.width(); 363 png_uint_32 height = png_handler.height(); 364 365 GRSurface* surface = malloc_surface(width * height); 366 if (!surface) { 367 return -8; 368 } 369 surface->width = width; 370 surface->height = height; 371 surface->row_bytes = width; 372 surface->pixel_bytes = 1; 373 374 #if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) 375 png_set_bgr(png_ptr); 376 #endif 377 378 for (png_uint_32 y = 0; y < height; ++y) { 379 unsigned char* p_row = surface->data + y * surface->row_bytes; 380 png_read_row(png_ptr, p_row, nullptr); 381 } 382 383 *pSurface = surface; 384 385 return 0; 386 } 387 388 // This function tests if a locale string stored in PNG (prefix) matches 389 // the locale string provided by the system (locale). 390 bool matches_locale(const std::string& prefix, const std::string& locale) { 391 // According to the BCP 47 format, A locale string may consists of: 392 // language-{extlang}-{script}-{region}-{variant} 393 // The locale headers in PNG mostly consist of language-{region} except for sr-Latn, and some 394 // android's system locale can have the format language-{script}-{region}. 395 396 // Return true if the whole string of prefix matches the top part of locale. Otherwise try to 397 // match the locale string without the {script} section. 398 // For instance, prefix == "en" matches locale == "en-US", prefix == "sr-Latn" matches locale 399 // == "sr-Latn-BA", and prefix == "zh-CN" matches locale == "zh-Hans-CN". 400 if (android::base::StartsWith(locale, prefix)) { 401 return true; 402 } 403 404 size_t separator = prefix.find('-'); 405 if (separator == std::string::npos) { 406 return false; 407 } 408 std::regex loc_regex(prefix.substr(0, separator) + "-[A-Za-z]*" + prefix.substr(separator)); 409 return std::regex_match(locale, loc_regex); 410 } 411 412 std::vector<std::string> get_locales_in_png(const std::string& png_name) { 413 PngHandler png_handler(png_name); 414 if (!png_handler) { 415 printf("Failed to open %s, error: %d\n", png_name.c_str(), png_handler.error_code()); 416 return {}; 417 } 418 if (png_handler.channels() != 1) { 419 printf("Expect input png to have 1 data channel, this file has %d\n", png_handler.channels()); 420 return {}; 421 } 422 423 std::vector<std::string> result; 424 std::vector<unsigned char> row(png_handler.width()); 425 for (png_uint_32 y = 0; y < png_handler.height(); ++y) { 426 png_read_row(png_handler.png_ptr(), row.data(), nullptr); 427 int h = (row[3] << 8) | row[2]; 428 std::string loc(reinterpret_cast<char*>(&row[5])); 429 if (!loc.empty()) { 430 result.push_back(loc); 431 } 432 for (int i = 0; i < h; ++i, ++y) { 433 png_read_row(png_handler.png_ptr(), row.data(), nullptr); 434 } 435 } 436 437 return result; 438 } 439 440 int res_create_localized_alpha_surface(const char* name, 441 const char* locale, 442 GRSurface** pSurface) { 443 *pSurface = nullptr; 444 if (locale == nullptr) { 445 return 0; 446 } 447 448 PngHandler png_handler(name); 449 if (!png_handler) return png_handler.error_code(); 450 451 if (png_handler.channels() != 1) { 452 return -7; 453 } 454 455 png_structp png_ptr = png_handler.png_ptr(); 456 png_uint_32 width = png_handler.width(); 457 png_uint_32 height = png_handler.height(); 458 459 for (png_uint_32 y = 0; y < height; ++y) { 460 std::vector<unsigned char> row(width); 461 png_read_row(png_ptr, row.data(), nullptr); 462 int w = (row[1] << 8) | row[0]; 463 int h = (row[3] << 8) | row[2]; 464 __unused int len = row[4]; 465 char* loc = reinterpret_cast<char*>(&row[5]); 466 467 if (y + 1 + h >= height || matches_locale(loc, locale)) { 468 printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); 469 470 GRSurface* surface = malloc_surface(w * h); 471 if (!surface) { 472 return -8; 473 } 474 surface->width = w; 475 surface->height = h; 476 surface->row_bytes = w; 477 surface->pixel_bytes = 1; 478 479 for (int i = 0; i < h; ++i, ++y) { 480 png_read_row(png_ptr, row.data(), nullptr); 481 memcpy(surface->data + i * w, row.data(), w); 482 } 483 484 *pSurface = surface; 485 break; 486 } 487 488 for (int i = 0; i < h; ++i, ++y) { 489 png_read_row(png_ptr, row.data(), nullptr); 490 } 491 } 492 493 return 0; 494 } 495 496 void res_free_surface(GRSurface* surface) { 497 free(surface); 498 } 499