aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2023-01-21 14:00:22 +0100
committerMattias Andrée <maandree@kth.se>2023-01-21 14:00:22 +0100
commit00fdd0019370abcc67cf95e9c604aeda4637ac8b (patch)
treea0d1a8f7baec414c143436550146d565fde02e79
parentAdd tests for libfonts_get_subpixel_expansion (diff)
downloadlibfonts-00fdd0019370abcc67cf95e9c604aeda4637ac8b.tar.gz
libfonts-00fdd0019370abcc67cf95e9c604aeda4637ac8b.tar.bz2
libfonts-00fdd0019370abcc67cf95e9c604aeda4637ac8b.tar.xz
Add libfonts_get_subpixel_map
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--Makefile1
-rw-r--r--libfonts.h31
-rw-r--r--libfonts_get_subpixel_map.c439
3 files changed, 471 insertions, 0 deletions
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