/* See LICENSE file for copyright and license details. */ #include "common.h" #ifndef TEST static int invert(struct libfonts_transformation *out, const struct libfonts_transformation *in) { double m[3][6], t; int i, j; #define SWAP_ROWS(A, B)\ do {\ for (i = 0; i < 6; i++) {\ t = m[A][i];\ m[A][i] = m[B][i];\ m[B][i] = t;\ }\ } while (0) /* Copy in-matrix and augment with identity-matrix */ for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { m[i][j] = in->m[i][j]; m[i][j + 3] = 0; } m[i][i + 3] = 1; } /* Set m[0][0] ≠ 0 */ if (eq(m[0][0], 0)) { if (!eq(m[1][0], 0)) SWAP_ROWS(0, 1); else if (!eq(m[2][0], 0)) SWAP_ROWS(0, 2); else return 0; } /* Set m[0][0] = 1 */ for (t = m[0][0], i = 0; i < 6; i++) m[0][i] /= t; /* Set m[1][0] = 0 */ for (t = m[1][0], i = 0; i < 6; i++) m[1][i] -= t * m[0][i]; /* Set m[2][0] = 0 */ for (t = m[2][0], i = 0; i < 6; i++) m[2][i] -= t * m[0][i]; /* Set m[1][1] ≠ 0 */ if (eq(m[1][1], 0)) { if (!eq(m[2][1], 0)) SWAP_ROWS(1, 2); else return 0; } /* Set m[1][1] = 1 */ for (t = m[1][1], i = 1; i < 6; i++) m[1][i] /= t; /* Set m[2][1] = 0 */ for (t = m[2][1], i = 1; i < 6; i++) m[2][i] -= t * m[1][i]; /* Set m[0][1] = 0 */ for (t = m[0][1], i = 1; i < 6; i++) m[0][i] -= t * m[1][i]; /* Set m[2][2] ≠ 0 */ if (eq(m[2][2], 0)) return 0; /* Set m[2][2] = 1 */ for (t = m[2][2], i = 2; i < 6; i++) m[2][i] /= t; /* Set m[1][2] = 0 */ for (t = m[1][2], i = 2; i < 6; i++) m[1][i] -= t * m[2][i]; /* Set m[0][2] = 0 */ for (t = m[0][2], i = 2; i < 6; i++) m[0][i] -= t * m[2][i]; /* Output augment */ for (i = 0; i < 3; i++) { out->m[i][0] = m[i][3]; out->m[i][1] = m[i][4]; out->m[i][2] = m[i][5]; } return 1; } int libfonts_get_output_dpi(struct libfonts_output *output, const char *edid) { struct libfonts_transformation invtrans; int width, height; char width1, width2, height1, height2; double x[4], y[4], c1, c2, c3, c4; if (edid) { output->dpi_x = 0; output->dpi_y = 0; if (strncasecmp(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2) || strlen(edid) < 256) return 0; width1 = edid[21 * 2 + 0]; width2 = edid[21 * 2 + 1]; height1 = edid[22 * 2 + 0]; height2 = edid[22 * 2 + 1]; if (!isxdigit(width1) || !isxdigit(width2) || !isxdigit(height1) || !isxdigit(height2)) return 0; width = ((width1 & 15) + (width1 > '9' ? 9 : 0)) << 4; width |= (width2 & 15) + (width2 > '9' ? 9 : 0); height = ((height1 & 15) + (height1 > '9' ? 9 : 0)) << 4; height |= (height2 & 15) + (height2 > '9' ? 9 : 0); if (!width || !height) return 0; output->dpi_x = (double)output->unrotated_output_width / (double)width * 254 / 100; output->dpi_y = (double)output->unrotated_output_height / (double)height * 254 / 100; } if (!invert(&invtrans, &output->output_transformation)) { output->dpi_x = 0; output->dpi_y = 0; return 0; } transform(&x[0], &y[0], 0, 0, &invtrans); transform(&x[1], &y[1], output->dpi_x, 0, &invtrans); transform(&x[2], &y[2], 0, output->dpi_y, &invtrans); transform(&x[3], &y[3], output->dpi_x, output->dpi_y, &invtrans); c1 = x[0] > x[1] ? x[0] - x[1] : x[1] - x[0]; c2 = x[0] > x[2] ? x[0] - x[2] : x[2] - x[0]; c3 = x[3] > x[1] ? x[3] - x[1] : x[1] - x[3]; c4 = x[3] > x[2] ? x[3] - x[2] : x[2] - x[3]; c1 = c1 > c2 ? c1 : c2; c3 = c3 > c4 ? c3 : c4; output->dpi_x = c1 > c3 ? c1 : c3; c1 = y[0] > y[1] ? y[0] - y[1] : y[1] - y[0]; c2 = y[0] > y[2] ? y[0] - y[2] : y[2] - y[0]; c3 = y[3] > y[1] ? y[3] - y[1] : y[1] - y[3]; c4 = y[3] > y[2] ? y[3] - y[2] : y[2] - y[3]; c1 = c1 > c2 ? c1 : c2; c3 = c3 > c4 ? c3 : c4; output->dpi_y = c1 > c3 ? c1 : c3; return 1; } #else int main(void) { #define T_(MAT, XOUT, YOUT, RET)\ do {\ output.dpi_x = 100;\ output.dpi_y = 150;\ memcpy(&output.output_transformation, &MAT, sizeof(struct libfonts_transformation));\ ASSERT(libfonts_get_output_dpi(&output, NULL) == RET);\ ASSERT(eq(output.dpi_x, XOUT));\ ASSERT(eq(output.dpi_y, YOUT));\ } while (0) #define T(MAT, XOUT, YOUT) T_(MAT, XOUT, YOUT, 1) #define ASIS(MAT) T(MAT, 100, 150) #define SWAPS(MAT) T(MAT, 150, 100) #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunsuffixed-float-constants" #endif const double sqrt1half = 0.7071067811865475; #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic pop #endif char edid[512]; struct libfonts_output output; struct libfonts_transformation asis_matrix = {.m = { {+1, 0, 0}, { 0, +1, 0}, { 0, 0, 1}}}; struct libfonts_transformation rot90cw_matrix = {.m = { { 0, -1, 0}, {+1, 0, 0}, { 0, 0, 1}}}; struct libfonts_transformation rot180cw_matrix = {.m = { {-1, 0, 0}, { 0, -1, 0}, { 0, 0, 1}}}; struct libfonts_transformation rot270cw_matrix = {.m = { { 0, +1, 0}, {-1, 0, 0}, { 0, 0, 1}}}; struct libfonts_transformation flip_matrix = {.m = { {+1, 0, 0}, { 0, -1, 0}, { 0, 0, 1}}}; struct libfonts_transformation flop_matrix = {.m = { {-1, 0, 0}, { 0, +1, 0}, { 0, 0, 1}}}; struct libfonts_transformation transpose_matrix = {.m = { { 0, +1, 0}, {+1, 0, 0}, { 0, 0, 1}}}; struct libfonts_transformation antitranspose_matrix = {.m = { { 0, -1, 0}, {-1, 0, 0}, { 0, 0, 1}}}; struct libfonts_transformation xdouble_matrix = {.m = { {+2, 0, 0}, { 0, +1, 0}, { 0, 0, 1}}}; struct libfonts_transformation ydouble_matrix = {.m = { {+1, 0, 0}, { 0, +2, 0}, { 0, 0, 1}}}; struct libfonts_transformation xydouble_matrix = {.m = { {+2, 0, 0}, { 0, +2, 0}, { 0, 0, 1}}}; struct libfonts_transformation xtranslate_matrix = {.m = { {+1, 0, 1}, { 0, +1, 0}, { 0, 0, 1}}}; struct libfonts_transformation ytranslate_matrix = {.m = { {+1, 0, 0}, { 0, +1, 1}, { 0, 0, 1}}}; struct libfonts_transformation xytranslate_matrix = {.m = { {+1, 0, 1}, { 0, +1, 1}, { 0, 0, 1}}}; struct libfonts_transformation xshear_matrix = {.m = { {+1, +1, 0}, { 0, +1, 0}, { 0, 0, 1}}}; struct libfonts_transformation yshear_matrix = {.m = { {+1, 0, 0}, {+1, +1, 0}, { 0, 0, 1}}}; struct libfonts_transformation rot45cw_matrix = {.m = { {+sqrt1half, -sqrt1half, 0}, {+sqrt1half, +sqrt1half, 0}, { 0, 0, 1}}}; struct libfonts_transformation uninvertable_matrix = {.m = { {1, 1, 0}, {1, 1, 0}, {0, 0, 1}}}; struct libfonts_transformation null_matrix = {.m = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}}; ASIS(asis_matrix); ASIS(rot180cw_matrix); ASIS(flip_matrix); ASIS(flop_matrix); ASIS(xtranslate_matrix); ASIS(ytranslate_matrix); ASIS(xytranslate_matrix); SWAPS(rot90cw_matrix); SWAPS(rot270cw_matrix); SWAPS(transpose_matrix); SWAPS(antitranspose_matrix); T(xdouble_matrix, 50, 150); T(ydouble_matrix, 100, 75); T(xydouble_matrix, 50, 75); T(xshear_matrix, 150, 150); /* not important */ T(yshear_matrix, 100, 150); /* not important */ T(rot45cw_matrix, 150 * sqrt1half, 150 * sqrt1half); /* not important */ T_(uninvertable_matrix, 0, 0, 0); T_(null_matrix, 0, 0, 0); output.unrotated_output_width = 400; output.unrotated_output_height = 500; output.dpi_x = 100; output.dpi_y = 150; strcpy(edid, "00""FF""FF""FF""FF""FF""FF""00"); memcpy(&output.output_transformation, &asis_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 0); ASSERT(eq(output.dpi_x, 0)); ASSERT(eq(output.dpi_y, 0)); output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = 'A'; edid[21 * 2 + 1] = 'A'; edid[22 * 2 + 0] = 'A'; edid[22 * 2 + 1] = 'A'; edid[255] = '\0'; memcpy(&output.output_transformation, &asis_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 0); ASSERT(eq(output.dpi_x, 0)); ASSERT(eq(output.dpi_y, 0)); output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = 'A'; edid[21 * 2 + 1] = 'A'; edid[22 * 2 + 0] = 'A'; edid[22 * 2 + 1] = 'A'; edid[254] = '\0'; memcpy(&output.output_transformation, &asis_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 0); ASSERT(eq(output.dpi_x, 0)); ASSERT(eq(output.dpi_y, 0)); output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = 'X'; edid[21 * 2 + 1] = 'X'; edid[22 * 2 + 0] = 'X'; edid[22 * 2 + 1] = 'X'; edid[256] = '\0'; memcpy(&output.output_transformation, &asis_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 0); ASSERT(eq(output.dpi_x, 0)); ASSERT(eq(output.dpi_y, 0)); output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = 'A'; edid[21 * 2 + 1] = 'A'; edid[22 * 2 + 0] = '0'; edid[22 * 2 + 1] = '0'; edid[256] = '\0'; memcpy(&output.output_transformation, &asis_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 0); ASSERT(eq(output.dpi_x, 0)); ASSERT(eq(output.dpi_y, 0)); output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = '0'; edid[21 * 2 + 1] = '0'; edid[22 * 2 + 0] = 'A'; edid[22 * 2 + 1] = 'A'; edid[256] = '\0'; memcpy(&output.output_transformation, &asis_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 0); ASSERT(eq(output.dpi_x, 0)); ASSERT(eq(output.dpi_y, 0)); output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = '0'; edid[21 * 2 + 1] = '0'; edid[22 * 2 + 0] = '0'; edid[22 * 2 + 1] = '0'; edid[256] = '\0'; memcpy(&output.output_transformation, &asis_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 0); ASSERT(eq(output.dpi_x, 0)); ASSERT(eq(output.dpi_y, 0)); output.unrotated_output_width = 400; output.unrotated_output_height = 500; output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = 'A'; edid[21 * 2 + 1] = 'A'; edid[22 * 2 + 0] = 'A'; edid[22 * 2 + 1] = 'A'; edid[256] = '\0'; memcpy(&output.output_transformation, &asis_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 1); ASSERT(eq(output.dpi_x, (double)254 / 100 * 400 / 0xAA)); ASSERT(eq(output.dpi_y, (double)254 / 100 * 500 / 0xAA)); output.unrotated_output_width = 400; output.unrotated_output_height = 500; output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = '9'; edid[21 * 2 + 1] = '9'; edid[22 * 2 + 0] = '8'; edid[22 * 2 + 1] = '8'; edid[256] = '\0'; memcpy(&output.output_transformation, &asis_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 1); ASSERT(eq(output.dpi_x, (double)254 / 100 * 400 / 0x99)); ASSERT(eq(output.dpi_y, (double)254 / 100 * 500 / 0x88)); output.unrotated_output_width = 400; output.unrotated_output_height = 500; output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = '9'; edid[21 * 2 + 1] = '9'; edid[22 * 2 + 0] = '8'; edid[22 * 2 + 1] = '8'; edid[256] = '\0'; memcpy(&output.output_transformation, &rot90cw_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 1); ASSERT(eq(output.dpi_y, (double)254 / 100 * 400 / 0x99)); ASSERT(eq(output.dpi_x, (double)254 / 100 * 500 / 0x88)); output.unrotated_output_width = 400; output.unrotated_output_height = 500; output.dpi_x = 100; output.dpi_y = 150; memset(edid, '0', sizeof(edid)); memcpy(edid, "00""FF""FF""FF""FF""FF""FF""00", 8 * 2); edid[21 * 2 + 0] = '9'; edid[21 * 2 + 1] = '9'; edid[22 * 2 + 0] = '8'; edid[22 * 2 + 1] = '8'; edid[400] = '\0'; memcpy(&output.output_transformation, &rot90cw_matrix, sizeof(struct libfonts_transformation)); ASSERT(libfonts_get_output_dpi(&output, edid) == 1); ASSERT(eq(output.dpi_y, (double)254 / 100 * 400 / 0x99)); ASSERT(eq(output.dpi_x, (double)254 / 100 * 500 / 0x88)); return 0; } #endif