aboutsummaryrefslogblamecommitdiffstats
path: root/libfonts_get_output_dpi.c
blob: c56cc49d272337d932739ae479534be87429e0e0 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                         
                   
            

 


                                                                                     
                          










                                           
                                                             







                                              
                               







                                         


                                                                                           
 
                               





                                        


                                                                                           
 
                               

                           









                                                                                           




                 


                                                                         
                                                

                                              
                                          
 


                                  
 
                                                                                                     
                                 
 



                                           
 

                                                                                                       
 



                                                                         
 

                                      
 

                                                                                                     

         






                                                                 










                                                                         
 






                                                     


                 





     
          
 













                                                                                                     










                                                              


































































                                                                     


                                                      




























                                                                    
                                                                                















































































































                                                                                                    

                                                                 













                                                                                                    

                                                                 













                                                                                                       

                                                                 
 












                                                                                                       

                                                                 
 




                 
/* 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