78 lines
3.3 KiB
C++
78 lines
3.3 KiB
C++
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
#include "fcitx-utils/log.h"
|
|
#include "../src/imageloader.h"
|
|
|
|
using namespace fcitx::m3ui;
|
|
|
|
int main() {
|
|
FCITX_ASSERT(!loadRasterImage({}));
|
|
FCITX_ASSERT(!loadSvgImage({}));
|
|
FCITX_ASSERT(!loadRasterImage({'b', 'a', 'd'}));
|
|
FCITX_ASSERT(!loadSvgImage({'b', 'a', 'd'}));
|
|
|
|
// Valid PNG bytes exercise the real incremental decoder, regardless of
|
|
// extension. The reference must remain valid after loader destruction.
|
|
LoadedSurface surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 16, 16));
|
|
std::vector<uint8_t> png;
|
|
FCITX_ASSERT(cairo_surface_write_to_png_stream(
|
|
surface.get(),
|
|
+[](void *data, const unsigned char *bytes, unsigned int length) {
|
|
auto &out = *static_cast<std::vector<uint8_t> *>(data);
|
|
out.insert(out.end(), bytes, bytes + length);
|
|
return CAIRO_STATUS_SUCCESS;
|
|
},
|
|
&png) == CAIRO_STATUS_SUCCESS);
|
|
auto image = loadRasterImage(png);
|
|
FCITX_ASSERT(image);
|
|
FCITX_ASSERT(gdk_pixbuf_get_width(image.get()) == 16);
|
|
FCITX_ASSERT(gdk_pixbuf_get_height(image.get()) == 16);
|
|
png[16] = 255; // Huge IHDR, rejected before entering libpng.
|
|
FCITX_ASSERT(!loadRasterImage(png));
|
|
png.resize(23);
|
|
FCITX_ASSERT(!loadRasterImage(png));
|
|
|
|
// A real non-PNG image exercises size-prepared rather than PNG preflight.
|
|
gchar *bmpData = nullptr;
|
|
gsize bmpSize = 0;
|
|
FCITX_ASSERT(gdk_pixbuf_save_to_buffer(image.get(), &bmpData, &bmpSize,
|
|
"bmp", nullptr, nullptr));
|
|
std::vector<uint8_t> bmp(bmpData, bmpData + bmpSize);
|
|
g_free(bmpData);
|
|
FCITX_ASSERT(loadRasterImage(bmp));
|
|
// BMP BITMAPINFOHEADER width is little-endian at byte 18.
|
|
FCITX_ASSERT(bmp.size() > 26 && bmp[14] >= 40);
|
|
bmp[18] = 1;
|
|
bmp[19] = 32; // 8193 pixels wide
|
|
bmp[20] = bmp[21] = 0;
|
|
FCITX_ASSERT(!loadRasterImage(bmp));
|
|
|
|
auto svg = [](const std::string &text) {
|
|
return loadSvgImage(std::vector<uint8_t>(text.begin(), text.end()));
|
|
};
|
|
auto rendered = svg("<svg xmlns='http://www.w3.org/2000/svg' width='16' "
|
|
"height='16'><rect width='16' height='16' "
|
|
"fill='red'/></svg>");
|
|
FCITX_ASSERT(rendered);
|
|
FCITX_ASSERT(cairo_surface_get_type(rendered.get()) == CAIRO_SURFACE_TYPE_IMAGE);
|
|
FCITX_ASSERT(cairo_image_surface_get_width(rendered.get()) == 16);
|
|
FCITX_ASSERT(cairo_image_surface_get_height(rendered.get()) == 16);
|
|
cairo_surface_flush(rendered.get());
|
|
const auto *pixel = reinterpret_cast<const uint32_t *>(
|
|
cairo_image_surface_get_data(rendered.get()));
|
|
FCITX_ASSERT(pixel[0] == 0xffff0000); // Native-endian Cairo ARGB32.
|
|
FCITX_ASSERT(!svg("<svg xmlns='http://www.w3.org/2000/svg' "
|
|
"width='1e30' height='16'/>"));
|
|
FCITX_ASSERT(!svg("<svg xmlns='http://www.w3.org/2000/svg' "
|
|
"width='8192' height='8192'/>"));
|
|
FCITX_ASSERT(!svg("<svg xmlns='http://www.w3.org/2000/svg' "
|
|
"width='0' height='16'/>"));
|
|
FCITX_ASSERT(!svg("<svg xmlns='http://www.w3.org/2000/svg'"));
|
|
|
|
std::vector<uint8_t> oversized(16 * 1024 * 1024 + 1);
|
|
FCITX_ASSERT(!loadRasterImage(oversized));
|
|
FCITX_ASSERT(!loadSvgImage(oversized));
|
|
}
|