|
28 | 28 | #include "nativeWindowHandle.h"
|
29 | 29 | #include "virtualFileSystem.h"
|
30 | 30 | #include "get_x11.h"
|
| 31 | +#include "pnmImage.h" |
| 32 | +#include "pnmFileTypeRegistry.h" |
31 | 33 |
|
32 | 34 | #include <errno.h>
|
33 | 35 | #include <fcntl.h>
|
@@ -2303,109 +2305,144 @@ read_ico(istream &ico) {
|
2303 | 2305 | // Seek to the image in the ICO.
|
2304 | 2306 | ico.seekg(entries[entry].offset);
|
2305 | 2307 | if (!ico.good()) goto cleanup;
|
2306 |
| - ico.read(reinterpret_cast<char *>(&infoHeader), sizeof(IcoInfoHeader)); |
2307 |
| - if (!ico.good()) goto cleanup; |
2308 |
| - bitsPerPixel = infoHeader.bitsPerPixel; |
2309 | 2308 |
|
2310 |
| - // TODO: Support PNG compressed ICOs. |
2311 |
| - if (infoHeader.compression != 0) goto cleanup; |
| 2309 | + if (ico.peek() == 0x89) { |
| 2310 | + // Hang on, this is actually a PNG header. |
| 2311 | + PNMImage img; |
| 2312 | + PNMFileTypeRegistry *reg = PNMFileTypeRegistry::get_global_ptr(); |
| 2313 | + if (!img.read(ico, "", reg->get_type_from_extension("png"))) { |
| 2314 | + goto cleanup; |
| 2315 | + } |
| 2316 | + img.set_maxval(255); |
| 2317 | + |
| 2318 | + image = XcursorImageCreate(img.get_x_size(), img.get_y_size()); |
2312 | 2319 |
|
2313 |
| - // Load the color palette, if one exists. |
2314 |
| - if (bitsPerPixel != 24 && bitsPerPixel != 32) { |
2315 |
| - colorCount = 1 << bitsPerPixel; |
2316 |
| - palette = new IcoColor[colorCount]; |
2317 |
| - ico.read(reinterpret_cast<char *>(palette), colorCount * sizeof(IcoColor)); |
| 2320 | + xel *ptr = img.get_array(); |
| 2321 | + xelval *alpha = img.get_alpha_array(); |
| 2322 | + size_t num_pixels = (size_t)img.get_x_size() * (size_t)img.get_y_size(); |
| 2323 | + unsigned int *dest = image->pixels; |
| 2324 | + |
| 2325 | + if (alpha != NULL) { |
| 2326 | + for (size_t p = 0; p < num_pixels; ++p) { |
| 2327 | + *dest++ = (*alpha << 24U) | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b); |
| 2328 | + ++ptr; |
| 2329 | + ++alpha; |
| 2330 | + } |
| 2331 | + } else { |
| 2332 | + for (size_t p = 0; p < num_pixels; ++p) { |
| 2333 | + *dest++ = 0xff000000U | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b); |
| 2334 | + ++ptr; |
| 2335 | + } |
| 2336 | + } |
| 2337 | + |
| 2338 | + } else { |
| 2339 | + ico.read(reinterpret_cast<char *>(&infoHeader), sizeof(IcoInfoHeader)); |
2318 | 2340 | if (!ico.good()) goto cleanup;
|
2319 |
| - } |
| 2341 | + bitsPerPixel = infoHeader.bitsPerPixel; |
2320 | 2342 |
|
2321 |
| - // Read in the pixel data. |
2322 |
| - xorBmpSize = (infoHeader.width * (infoHeader.height / 2) * bitsPerPixel) / 8; |
2323 |
| - andBmpSize = (infoHeader.width * (infoHeader.height / 2)) / 8; |
2324 |
| - curXor = xorBmp = new char[xorBmpSize]; |
2325 |
| - curAnd = andBmp = new char[andBmpSize]; |
2326 |
| - ico.read(xorBmp, xorBmpSize); |
2327 |
| - if (!ico.good()) goto cleanup; |
2328 |
| - ico.read(andBmp, andBmpSize); |
2329 |
| - if (!ico.good()) goto cleanup; |
| 2343 | + if (infoHeader.compression != 0) goto cleanup; |
2330 | 2344 |
|
2331 |
| - // If this is an actual CUR not an ICO set up the hotspot properly. |
2332 |
| - image = XcursorImageCreate(infoHeader.width, infoHeader.height / 2); |
2333 |
| - if (header.type == 2) { image->xhot = entries[entry].xhot; image->yhot = entries[entry].yhot; } |
2334 |
| - |
2335 |
| - // Support all the formats that GIMP supports, minus PNG compressed ICOs. |
2336 |
| - // Would need to use libpng to decode the compressed ones. |
2337 |
| - switch (bitsPerPixel) { |
2338 |
| - case 1: |
2339 |
| - case 4: |
2340 |
| - case 8: |
2341 |
| - // For colors less that a byte wide, shift and mask the palette indices |
2342 |
| - // off each element of the xorBmp and append them to the image. |
2343 |
| - mask = ((1 << bitsPerPixel) - 1); |
2344 |
| - for (i = image->height - 1; i >= 0; i--) { |
2345 |
| - for (j = 0; j < image->width; j += 8 / bitsPerPixel) { |
2346 |
| - for (k = 0; k < 8 / bitsPerPixel; k++) { |
2347 |
| - shift = 8 - ((k + 1) * bitsPerPixel); |
2348 |
| - color = palette[(*curXor & (mask << shift)) >> shift]; |
2349 |
| - image->pixels[(i * image->width) + j + k] = (color.red << 16) + |
2350 |
| - (color.green << 8) + |
2351 |
| - (color.blue); |
2352 |
| - } |
| 2345 | + // Load the color palette, if one exists. |
| 2346 | + if (bitsPerPixel != 24 && bitsPerPixel != 32) { |
| 2347 | + colorCount = 1 << bitsPerPixel; |
| 2348 | + palette = new IcoColor[colorCount]; |
| 2349 | + ico.read(reinterpret_cast<char *>(palette), colorCount * sizeof(IcoColor)); |
| 2350 | + if (!ico.good()) goto cleanup; |
| 2351 | + } |
2353 | 2352 |
|
2354 |
| - curXor++; |
2355 |
| - } |
| 2353 | + // Read in the pixel data. |
| 2354 | + xorBmpSize = (infoHeader.width * (infoHeader.height / 2) * bitsPerPixel) / 8; |
| 2355 | + andBmpSize = (infoHeader.width * (infoHeader.height / 2)) / 8; |
| 2356 | + curXor = xorBmp = new char[xorBmpSize]; |
| 2357 | + curAnd = andBmp = new char[andBmpSize]; |
| 2358 | + ico.read(xorBmp, xorBmpSize); |
| 2359 | + if (!ico.good()) goto cleanup; |
| 2360 | + ico.read(andBmp, andBmpSize); |
| 2361 | + if (!ico.good()) goto cleanup; |
2356 | 2362 |
|
2357 |
| - // Set the alpha byte properly according to the andBmp. |
2358 |
| - for (j = 0; j < image->width; j += 8) { |
2359 |
| - for (k = 0; k < 8; k++) { |
2360 |
| - shift = 7 - k; |
2361 |
| - image->pixels[(i * image->width) + j + k] |= |
2362 |
| - ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24); |
| 2363 | + image = XcursorImageCreate(infoHeader.width, infoHeader.height / 2); |
| 2364 | + |
| 2365 | + // Support all the formats that GIMP supports. |
| 2366 | + switch (bitsPerPixel) { |
| 2367 | + case 1: |
| 2368 | + case 4: |
| 2369 | + case 8: |
| 2370 | + // For colors less that a byte wide, shift and mask the palette indices |
| 2371 | + // off each element of the xorBmp and append them to the image. |
| 2372 | + mask = ((1 << bitsPerPixel) - 1); |
| 2373 | + for (i = image->height - 1; i >= 0; i--) { |
| 2374 | + for (j = 0; j < image->width; j += 8 / bitsPerPixel) { |
| 2375 | + for (k = 0; k < 8 / bitsPerPixel; k++) { |
| 2376 | + shift = 8 - ((k + 1) * bitsPerPixel); |
| 2377 | + color = palette[(*curXor & (mask << shift)) >> shift]; |
| 2378 | + image->pixels[(i * image->width) + j + k] = (color.red << 16) + |
| 2379 | + (color.green << 8) + |
| 2380 | + (color.blue); |
| 2381 | + } |
| 2382 | + |
| 2383 | + curXor++; |
2363 | 2384 | }
|
2364 | 2385 |
|
2365 |
| - curAnd++; |
2366 |
| - } |
2367 |
| - } |
| 2386 | + // Set the alpha byte properly according to the andBmp. |
| 2387 | + for (j = 0; j < image->width; j += 8) { |
| 2388 | + for (k = 0; k < 8; k++) { |
| 2389 | + shift = 7 - k; |
| 2390 | + image->pixels[(i * image->width) + j + k] |= |
| 2391 | + ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24); |
| 2392 | + } |
2368 | 2393 |
|
2369 |
| - break; |
2370 |
| - case 24: |
2371 |
| - // Pack each of the three bytes into a single color, BGR -> 0RGB |
2372 |
| - for (i = image->height - 1; i >= 0; i--) { |
2373 |
| - for (j = 0; j < image->width; j++) { |
2374 |
| - image->pixels[(i * image->width) + j] = (*(curXor + 2) << 16) + |
2375 |
| - (*(curXor + 1) << 8) + (*curXor); |
2376 |
| - curXor += 3; |
| 2394 | + curAnd++; |
| 2395 | + } |
2377 | 2396 | }
|
| 2397 | + break; |
2378 | 2398 |
|
2379 |
| - // Set the alpha byte properly according to the andBmp. |
2380 |
| - for (j = 0; j < image->width; j += 8) { |
2381 |
| - for (k = 0; k < 8; k++) { |
2382 |
| - shift = 7 - k; |
2383 |
| - image->pixels[(i * image->width) + j + k] |= |
2384 |
| - ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24); |
| 2399 | + case 24: |
| 2400 | + // Pack each of the three bytes into a single color, BGR -> 0RGB |
| 2401 | + for (i = image->height - 1; i >= 0; i--) { |
| 2402 | + for (j = 0; j < image->width; j++) { |
| 2403 | + image->pixels[(i * image->width) + j] = (*(curXor + 2) << 16) + |
| 2404 | + (*(curXor + 1) << 8) + (*curXor); |
| 2405 | + curXor += 3; |
2385 | 2406 | }
|
2386 | 2407 |
|
2387 |
| - curAnd++; |
2388 |
| - } |
| 2408 | + // Set the alpha byte properly according to the andBmp. |
| 2409 | + for (j = 0; j < image->width; j += 8) { |
| 2410 | + for (k = 0; k < 8; k++) { |
| 2411 | + shift = 7 - k; |
| 2412 | + image->pixels[(i * image->width) + j + k] |= |
| 2413 | + ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24); |
| 2414 | + } |
2389 | 2415 |
|
2390 |
| - } |
| 2416 | + curAnd++; |
| 2417 | + } |
| 2418 | + } |
| 2419 | + break; |
2391 | 2420 |
|
2392 |
| - break; |
2393 |
| - case 32: |
2394 |
| - // Pack each of the four bytes into a single color, BGRA -> ARGB |
2395 |
| - for (i = image->height - 1; i >= 0; i--) { |
2396 |
| - for (j = 0; j < image->width; j++) { |
2397 |
| - image->pixels[(i * image->width) + j] = (*(curXor + 3) << 24) + |
2398 |
| - (*(curXor + 2) << 16) + |
2399 |
| - (*(curXor + 1) << 8) + |
2400 |
| - (*curXor); |
2401 |
| - curXor += 4; |
| 2421 | + case 32: |
| 2422 | + // Pack each of the four bytes into a single color, BGRA -> ARGB |
| 2423 | + for (i = image->height - 1; i >= 0; i--) { |
| 2424 | + for (j = 0; j < image->width; j++) { |
| 2425 | + image->pixels[(i * image->width) + j] = (*(curXor + 3) << 24) + |
| 2426 | + (*(curXor + 2) << 16) + |
| 2427 | + (*(curXor + 1) << 8) + |
| 2428 | + (*curXor); |
| 2429 | + curXor += 4; |
| 2430 | + } |
2402 | 2431 | }
|
| 2432 | + break; |
| 2433 | + |
| 2434 | + default: |
| 2435 | + goto cleanup; |
2403 | 2436 | }
|
| 2437 | + } |
2404 | 2438 |
|
2405 |
| - break; |
2406 |
| - default: |
2407 |
| - goto cleanup; |
2408 |
| - break; |
| 2439 | + // If this is an actual CUR not an ICO set up the hotspot properly. |
| 2440 | + if (header.type == 2) { |
| 2441 | + image->xhot = entries[entry].xhot; |
| 2442 | + image->yhot = entries[entry].yhot; |
| 2443 | + } else { |
| 2444 | + image->xhot = 0; |
| 2445 | + image->yhot = 0; |
2409 | 2446 | }
|
2410 | 2447 |
|
2411 | 2448 | ret = XcursorImageLoadCursor(_display, image);
|
|
0 commit comments