From 00fdd0019370abcc67cf95e9c604aeda4637ac8b Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 21 Jan 2023 14:00:22 +0100 Subject: Add libfonts_get_subpixel_map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 1 + libfonts.h | 31 ++++ libfonts_get_subpixel_map.c | 439 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 471 insertions(+) create mode 100644 libfonts_get_subpixel_map.c diff --git a/Makefile b/Makefile index 32ad9a5..624232d 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ PUBLIC_OBJ =\ libfonts_get_output_dpi.o\ libfonts_get_output_rendering_settings.o\ libfonts_get_subpixel_expansion.o\ + libfonts_get_subpixel_map.o\ libfonts_get_subpixel_order_class.o\ libfonts_parse_alias_line.o\ libfonts_parse_dir_line.o\ diff --git a/libfonts.h b/libfonts.h index 3ecd123..f771ab8 100644 --- a/libfonts.h +++ b/libfonts.h @@ -2465,5 +2465,36 @@ int libfonts_unget_subpixel_order_class(enum libfonts_subpixel_order *, */ int libfonts_get_subpixel_expansion(enum libfonts_subpixel_order_class, size_t *restrict, size_t *restrict); +/** + * Get the abstract colour layout for a subpixel structure + * + * @param layout The subpixel layout + * @param rowsize A value such that `y * rowsize + x` is the position + * `map` for the vertical position `y` (counted top-down from 0) + * with the horizontal position `x` (counted left-to-right from 0) + * @param map Output buffer for the subpixel mapping in the layout: where + * each cell (there may be multiple) set to the value 0 has the colour + * output in the second parameter of `libfonts_get_subpixel_order_class`, + * each cell (there may be multiple) set to the value 1 has the colour + * output in the third parameter of `libfonts_get_subpixel_order_class`, + * and each cell (there may be multiple) set to the value 2 has the colour + * output in the fourth parameter of `libfonts_get_subpixel_order_class`; + * each cell will be given one of these values. The map's width and height + * is assumed to be the width and height multipliers, respectively, as + * output by `libfonts_get_subpixel_expansion` + * @param n0p Output parameter for the number of cells given the value 0 + * @param n1p Output parameter for the number of cells given the value 1 + * @param n2p Output parameter for the number of cells given the value 2 + * @return 0 on success, -1 on failure + * + * @throws EINVAL `layout` is `LIBFONTS_SUBPIXEL_ORDER_CLASS_OTHER` + * @throws EINVAL `layout` is unrecognised + * @throws EINVAL `rowsize` is less than the width multiplier output by + * `libfonts_get_subpixel_expansion` (this is however only + * checked if it is used) + */ +int libfonts_get_subpixel_map(enum libfonts_subpixel_order_class, size_t, uint8_t *restrict, + uint8_t *restrict, uint8_t *restrict, uint8_t *restrict); + #endif diff --git a/libfonts_get_subpixel_map.c b/libfonts_get_subpixel_map.c new file mode 100644 index 0000000..9581a57 --- /dev/null +++ b/libfonts_get_subpixel_map.c @@ -0,0 +1,439 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +int +libfonts_get_subpixel_map(enum libfonts_subpixel_order_class layout, size_t rowsize, uint8_t *restrict map, + uint8_t *restrict n0p, uint8_t *restrict n1p, uint8_t *restrict n2p) +{ + size_t n0, n1, n2; + +#define SET_1_X_3(R1C1, R1C2, R1C3)\ + do {\ + if (map) {\ + map[0] = (R1C1);\ + map[1] = (R1C2);\ + map[2] = (R1C3);\ + }\ + n0 = 1;\ + n1 = 1;\ + n2 = 1;\ + } while (0) + +#define SET_3_X_1(R1C1, R2C1, R3C1)\ + do {\ + if (map) {\ + if (rowsize < 1)\ + goto einval;\ + map[0 * rowsize] = (R1C1);\ + map[1 * rowsize] = (R2C1);\ + map[2 * rowsize] = (R3C1);\ + }\ + n0 = 1;\ + n1 = 1;\ + n2 = 1;\ + } while (0) + +#define SET_2_X_2(R1C1, R1C2, R2C1, R2C2)\ + do {\ + if (map) {\ + if (rowsize < 2)\ + goto einval;\ + map[0 * rowsize + 0] = (R1C1);\ + map[0 * rowsize + 1] = (R1C2);\ + map[1 * rowsize + 0] = (R2C1);\ + map[1 * rowsize + 1] = (R2C2);\ + }\ + n0 = 2;\ + n1 = 1;\ + n2 = 1;\ + } while (0) + +#define SET_3_X_2(R1C1, R1C2, R2C1, R2C2, R3C1, R3C2)\ + do {\ + if (map) {\ + if (rowsize < 2)\ + goto einval;\ + map[0 * rowsize + 0] = (R1C1);\ + map[0 * rowsize + 1] = (R1C2);\ + map[1 * rowsize + 0] = (R2C1);\ + map[1 * rowsize + 1] = (R2C2);\ + map[2 * rowsize + 0] = (R3C1);\ + map[2 * rowsize + 1] = (R3C2);\ + }\ + n0 = 2;\ + n1 = 2;\ + n2 = 2;\ + } while (0) + +#define SET_2_X_3(R1C1, R1C2, R1C3, R2C1, R2C2, R2C3)\ + do {\ + if (map) {\ + if (rowsize < 3)\ + goto einval;\ + map[0 * rowsize + 0] = (R1C1);\ + map[0 * rowsize + 1] = (R1C2);\ + map[0 * rowsize + 2] = (R1C3);\ + map[1 * rowsize + 0] = (R2C1);\ + map[1 * rowsize + 1] = (R2C2);\ + map[1 * rowsize + 2] = (R2C3);\ + }\ + n0 = 2;\ + n1 = 2;\ + n2 = 2;\ + } while (0) + + switch (layout) { + case LIBFONTS_SUBPIXEL_ORDER_CLASS_123: + SET_1_X_3(0, 1, 2); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_1_2_3: + SET_3_X_1(0, + 1, + 2); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_11_23: + SET_2_X_2(0, 0, + 1, 2); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_21_31: + SET_2_X_2(1, 0, + 2, 0); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_32_11: + SET_2_X_2(2, 1, + 0, 0); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_13_12: + SET_2_X_2(0, 2, + 0, 1); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_BALANCED_11_23: + SET_3_X_2(0, 0, + 1, 2, + 1, 2); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_BALANCED_21_31: + SET_2_X_3(1, 1, 0, + 2, 2, 0); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_BALANCED_32_11: + SET_3_X_2(2, 1, + 2, 1, + 0, 0); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_BALANCED_13_12: + SET_2_X_3(0, 2, 2, + 0, 1, 1); + break; + + case LIBFONTS_SUBPIXEL_ORDER_CLASS_OTHER: + default: + goto einval; + } + + if (n0p) + *n0p = n0; + if (n1p) + *n1p = n1; + if (n2p) + *n2p = n2; + + return 0; + +einval: + errno = EINVAL; + return -1; +} + + +#else + + +int +main(void) +{ + uint8_t map[128], ns[3]; + size_t i, j, rowsize; + +#define T(L)\ + do {\ + errno = 0;\ + ASSERT(libfonts_get_subpixel_map(L, 16, NULL, NULL, NULL, NULL) == -1);\ + ASSERT(errno == EINVAL);\ + \ + errno = 0;\ + ASSERT(libfonts_get_subpixel_map(L, 16, map, NULL, NULL, NULL) == -1);\ + ASSERT(errno == EINVAL);\ + \ + errno = 0;\ + ASSERT(libfonts_get_subpixel_map(L, 16, map, &ns[0], &ns[1], &ns[2]) == -1);\ + ASSERT(errno == EINVAL);\ + } while (0) + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_OTHER); + T((enum libfonts_subpixel_order_class)999); + +#undef T + +#define TEST_1_X_3(R1C1, R1C2, R1C3)\ + do {\ + ASSERT(map[0] == (R1C1) - 1);\ + ASSERT(map[1] == (R1C2) - 1);\ + ASSERT(map[2] == (R1C3) - 1);\ + ASSERT(ns[0] == 1);\ + ASSERT(ns[1] == 1);\ + ASSERT(ns[2] == 1);\ + } while (0) + +#define TEST_3_X_1(R1C1, R2C1, R3C1)\ + do {\ + ASSERT(map[0 * rowsize] == (R1C1) - 1);\ + ASSERT(map[1 * rowsize] == (R2C1) - 1);\ + ASSERT(map[2 * rowsize] == (R3C1) - 1);\ + ASSERT(ns[0] == 1);\ + ASSERT(ns[1] == 1);\ + ASSERT(ns[2] == 1);\ + } while (0) + +#define TEST_2_X_2(R1C1, R1C2, R2C1, R2C2)\ + do {\ + ASSERT(map[0 * rowsize + 0] == (R1C1) - 1);\ + ASSERT(map[0 * rowsize + 1] == (R1C2) - 1);\ + ASSERT(map[1 * rowsize + 0] == (R2C1) - 1);\ + ASSERT(map[1 * rowsize + 1] == (R2C2) - 1);\ + ASSERT(ns[0] == 2);\ + ASSERT(ns[1] == 1);\ + ASSERT(ns[2] == 1);\ + } while (0) + +#define TEST_3_X_2(R1C1, R1C2, R2C1, R2C2, R3C1, R3C2)\ + do {\ + ASSERT(map[0 * rowsize + 0] == (R1C1) - 1);\ + ASSERT(map[0 * rowsize + 1] == (R1C2) - 1);\ + ASSERT(map[1 * rowsize + 0] == (R2C1) - 1);\ + ASSERT(map[1 * rowsize + 1] == (R2C2) - 1);\ + ASSERT(map[2 * rowsize + 0] == (R3C1) - 1);\ + ASSERT(map[2 * rowsize + 1] == (R3C2) - 1);\ + ASSERT(ns[0] == 2);\ + ASSERT(ns[1] == 2);\ + ASSERT(ns[2] == 2);\ + } while (0) + +#define TEST_2_X_3(R1C1, R1C2, R1C3, R2C1, R2C2, R2C3)\ + do {\ + ASSERT(map[0 * rowsize + 0] == (R1C1) - 1);\ + ASSERT(map[0 * rowsize + 1] == (R1C2) - 1);\ + ASSERT(map[0 * rowsize + 2] == (R1C3) - 1);\ + ASSERT(map[1 * rowsize + 0] == (R2C1) - 1);\ + ASSERT(map[1 * rowsize + 1] == (R2C2) - 1);\ + ASSERT(map[1 * rowsize + 2] == (R2C3) - 1);\ + ASSERT(ns[0] == 2);\ + ASSERT(ns[1] == 2);\ + ASSERT(ns[2] == 2);\ + } while (0) + +#define TEST_3_X_2_BALANCED_2_X_2(R1C1, R1C2, R2C1, R2C2)\ + TEST_3_X_2((R1C1), (R1C2),\ + (R1C1) == (R1C2) ? (R2C1) : (R1C1),\ + (R1C1) == (R1C2) ? (R2C2) : (R1C2),\ + (R2C1), (R2C2)) + +#define TEST_2_X_3_BALANCED_2_X_2(R1C1, R1C2, R2C1, R2C2)\ + TEST_2_X_3((R1C1), (R1C1) == (R2C1) ? (R1C2) : (R1C1), (R1C2),\ + (R2C1), (R1C1) == (R2C1) ? (R2C2) : (R2C1), (R2C2)) + +#define CHECK_NS(H, W, N0, N1, N2)\ + do {\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + for (i = 0; i < (H); i++) {\ + for (j = 0; j < (W); j++) {\ + ASSERT(map[i * rowsize + j] <= 2);\ + ns[map[i * rowsize + j]] += 1;\ + }\ + }\ + ASSERT(ns[0] == N0);\ + ASSERT(ns[1] == N1);\ + ASSERT(ns[2] == N2);\ + } while (0) + +#define T_(L, ROWSIZE, H, W, MAP, N0, N1, N2, NSCHECK, MAPTEST)\ + do {\ + rowsize = (ROWSIZE);\ + \ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, rowsize, MAP, NULL, NULL, NULL));\ + ASSERT(errno == EDOM);\ + NSCHECK;\ + MAPTEST;\ + \ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, rowsize, MAP, &ns[0], NULL, NULL));\ + ASSERT(errno == EDOM);\ + ASSERT(ns[0] == (N0));\ + NSCHECK;\ + MAPTEST;\ + \ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, rowsize, MAP, NULL, &ns[1], NULL));\ + ASSERT(errno == EDOM);\ + ASSERT(ns[1] == (N1));\ + NSCHECK;\ + MAPTEST;\ + \ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, rowsize, MAP, &ns[0], &ns[1], NULL));\ + ASSERT(errno == EDOM);\ + ASSERT(ns[0] == (N0));\ + ASSERT(ns[1] == (N1));\ + NSCHECK;\ + MAPTEST;\ + \ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, rowsize, MAP, NULL, NULL, &ns[2]));\ + ASSERT(errno == EDOM);\ + ASSERT(ns[2] == (N2));\ + NSCHECK;\ + MAPTEST;\ + \ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, rowsize, MAP, &ns[0], NULL, &ns[2]));\ + ASSERT(errno == EDOM);\ + ASSERT(ns[0] == (N0));\ + ASSERT(ns[2] == (N2));\ + NSCHECK;\ + MAPTEST;\ + \ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, rowsize, MAP, NULL, &ns[1], &ns[2]));\ + ASSERT(errno == EDOM);\ + ASSERT(ns[1] == (N1));\ + ASSERT(ns[2] == (N2));\ + NSCHECK;\ + MAPTEST;\ + \ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, rowsize, MAP, &ns[0], &ns[1], &ns[2]));\ + ASSERT(errno == EDOM);\ + ASSERT(ns[0] == (N0));\ + ASSERT(ns[1] == (N1));\ + ASSERT(ns[2] == (N2));\ + NSCHECK;\ + MAPTEST;\ + } while (0) + +#define T2_(L, ROWSIZE, H, N0, N1, N2, N0P, N1P, N2P)\ + do {\ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, ROWSIZE, NULL, N0P, N1P, N2P));\ + ASSERT(errno == EDOM);\ + ASSERT(ns[0] == (N0));\ + ASSERT(ns[1] == (N1));\ + ASSERT(ns[2] == (N2));\ + \ + if (H > 1) {\ + errno = 0;\ + ASSERT(libfonts_get_subpixel_map(L, ROWSIZE, map, N0P, N1P, N2P) == -1);\ + ASSERT(errno == EINVAL);\ + } else {\ + errno = EDOM;\ + ns[0] = 0, ns[1] = 0, ns[2] = 0;\ + ASSERT(!libfonts_get_subpixel_map(L, ROWSIZE, map, N0P, N1P, N2P));\ + ASSERT(errno == EDOM);\ + ASSERT(ns[0] == (N0));\ + ASSERT(ns[1] == (N1));\ + ASSERT(ns[2] == (N2));\ + }\ + } while (0) + +#define T(L, H, W, N0, N1, N2, MAPTEST)\ + do {\ + T_(L, W, H, W, map, N0, N1, N2, CHECK_NS(H, W, N0, N1, N2), MAPTEST);\ + T_(L, W, H, W, NULL, N0, N1, N2,,);\ + T_(L, W + 1, H, W, map, N0, N1, N2, CHECK_NS(H, W, N0, N1, N2), MAPTEST);\ + T_(L, W + 1, H, W, NULL, N0, N1, N2,,);\ + T2_(L, W - 1, H, 0, 0, 0, NULL, NULL, NULL);\ + T2_(L, W - 1, H, N0, 0, 0, &ns[0], NULL, NULL);\ + T2_(L, W - 1, H, 0, N1, 0, NULL, &ns[1], NULL);\ + T2_(L, W - 1, H, N0, N1, 0, &ns[0], &ns[1], NULL);\ + T2_(L, W - 1, H, 0, 0, N2, NULL, NULL, &ns[2]);\ + T2_(L, W - 1, H, N0, 0, N2, &ns[0], NULL, &ns[2]);\ + T2_(L, W - 1, H, 0, N1, N2, NULL, &ns[1], &ns[2]);\ + T2_(L, W - 1, H, N0, N1, N2, &ns[0], &ns[1], &ns[2]);\ + } while (0) + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_123, + 1, 3, 1, 1, 1, + TEST_1_X_3(1, 2, 3)); + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_1_2_3, + 3, 1, 1, 1, 1, + TEST_3_X_1(1, + 2, + 3)); + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_11_23, + 2, 2, 2, 1, 1, + TEST_2_X_2(1, 1, + 2, 3)); + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_21_31, + 2, 2, 2, 1, 1, + TEST_2_X_2(2, 1, + 3, 1)); + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_32_11, + 2, 2, 2, 1, 1, + TEST_2_X_2(3, 2, + 1, 1)); + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_13_12, + 2, 2, 2, 1, 1, + TEST_2_X_2(1, 3, + 1, 2)); + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_BALANCED_11_23, + 3, 2, 2, 2, 2, + TEST_3_X_2(1, 1, + 2, 3, + 2, 3)); + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_BALANCED_21_31, + 2, 3, 2, 2, 2, + TEST_2_X_3(2, 2, 1, + 3, 3, 1)); + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_BALANCED_32_11, + 3, 2, 2, 2, 2, + TEST_3_X_2_BALANCED_2_X_2(3, 2, + 1, 1)); + + T(LIBFONTS_SUBPIXEL_ORDER_CLASS_BALANCED_13_12, + 2, 3, 2, 2, 2, + TEST_2_X_3_BALANCED_2_X_2(1, 3, + 1, 2)); + + return 0; +} + + +#endif -- cgit v1.2.3-70-g09d2