#ifndef MUPDF_FITZ_MATH_H1#define MUPDF_FITZ_MATH_H23#include "mupdf/fitz/system.h"45/* Multiply scaled two integers in the 0..255 range */6static inline int fz_mul255(int a, int b)7{8/* see Jim Blinn's book "Dirty Pixels" for how this works */9int x = a * b + 128;10x += x >> 8;11return x >> 8;12}1314/* Expand a value A from the 0...255 range to the 0..256 range */15#define FZ_EXPAND(A) ((A)+((A)>>7))1617/* Combine values A (in any range) and B (in the 0..256 range),18* to give a single value in the same range as A was. */19#define FZ_COMBINE(A,B) (((A)*(B))>>8)2021/* Combine values A and C (in the same (any) range) and B and D (in the22* 0..256 range), to give a single value in the same range as A and C were. */23#define FZ_COMBINE2(A,B,C,D) (FZ_COMBINE((A), (B)) + FZ_COMBINE((C), (D)))2425/* Blend SRC and DST (in the same range) together according to26* AMOUNT (in the 0...256 range). */27#define FZ_BLEND(SRC, DST, AMOUNT) ((((SRC)-(DST))*(AMOUNT) + ((DST)<<8))>>8)2829/* Range checking atof */30float fz_atof(const char *s);3132/* atoi that copes with NULL */33int fz_atoi(const char *s);3435/*36Some standard math functions, done as static inlines for speed.37People with compilers that do not adequately implement inlines may38like to reimplement these using macros.39*/40static inline float fz_abs(float f)41{42return (f < 0 ? -f : f);43}4445static inline int fz_absi(int i)46{47return (i < 0 ? -i : i);48}4950static inline float fz_min(float a, float b)51{52return (a < b ? a : b);53}5455static inline int fz_mini(int a, int b)56{57return (a < b ? a : b);58}5960static inline float fz_max(float a, float b)61{62return (a > b ? a : b);63}6465static inline int fz_maxi(int a, int b)66{67return (a > b ? a : b);68}6970static inline float fz_clamp(float f, float min, float max)71{72return (f > min ? (f < max ? f : max) : min);73}7475static inline int fz_clampi(int i, int min, int max)76{77return (i > min ? (i < max ? i : max) : min);78}7980static inline double fz_clampd(double d, double min, double max)81{82return (d > min ? (d < max ? d : max) : min);83}8485static inline void *fz_clampp(void *p, void *min, void *max)86{87return (p > min ? (p < max ? p : max) : min);88}8990#define DIV_BY_ZERO(a, b, min, max) (((a) < 0) ^ ((b) < 0) ? (min) : (max))9192/*93fz_point is a point in a two-dimensional space.94*/95typedef struct fz_point_s fz_point;96struct fz_point_s97{98float x, y;99};100101/*102fz_rect is a rectangle represented by two diagonally opposite103corners at arbitrary coordinates.104105Rectangles are always axis-aligned with the X- and Y- axes.106The relationship between the coordinates are that x0 <= x1 and107y0 <= y1 in all cases except for infinte rectangles. The area108of a rectangle is defined as (x1 - x0) * (y1 - y0). If either109x0 > x1 or y0 > y1 is true for a given rectangle then it is110defined to be infinite.111112To check for empty or infinite rectangles use fz_is_empty_rect113and fz_is_infinite_rect.114115x0, y0: The top left corner.116117x1, y1: The botton right corner.118*/119typedef struct fz_rect_s fz_rect;120struct fz_rect_s121{122float x0, y0;123float x1, y1;124};125126/*127fz_rect_min: get the minimum point from a rectangle as an fz_point.128*/129static inline fz_point *fz_rect_min(fz_rect *f)130{131return (fz_point *)&f->x0;132}133134/*135fz_rect_max: get the maximum point from a rectangle as an fz_point.136*/137static inline fz_point *fz_rect_max(fz_rect *f)138{139return (fz_point *)&f->x1;140}141142/*143fz_irect is a rectangle using integers instead of floats.144145It's used in the draw device and for pixmap dimensions.146*/147typedef struct fz_irect_s fz_irect;148struct fz_irect_s149{150int x0, y0;151int x1, y1;152};153154/*155A rectangle with sides of length one.156157The bottom left corner is at (0, 0) and the top right corner158is at (1, 1).159*/160extern const fz_rect fz_unit_rect;161162/*163An empty rectangle with an area equal to zero.164165Both the top left and bottom right corner are at (0, 0).166*/167extern const fz_rect fz_empty_rect;168extern const fz_irect fz_empty_irect;169170/*171An infinite rectangle with negative area.172173The corner (x0, y0) is at (1, 1) while the corner (x1, y1) is174at (-1, -1).175*/176extern const fz_rect fz_infinite_rect;177extern const fz_irect fz_infinite_irect;178179/*180fz_is_empty_rect: Check if rectangle is empty.181182An empty rectangle is defined as one whose area is zero.183*/184static inline int185fz_is_empty_rect(const fz_rect *r)186{187return ((r)->x0 == (r)->x1 || (r)->y0 == (r)->y1);188}189190static inline int191fz_is_empty_irect(const fz_irect *r)192{193return ((r)->x0 == (r)->x1 || (r)->y0 == (r)->y1);194}195196/*197fz_is_infinite: Check if rectangle is infinite.198199An infinite rectangle is defined as one where either of the200two relationships between corner coordinates are not true.201*/202static inline int203fz_is_infinite_rect(const fz_rect *r)204{205return ((r)->x0 > (r)->x1 || (r)->y0 > (r)->y1);206}207208static inline int209fz_is_infinite_irect(const fz_irect *r)210{211return ((r)->x0 > (r)->x1 || (r)->y0 > (r)->y1);212}213214/*215fz_matrix is a a row-major 3x3 matrix used for representing216transformations of coordinates throughout MuPDF.217218Since all points reside in a two-dimensional space, one vector219is always a constant unit vector; hence only some elements may220vary in a matrix. Below is how the elements map between221different representations.222223/ a b 0 \224| c d 0 | normally represented as [ a b c d e f ].225\ e f 1 /226*/227typedef struct fz_matrix_s fz_matrix;228struct fz_matrix_s229{230float a, b, c, d, e, f;231};232233/*234fz_identity: Identity transform matrix.235*/236extern const fz_matrix fz_identity;237238static inline fz_matrix *fz_copy_matrix(fz_matrix *restrict m, const fz_matrix *restrict s)239{240*m = *s;241return m;242}243244/*245fz_concat: Multiply two matrices.246247The order of the two matrices are important since matrix248multiplication is not commutative.249250Returns result.251252Does not throw exceptions.253*/254fz_matrix *fz_concat(fz_matrix *result, const fz_matrix *left, const fz_matrix *right);255256/*257fz_scale: Create a scaling matrix.258259The returned matrix is of the form [ sx 0 0 sy 0 0 ].260261m: Pointer to the matrix to populate262263sx, sy: Scaling factors along the X- and Y-axes. A scaling264factor of 1.0 will not cause any scaling along the relevant265axis.266267Returns m.268269Does not throw exceptions.270*/271fz_matrix *fz_scale(fz_matrix *m, float sx, float sy);272273/*274fz_pre_scale: Scale a matrix by premultiplication.275276m: Pointer to the matrix to scale277278sx, sy: Scaling factors along the X- and Y-axes. A scaling279factor of 1.0 will not cause any scaling along the relevant280axis.281282Returns m (updated).283284Does not throw exceptions.285*/286fz_matrix *fz_pre_scale(fz_matrix *m, float sx, float sy);287288/*289fz_shear: Create a shearing matrix.290291The returned matrix is of the form [ 1 sy sx 1 0 0 ].292293m: pointer to place to store returned matrix294295sx, sy: Shearing factors. A shearing factor of 0.0 will not296cause any shearing along the relevant axis.297298Returns m.299300Does not throw exceptions.301*/302fz_matrix *fz_shear(fz_matrix *m, float sx, float sy);303304/*305fz_pre_shear: Premultiply a matrix with a shearing matrix.306307The shearing matrix is of the form [ 1 sy sx 1 0 0 ].308309m: pointer to matrix to premultiply310311sx, sy: Shearing factors. A shearing factor of 0.0 will not312cause any shearing along the relevant axis.313314Returns m (updated).315316Does not throw exceptions.317*/318fz_matrix *fz_pre_shear(fz_matrix *m, float sx, float sy);319320/*321fz_rotate: Create a rotation matrix.322323The returned matrix is of the form324[ cos(deg) sin(deg) -sin(deg) cos(deg) 0 0 ].325326m: Pointer to place to store matrix327328degrees: Degrees of counter clockwise rotation. Values less329than zero and greater than 360 are handled as expected.330331Returns m.332333Does not throw exceptions.334*/335fz_matrix *fz_rotate(fz_matrix *m, float degrees);336337/*338fz_pre_rotate: Rotate a transformation by premultiplying.339340The premultiplied matrix is of the form341[ cos(deg) sin(deg) -sin(deg) cos(deg) 0 0 ].342343m: Pointer to matrix to premultiply.344345degrees: Degrees of counter clockwise rotation. Values less346than zero and greater than 360 are handled as expected.347348Returns m (updated).349350Does not throw exceptions.351*/352fz_matrix *fz_pre_rotate(fz_matrix *m, float degrees);353354/*355fz_translate: Create a translation matrix.356357The returned matrix is of the form [ 1 0 0 1 tx ty ].358359m: A place to store the created matrix.360361tx, ty: Translation distances along the X- and Y-axes. A362translation of 0 will not cause any translation along the363relevant axis.364365Returns m.366367Does not throw exceptions.368*/369fz_matrix *fz_translate(fz_matrix *m, float tx, float ty);370371/*372fz_pre_translate: Translate a matrix by premultiplication.373374m: The matrix to translate375376tx, ty: Translation distances along the X- and Y-axes. A377translation of 0 will not cause any translation along the378relevant axis.379380Returns m.381382Does not throw exceptions.383*/384fz_matrix *fz_pre_translate(fz_matrix *m, float tx, float ty);385386/*387fz_invert_matrix: Create an inverse matrix.388389inverse: Place to store inverse matrix.390391matrix: Matrix to invert. A degenerate matrix, where the392determinant is equal to zero, can not be inverted and the393original matrix is returned instead.394395Returns inverse.396397Does not throw exceptions.398*/399fz_matrix *fz_invert_matrix(fz_matrix *inverse, const fz_matrix *matrix);400401/*402fz_try_invert_matrix: Attempt to create an inverse matrix.403404inverse: Place to store inverse matrix.405406matrix: Matrix to invert. A degenerate matrix, where the407determinant is equal to zero, can not be inverted.408409Returns 1 if matrix is degenerate (singular), or 0 otherwise.410411Does not throw exceptions.412*/413int fz_try_invert_matrix(fz_matrix *inverse, const fz_matrix *matrix);414415/*416fz_is_rectilinear: Check if a transformation is rectilinear.417418Rectilinear means that no shearing is present and that any419rotations present are a multiple of 90 degrees. Usually this420is used to make sure that axis-aligned rectangles before the421transformation are still axis-aligned rectangles afterwards.422423Does not throw exceptions.424*/425int fz_is_rectilinear(const fz_matrix *m);426427/*428fz_matrix_expansion: Calculate average scaling factor of matrix.429*/430float fz_matrix_expansion(const fz_matrix *m); /* sumatrapdf */431432/*433fz_intersect_rect: Compute intersection of two rectangles.434435Given two rectangles, update the first to be the smallest436axis-aligned rectangle that covers the area covered by both437given rectangles. If either rectangle is empty then the438intersection is also empty. If either rectangle is infinite439then the intersection is simply the non-infinite rectangle.440Should both rectangles be infinite, then the intersection is441also infinite.442443Does not throw exceptions.444*/445fz_rect *fz_intersect_rect(fz_rect *restrict a, const fz_rect *restrict b);446447/*448fz_intersect_irect: Compute intersection of two bounding boxes.449450Similar to fz_intersect_rect but operates on two bounding451boxes instead of two rectangles.452453Does not throw exceptions.454*/455fz_irect *fz_intersect_irect(fz_irect *restrict a, const fz_irect *restrict b);456457/*458fz_union_rect: Compute union of two rectangles.459460Given two rectangles, update the first to be the smallest461axis-aligned rectangle that encompasses both given rectangles.462If either rectangle is infinite then the union is also infinite.463If either rectangle is empty then the union is simply the464non-empty rectangle. Should both rectangles be empty, then the465union is also empty.466467Does not throw exceptions.468*/469fz_rect *fz_union_rect(fz_rect *restrict a, const fz_rect *restrict b);470471/*472fz_irect_from_rect: Convert a rect into the minimal bounding box473that covers the rectangle.474475bbox: Place to store the returned bbox.476477rect: The rectangle to convert to a bbox.478479Coordinates in a bounding box are integers, so rounding of the480rects coordinates takes place. The top left corner is rounded481upwards and left while the bottom right corner is rounded482downwards and to the right.483484Returns bbox (updated).485486Does not throw exceptions.487*/488489fz_irect *fz_irect_from_rect(fz_irect *restrict bbox, const fz_rect *restrict rect);490491/*492fz_round_rect: Round rectangle coordinates.493494Coordinates in a bounding box are integers, so rounding of the495rects coordinates takes place. The top left corner is rounded496upwards and left while the bottom right corner is rounded497downwards and to the right.498499This differs from fz_irect_from_rect, in that fz_irect_from_rect500slavishly follows the numbers (i.e any slight over/under calculations501can cause whole extra pixels to be added). fz_round_rect502allows for a small amount of rounding error when calculating503the bbox.504505Does not throw exceptions.506*/507fz_irect *fz_round_rect(fz_irect *restrict bbox, const fz_rect *restrict rect);508509/*510fz_rect_from_irect: Convert a bbox into a rect.511512For our purposes, a rect can represent all the values we meet in513a bbox, so nothing can go wrong.514515rect: A place to store the generated rectangle.516517bbox: The bbox to convert.518519Returns rect (updated).520521Does not throw exceptions.522*/523fz_rect *fz_rect_from_irect(fz_rect *restrict rect, const fz_irect *restrict bbox);524525/*526fz_expand_rect: Expand a bbox by a given amount in all directions.527528Does not throw exceptions.529*/530fz_rect *fz_expand_rect(fz_rect *b, float expand);531532/*533fz_include_point_in_rect: Expand a bbox to include a given point.534To create a rectangle that encompasses a sequence of points, the535rectangle must first be set to be the empty rectangle at one of536the points before including the others.537*/538fz_rect *fz_include_point_in_rect(fz_rect *r, const fz_point *p);539540/*541fz_translate_irect: Translate bounding box.542543Translate a bbox by a given x and y offset. Allows for overflow.544545Does not throw exceptions.546*/547fz_irect *fz_translate_irect(fz_irect *a, int xoff, int yoff);548549/*550fz_transform_point: Apply a transformation to a point.551552transform: Transformation matrix to apply. See fz_concat,553fz_scale, fz_rotate and fz_translate for how to create a554matrix.555556point: Pointer to point to update.557558Returns transform (unchanged).559560Does not throw exceptions.561*/562fz_point *fz_transform_point(fz_point *restrict point, const fz_matrix *restrict transform);563fz_point *fz_transform_point_xy(fz_point *restrict point, const fz_matrix *restrict transform, float x, float y);564565/*566fz_transform_vector: Apply a transformation to a vector.567568transform: Transformation matrix to apply. See fz_concat,569fz_scale and fz_rotate for how to create a matrix. Any570translation will be ignored.571572vector: Pointer to vector to update.573574Does not throw exceptions.575*/576fz_point *fz_transform_vector(fz_point *restrict vector, const fz_matrix *restrict transform);577578/*579fz_transform_rect: Apply a transform to a rectangle.580581After the four corner points of the axis-aligned rectangle582have been transformed it may not longer be axis-aligned. So a583new axis-aligned rectangle is created covering at least the584area of the transformed rectangle.585586transform: Transformation matrix to apply. See fz_concat,587fz_scale and fz_rotate for how to create a matrix.588589rect: Rectangle to be transformed. The two special cases590fz_empty_rect and fz_infinite_rect, may be used but are591returned unchanged as expected.592593Does not throw exceptions.594*/595fz_rect *fz_transform_rect(fz_rect *restrict rect, const fz_matrix *restrict transform);596597/*598fz_normalize_vector: Normalize a vector to length one.599*/600void fz_normalize_vector(fz_point *p);601602void fz_gridfit_matrix(fz_matrix *m);603604float fz_matrix_max_expansion(const fz_matrix *m);605606#endif607608609