diff options
Diffstat (limited to 'libfonts_calculate_subpixel_order.c')
-rw-r--r-- | libfonts_calculate_subpixel_order.c | 172 |
1 files changed, 132 insertions, 40 deletions
diff --git a/libfonts_calculate_subpixel_order.c b/libfonts_calculate_subpixel_order.c index 6d26921..746cece 100644 --- a/libfonts_calculate_subpixel_order.c +++ b/libfonts_calculate_subpixel_order.c @@ -2,51 +2,43 @@ #include "libfonts.h" -enum libfonts_subpixel_order -libfonts_calculate_subpixel_order(enum libfonts_subpixel_order unrotated, enum libfonts_orientation rotation) -{ - int rot; +#define TOLERANCE 0.000001 - switch (rotation) { - case LIBFONTS_ORIENTATION_UNKNOWN: - default: - switch (unrotated) { - case LIBFONTS_SUBPIXEL_ORDER_UNKNOWN: - case LIBFONTS_SUBPIXEL_ORDER_NONRGB: - case LIBFONTS_SUBPIXEL_ORDER_NONLINEAR: - case LIBFONTS_SUBPIXEL_ORDER_OTHER: - return unrotated; - default: - return LIBFONTS_SUBPIXEL_ORDER_UNKNOWN; - } - break; - case LIBFONTS_ORIENTATION_0_DEGREES_CLOCKWISE: - return unrotated; +static void +transform(double *x_out, double *y_out, double x, double y, const struct libfonts_transformation *transformation) +{ + double a = transformation->m[0][0], b = transformation->m[0][1], c = transformation->m[0][2]; + double d = transformation->m[1][0], e = transformation->m[1][1], f = transformation->m[1][2]; + double g = transformation->m[2][0], h = transformation->m[2][1], i = transformation->m[2][2]; + double w = g*x + h*y + i; + *x_out = (a*x + b*y + c) / w; + *y_out = (d*x + e*y + f) / w; +} - case LIBFONTS_ORIENTATION_90_DEGREES_CLOCKWISE: - rot = 1; - break; - case LIBFONTS_ORIENTATION_180_DEGREES_CLOCKWISE: - rot = 2; - break; +static int +eq(double a, double b) +{ + return b - TOLERANCE <= a && a <= b + TOLERANCE; +} - case LIBFONTS_ORIENTATION_270_DEGREES_CLOCKWISE: - rot = 3; - break; - case LIBFONTS_ORIENTATION_OTHER: - switch (unrotated) { - case LIBFONTS_SUBPIXEL_ORDER_UNKNOWN: - case LIBFONTS_SUBPIXEL_ORDER_NONRGB: - case LIBFONTS_SUBPIXEL_ORDER_NONLINEAR: - return unrotated; - default: - return LIBFONTS_SUBPIXEL_ORDER_NONLINEAR; - } - break; - } +enum libfonts_subpixel_order +libfonts_calculate_subpixel_order(enum libfonts_subpixel_order unrotated, const struct libfonts_transformation *transformation) +{ +#define ASIS 0 +#define ROTATED_90_DEG_CLOCKWISE 1 +#define ROTATED_180_DEG_CLOCKWISE 2 +#define ROTATED_270_DEG_CLOCKWISE 3 +#define FLIPPED -1 +#define FLOPPED -2 +#define TRANSPOSED -3 +#define ANTITRANSPOSED -4 +#define OTHER -5 + + double x[4], y[4], xmin, ymin, xmax, ymax, t1, t2; + int trans, i, j; switch (unrotated) { case LIBFONTS_SUBPIXEL_ORDER_UNKNOWN: @@ -55,6 +47,106 @@ libfonts_calculate_subpixel_order(enum libfonts_subpixel_order unrotated, enum l case LIBFONTS_SUBPIXEL_ORDER_OTHER: return unrotated; default: - return ((unrotated + rot) & 3) + (unrotated & ~3); + break; + } + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if (!eq(transformation->m[i][j], 0)) + goto known; + return LIBFONTS_SUBPIXEL_ORDER_UNKNOWN; +known: + + transform(&x[0], &y[0], 0, 0, transformation); + transform(&x[1], &y[1], 1, 0, transformation); + transform(&x[2], &y[2], 0, 1, transformation); + transform(&x[3], &y[3], 1, 1, transformation); + + t1 = x[0] < x[1] ? x[0] : x[1]; + t2 = x[2] < x[3] ? x[2] : x[3]; + xmin = t1 < t2 ? t1 : t2; + + t1 = y[0] < y[1] ? y[0] : y[1]; + t2 = y[2] < y[3] ? y[2] : y[3]; + ymin = t1 < t2 ? t1 : t2; + + for (i = 0; i < 4; i++) { + x[i] -= xmin; + y[i] -= ymin; + } + + t1 = x[0] > x[1] ? x[0] : x[1]; + t2 = x[2] > x[3] ? x[2] : x[3]; + xmax = t1 > t2 ? t1 : t2; + + t1 = y[0] > y[1] ? y[0] : y[1]; + t2 = y[2] > y[3] ? y[2] : y[3]; + ymax = t1 > t2 ? t1 : t2; + + for (i = 0; i < 4; i++) { + x[i] /= xmax; + y[i] /= ymax; + } + + /* Here we select the inverse transformation from what `transformation` + * applies, as `transformation` applies to the image on the output and + * we want to know how the output is physically configured, which is + * the inverse */ + trans = OTHER; + if (eq(x[0], 0) && eq(y[0], 0) && eq(x[3], 1) && eq(y[3], 1)) { + if (eq(x[1], 1) && eq(y[1], 0) && eq(x[2], 0) && eq(y[2], 1)) + trans = ASIS; + else if (eq(x[2], 1) && eq(y[2], 0) && eq(x[1], 0) && eq(y[1], 1)) + trans = TRANSPOSED; + } else if (eq(x[1], 0) && eq(y[1], 0) && eq(x[2], 1) && eq(y[2], 1)) { + if (eq(x[0], 1) && eq(y[0], 0) && eq(x[3], 0) && eq(y[3], 1)) + trans = FLOPPED; + else if (eq(x[3], 1) && eq(y[3], 0) && eq(x[0], 0) && eq(y[0], 1)) + trans = ROTATED_90_DEG_CLOCKWISE; + } else if (eq(x[2], 0) && eq(y[2], 0) && eq(x[1], 1) && eq(y[1], 1)) { + if (eq(x[0], 1) && eq(y[0], 0) && eq(x[3], 0) && eq(y[3], 1)) + trans = ROTATED_270_DEG_CLOCKWISE; + else if (eq(x[3], 1) && eq(y[3], 0) && eq(x[0], 0) && eq(y[0], 1)) + trans = FLIPPED; + } else if (eq(x[3], 0) && eq(y[3], 0) && eq(x[0], 1) && eq(y[0], 1)) { + if (eq(x[1], 1) && eq(y[1], 0) && eq(x[2], 0) && eq(y[2], 1)) + trans = ANTITRANSPOSED; + else if (eq(x[2], 1) && eq(y[2], 0) && eq(x[1], 0) && eq(y[1], 1)) + trans = ROTATED_180_DEG_CLOCKWISE; + } + + switch (trans) { + case OTHER: + return LIBFONTS_SUBPIXEL_ORDER_NONLINEAR; + + case ANTITRANSPOSED: + if (unrotated <= LIBFONTS_SUBPIXEL_ORDER_G_R_B) + return unrotated ^ 1; + else + return unrotated ^ 5; + + case TRANSPOSED: + if (unrotated <= LIBFONTS_SUBPIXEL_ORDER_G_R_B) + return unrotated ^ 1; + else + return 8 - (unrotated & 7) + (unrotated & ~7); + + case FLOPPED: + if (unrotated <= LIBFONTS_SUBPIXEL_ORDER_G_R_B) + return unrotated ^ ((~unrotated << 1) & 2); + else + return unrotated ^ 4 ^ ((unrotated << 1) & 2); + + case FLIPPED: + if (unrotated <= LIBFONTS_SUBPIXEL_ORDER_G_R_B) + return unrotated ^ ((unrotated << 1) & 2); + else + return unrotated ^ 4 ^ ((~unrotated << 1) & 2); + + case ASIS: + return unrotated; + + default: + return ((unrotated + trans) & 3) + (unrotated & ~3); } } |