| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885 |
- // Copyright (C) 2004-2025 Artifex Software, Inc.
- //
- // This file is part of MuPDF.
- //
- // MuPDF is free software: you can redistribute it and/or modify it under the
- // terms of the GNU Affero General Public License as published by the Free
- // Software Foundation, either version 3 of the License, or (at your option)
- // any later version.
- //
- // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
- // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
- // details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
- //
- // Alternative licensing terms are available from the licensor.
- // For commercial licensing, see <https://www.artifex.com/> or contact
- // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
- // CA 94129, USA, for further information.
- #include "mupdf/fitz.h"
- #include <math.h>
- #include <float.h>
- #include <limits.h>
- #define MAX4(a,b,c,d) fz_max(fz_max(a,b), fz_max(c,d))
- #define MIN4(a,b,c,d) fz_min(fz_min(a,b), fz_min(c,d))
- /* A useful macro to add with overflow detection and clamping.
- We want to do "b = a + x", but to allow for overflow. Consider the
- top bits, and the cases in which overflow occurs:
- overflow a x b ~a^x a^b (~a^x)&(a^b)
- no 0 0 0 1 0 0
- yes 0 0 1 1 1 1
- no 0 1 0 0 0 0
- no 0 1 1 0 1 0
- no 1 0 0 0 1 0
- no 1 0 1 0 0 0
- yes 1 1 0 1 1 1
- no 1 1 1 1 0 0
- */
- #define ADD_WITH_SAT(b,a,x) \
- ((b) = (a) + (x), (b) = (((~(a)^(x))&((a)^(b))) < 0 ? ((x) < 0 ? INT_MIN : INT_MAX) : (b)))
- /* Matrices, points and affine transformations */
- const fz_matrix fz_identity = { 1, 0, 0, 1, 0, 0 };
- fz_matrix
- fz_concat(fz_matrix one, fz_matrix two)
- {
- fz_matrix dst;
- dst.a = one.a * two.a + one.b * two.c;
- dst.b = one.a * two.b + one.b * two.d;
- dst.c = one.c * two.a + one.d * two.c;
- dst.d = one.c * two.b + one.d * two.d;
- dst.e = one.e * two.a + one.f * two.c + two.e;
- dst.f = one.e * two.b + one.f * two.d + two.f;
- return dst;
- }
- fz_matrix
- fz_scale(float sx, float sy)
- {
- fz_matrix m;
- m.a = sx; m.b = 0;
- m.c = 0; m.d = sy;
- m.e = 0; m.f = 0;
- return m;
- }
- fz_matrix
- fz_pre_scale(fz_matrix m, float sx, float sy)
- {
- m.a *= sx;
- m.b *= sx;
- m.c *= sy;
- m.d *= sy;
- return m;
- }
- fz_matrix
- fz_post_scale(fz_matrix m, float sx, float sy)
- {
- m.a *= sx;
- m.b *= sy;
- m.c *= sx;
- m.d *= sy;
- m.e *= sx;
- m.f *= sy;
- return m;
- }
- fz_matrix
- fz_shear(float h, float v)
- {
- fz_matrix m;
- m.a = 1; m.b = v;
- m.c = h; m.d = 1;
- m.e = 0; m.f = 0;
- return m;
- }
- fz_matrix
- fz_pre_shear(fz_matrix m, float h, float v)
- {
- float a = m.a;
- float b = m.b;
- m.a += v * m.c;
- m.b += v * m.d;
- m.c += h * a;
- m.d += h * b;
- return m;
- }
- fz_matrix
- fz_rotate(float theta)
- {
- fz_matrix m;
- float s;
- float c;
- while (theta < 0)
- theta += 360;
- while (theta >= 360)
- theta -= 360;
- if (fabsf(0 - theta) < FLT_EPSILON)
- {
- s = 0;
- c = 1;
- }
- else if (fabsf(90.0f - theta) < FLT_EPSILON)
- {
- s = 1;
- c = 0;
- }
- else if (fabsf(180.0f - theta) < FLT_EPSILON)
- {
- s = 0;
- c = -1;
- }
- else if (fabsf(270.0f - theta) < FLT_EPSILON)
- {
- s = -1;
- c = 0;
- }
- else
- {
- s = sinf(theta * FZ_PI / 180);
- c = cosf(theta * FZ_PI / 180);
- }
- m.a = c; m.b = s;
- m.c = -s; m.d = c;
- m.e = 0; m.f = 0;
- return m;
- }
- fz_matrix
- fz_pre_rotate(fz_matrix m, float theta)
- {
- while (theta < 0)
- theta += 360;
- while (theta >= 360)
- theta -= 360;
- if (fabsf(0 - theta) < FLT_EPSILON)
- {
- /* Nothing to do */
- }
- else if (fabsf(90.0f - theta) < FLT_EPSILON)
- {
- float a = m.a;
- float b = m.b;
- m.a = m.c;
- m.b = m.d;
- m.c = -a;
- m.d = -b;
- }
- else if (fabsf(180.0f - theta) < FLT_EPSILON)
- {
- m.a = -m.a;
- m.b = -m.b;
- m.c = -m.c;
- m.d = -m.d;
- }
- else if (fabsf(270.0f - theta) < FLT_EPSILON)
- {
- float a = m.a;
- float b = m.b;
- m.a = -m.c;
- m.b = -m.d;
- m.c = a;
- m.d = b;
- }
- else
- {
- float s = sinf(theta * FZ_PI / 180);
- float c = cosf(theta * FZ_PI / 180);
- float a = m.a;
- float b = m.b;
- m.a = c * a + s * m.c;
- m.b = c * b + s * m.d;
- m.c =-s * a + c * m.c;
- m.d =-s * b + c * m.d;
- }
- return m;
- }
- fz_matrix
- fz_translate(float tx, float ty)
- {
- fz_matrix m;
- m.a = 1; m.b = 0;
- m.c = 0; m.d = 1;
- m.e = tx; m.f = ty;
- return m;
- }
- fz_matrix
- fz_pre_translate(fz_matrix m, float tx, float ty)
- {
- m.e += tx * m.a + ty * m.c;
- m.f += tx * m.b + ty * m.d;
- return m;
- }
- fz_matrix
- fz_transform_page(fz_rect mediabox, float resolution, float rotate)
- {
- float user_w, user_h, pixel_w, pixel_h;
- fz_rect pixel_box;
- fz_matrix matrix;
- /* Adjust scaling factors to cover whole pixels */
- user_w = mediabox.x1 - mediabox.x0;
- user_h = mediabox.y1 - mediabox.y0;
- pixel_w = floorf(user_w * resolution / 72 + 0.5f);
- pixel_h = floorf(user_h * resolution / 72 + 0.5f);
- matrix = fz_pre_rotate(fz_scale(pixel_w / user_w, pixel_h / user_h), rotate);
- /* Adjust the page origin to sit at 0,0 after rotation */
- pixel_box = fz_transform_rect(mediabox, matrix);
- matrix.e -= pixel_box.x0;
- matrix.f -= pixel_box.y0;
- return matrix;
- }
- fz_matrix
- fz_invert_matrix(fz_matrix src)
- {
- float a = src.a;
- float det = a * src.d - src.b * src.c;
- if (det < -FLT_EPSILON || det > FLT_EPSILON)
- {
- fz_matrix dst;
- float rdet = 1 / det;
- dst.a = src.d * rdet;
- dst.b = -src.b * rdet;
- dst.c = -src.c * rdet;
- dst.d = a * rdet;
- a = -src.e * dst.a - src.f * dst.c;
- dst.f = -src.e * dst.b - src.f * dst.d;
- dst.e = a;
- return dst;
- }
- return src;
- }
- int
- fz_try_invert_matrix(fz_matrix *dst, fz_matrix src)
- {
- double sa = (double)src.a;
- double sb = (double)src.b;
- double sc = (double)src.c;
- double sd = (double)src.d;
- double da, db, dc, dd;
- double det = sa * sd - sb * sc;
- if (det >= -DBL_EPSILON && det <= DBL_EPSILON)
- return 1;
- det = 1 / det;
- da = sd * det;
- dst->a = (float)da;
- db = -sb * det;
- dst->b = (float)db;
- dc = -sc * det;
- dst->c = (float)dc;
- dd = sa * det;
- dst->d = (float)dd;
- da = -src.e * da - src.f * dc;
- dst->f = (float)(-src.e * db - src.f * dd);
- dst->e = (float)da;
- return 0;
- }
- int
- fz_is_rectilinear(fz_matrix m)
- {
- return (fabsf(m.b) < FLT_EPSILON && fabsf(m.c) < FLT_EPSILON) ||
- (fabsf(m.a) < FLT_EPSILON && fabsf(m.d) < FLT_EPSILON);
- }
- float
- fz_matrix_expansion(fz_matrix m)
- {
- return sqrtf(fabsf(m.a * m.d - m.b * m.c));
- }
- float
- fz_matrix_max_expansion(fz_matrix m)
- {
- float max = fabsf(m.a);
- float x = fabsf(m.b);
- if (max < x)
- max = x;
- x = fabsf(m.c);
- if (max < x)
- max = x;
- x = fabsf(m.d);
- if (max < x)
- max = x;
- return max;
- }
- fz_point
- fz_transform_point(fz_point p, fz_matrix m)
- {
- float x = p.x;
- p.x = x * m.a + p.y * m.c + m.e;
- p.y = x * m.b + p.y * m.d + m.f;
- return p;
- }
- fz_point
- fz_transform_point_xy(float x, float y, fz_matrix m)
- {
- fz_point p;
- p.x = x * m.a + y * m.c + m.e;
- p.y = x * m.b + y * m.d + m.f;
- return p;
- }
- fz_point
- fz_transform_vector(fz_point p, fz_matrix m)
- {
- float x = p.x;
- p.x = x * m.a + p.y * m.c;
- p.y = x * m.b + p.y * m.d;
- return p;
- }
- fz_point
- fz_normalize_vector(fz_point p)
- {
- float len = p.x * p.x + p.y * p.y;
- if (len != 0)
- {
- len = sqrtf(len);
- p.x /= len;
- p.y /= len;
- }
- return p;
- }
- /* Rectangles and bounding boxes */
- /* biggest and smallest integers that a float can represent perfectly (i.e. 24 bits) */
- #define MAX_SAFE_INT 16777216
- #define MIN_SAFE_INT -16777216
- const fz_rect fz_infinite_rect = { FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT };
- const fz_rect fz_empty_rect = { FZ_MAX_INF_RECT, FZ_MAX_INF_RECT, FZ_MIN_INF_RECT, FZ_MIN_INF_RECT };
- const fz_rect fz_invalid_rect = { 0, 0, -1, -1 };
- const fz_rect fz_unit_rect = { 0, 0, 1, 1 };
- const fz_irect fz_infinite_irect = { FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT };
- const fz_irect fz_empty_irect = { FZ_MAX_INF_RECT, FZ_MAX_INF_RECT, FZ_MIN_INF_RECT, FZ_MIN_INF_RECT };
- const fz_irect fz_invalid_irect = { 0, 0, -1, -1 };
- const fz_irect fz_unit_bbox = { 0, 0, 1, 1 };
- const fz_quad fz_infinite_quad = { { -INFINITY, INFINITY}, {INFINITY, INFINITY}, {-INFINITY, -INFINITY}, {INFINITY, -INFINITY} };
- const fz_quad fz_invalid_quad = { {NAN, NAN}, {NAN, NAN}, {NAN, NAN}, {NAN, NAN} };
- fz_irect
- fz_irect_from_rect(fz_rect r)
- {
- fz_irect b;
- if (fz_is_infinite_rect(r))
- return fz_infinite_irect;
- if (!fz_is_valid_rect(r))
- return fz_invalid_irect;
- b.x0 = fz_clamp(floorf(r.x0), MIN_SAFE_INT, MAX_SAFE_INT);
- b.y0 = fz_clamp(floorf(r.y0), MIN_SAFE_INT, MAX_SAFE_INT);
- b.x1 = fz_clamp(ceilf(r.x1), MIN_SAFE_INT, MAX_SAFE_INT);
- b.y1 = fz_clamp(ceilf(r.y1), MIN_SAFE_INT, MAX_SAFE_INT);
- return b;
- }
- fz_rect
- fz_rect_from_irect(fz_irect a)
- {
- fz_rect r;
- if (fz_is_infinite_irect(a))
- return fz_infinite_rect;
- r.x0 = a.x0;
- r.y0 = a.y0;
- r.x1 = a.x1;
- r.y1 = a.y1;
- return r;
- }
- fz_irect
- fz_round_rect(fz_rect r)
- {
- fz_irect b;
- float f;
- f = floorf(r.x0 + 0.001f);
- b.x0 = fz_clamp(f, MIN_SAFE_INT, MAX_SAFE_INT);
- f = floorf(r.y0 + 0.001f);
- b.y0 = fz_clamp(f, MIN_SAFE_INT, MAX_SAFE_INT);
- f = ceilf(r.x1 - 0.001f);
- b.x1 = fz_clamp(f, MIN_SAFE_INT, MAX_SAFE_INT);
- f = ceilf(r.y1 - 0.001f);
- b.y1 = fz_clamp(f, MIN_SAFE_INT, MAX_SAFE_INT);
- return b;
- }
- fz_rect
- fz_intersect_rect(fz_rect a, fz_rect b)
- {
- if (fz_is_infinite_rect(b)) return a;
- if (fz_is_infinite_rect(a)) return b;
- if (a.x0 < b.x0)
- a.x0 = b.x0;
- if (a.y0 < b.y0)
- a.y0 = b.y0;
- if (a.x1 > b.x1)
- a.x1 = b.x1;
- if (a.y1 > b.y1)
- a.y1 = b.y1;
- return a;
- }
- fz_irect
- fz_intersect_irect(fz_irect a, fz_irect b)
- {
- if (fz_is_infinite_irect(b)) return a;
- if (fz_is_infinite_irect(a)) return b;
- if (a.x0 < b.x0)
- a.x0 = b.x0;
- if (a.y0 < b.y0)
- a.y0 = b.y0;
- if (a.x1 > b.x1)
- a.x1 = b.x1;
- if (a.y1 > b.y1)
- a.y1 = b.y1;
- return a;
- }
- fz_rect
- fz_union_rect(fz_rect a, fz_rect b)
- {
- /* Check for empty box before infinite box */
- if (!fz_is_valid_rect(b)) return a;
- if (!fz_is_valid_rect(a)) return b;
- if (fz_is_infinite_rect(a)) return a;
- if (fz_is_infinite_rect(b)) return b;
- if (a.x0 > b.x0)
- a.x0 = b.x0;
- if (a.y0 > b.y0)
- a.y0 = b.y0;
- if (a.x1 < b.x1)
- a.x1 = b.x1;
- if (a.y1 < b.y1)
- a.y1 = b.y1;
- return a;
- }
- fz_rect
- fz_translate_rect(fz_rect a, float xoff, float yoff)
- {
- if (fz_is_infinite_rect(a)) return a;
- a.x0 += xoff;
- a.y0 += yoff;
- a.x1 += xoff;
- a.y1 += yoff;
- return a;
- }
- fz_irect
- fz_translate_irect(fz_irect a, int xoff, int yoff)
- {
- int t;
- if (fz_is_empty_irect(a)) return a;
- if (fz_is_infinite_irect(a)) return a;
- a.x0 = ADD_WITH_SAT(t, a.x0, xoff);
- a.y0 = ADD_WITH_SAT(t, a.y0, yoff);
- a.x1 = ADD_WITH_SAT(t, a.x1, xoff);
- a.y1 = ADD_WITH_SAT(t, a.y1, yoff);
- return a;
- }
- fz_rect
- fz_transform_rect(fz_rect r, fz_matrix m)
- {
- fz_point s, t, u, v;
- int invalid;
- if (fz_is_infinite_rect(r))
- return r;
- if (fabsf(m.b) < FLT_EPSILON && fabsf(m.c) < FLT_EPSILON)
- {
- if (m.a < 0)
- {
- float f = r.x0;
- r.x0 = r.x1;
- r.x1 = f;
- }
- if (m.d < 0)
- {
- float f = r.y0;
- r.y0 = r.y1;
- r.y1 = f;
- }
- s = fz_transform_point_xy(r.x0, r.y0, m);
- t = fz_transform_point_xy(r.x1, r.y1, m);
- r.x0 = s.x; r.y0 = s.y;
- r.x1 = t.x; r.y1 = t.y;
- /* If r was invalid coming in, it'll still be invalid now. */
- return r;
- }
- else if (fabsf(m.a) < FLT_EPSILON && fabsf(m.d) < FLT_EPSILON)
- {
- if (m.b < 0)
- {
- float f = r.x0;
- r.x0 = r.x1;
- r.x1 = f;
- }
- if (m.c < 0)
- {
- float f = r.y0;
- r.y0 = r.y1;
- r.y1 = f;
- }
- s = fz_transform_point_xy(r.x0, r.y0, m);
- t = fz_transform_point_xy(r.x1, r.y1, m);
- r.x0 = s.x; r.y0 = s.y;
- r.x1 = t.x; r.y1 = t.y;
- /* If r was invalid coming in, it'll still be invalid now. */
- return r;
- }
- invalid = (r.x0 > r.x1) || (r.y0 > r.y1);
- s.x = r.x0; s.y = r.y0;
- t.x = r.x0; t.y = r.y1;
- u.x = r.x1; u.y = r.y1;
- v.x = r.x1; v.y = r.y0;
- s = fz_transform_point(s, m);
- t = fz_transform_point(t, m);
- u = fz_transform_point(u, m);
- v = fz_transform_point(v, m);
- r.x0 = MIN4(s.x, t.x, u.x, v.x);
- r.y0 = MIN4(s.y, t.y, u.y, v.y);
- r.x1 = MAX4(s.x, t.x, u.x, v.x);
- r.y1 = MAX4(s.y, t.y, u.y, v.y);
- /* If we were called with an invalid rectangle, return an
- * invalid rectangle after transformation. */
- if (invalid)
- {
- float f;
- f = r.x0; r.x0 = r.x1; r.x1 = f;
- f = r.y0; r.y0 = r.y1; r.y1 = f;
- }
- return r;
- }
- fz_irect
- fz_expand_irect(fz_irect a, int expand)
- {
- if (fz_is_infinite_irect(a)) return a;
- if (!fz_is_valid_irect(a)) return a;
- a.x0 -= expand;
- a.y0 -= expand;
- a.x1 += expand;
- a.y1 += expand;
- return a;
- }
- fz_rect
- fz_expand_rect(fz_rect a, float expand)
- {
- if (fz_is_infinite_rect(a)) return a;
- if (!fz_is_valid_rect(a)) return a;
- a.x0 -= expand;
- a.y0 -= expand;
- a.x1 += expand;
- a.y1 += expand;
- return a;
- }
- /* Adding a point to an invalid rectangle makes the zero area rectangle
- * that contains just that point. */
- fz_rect fz_include_point_in_rect(fz_rect r, fz_point p)
- {
- if (fz_is_infinite_rect(r)) return r;
- if (p.x < r.x0) r.x0 = p.x;
- if (p.x > r.x1) r.x1 = p.x;
- if (p.y < r.y0) r.y0 = p.y;
- if (p.y > r.y1) r.y1 = p.y;
- return r;
- }
- int fz_contains_rect(fz_rect a, fz_rect b)
- {
- /* An invalid rect can't contain anything */
- if (!fz_is_valid_rect(a))
- return 0;
- /* Any valid rect contains all invalid rects */
- if (!fz_is_valid_rect(b))
- return 1;
- return ((a.x0 <= b.x0) &&
- (a.y0 <= b.y0) &&
- (a.x1 >= b.x1) &&
- (a.y1 >= b.y1));
- }
- int
- fz_is_valid_quad(fz_quad q)
- {
- return (!isnan(q.ll.x) &&
- !isnan(q.ll.y) &&
- !isnan(q.ul.x) &&
- !isnan(q.ul.y) &&
- !isnan(q.lr.x) &&
- !isnan(q.lr.y) &&
- !isnan(q.ur.x) &&
- !isnan(q.ur.y));
- }
- int
- fz_is_infinite_quad(fz_quad q)
- {
- /* For a quad to be infinite, all the ordinates need to be infinite. */
- if (!isinf(q.ll.x) ||
- !isinf(q.ll.y) ||
- !isinf(q.ul.x) ||
- !isinf(q.ul.y) ||
- !isinf(q.lr.x) ||
- !isinf(q.lr.y) ||
- !isinf(q.ur.x) ||
- !isinf(q.ur.y))
- return 0;
- /* Just because all the ordinates are infinite, we don't necessarily have an infinite quad. */
- /* The quad points in order are: ll, ul, ur, lr OR reversed: ll, lr, ur, ul */
- /* The required points are: (-inf, -inf) (-inf, inf) (inf, inf) (inf, -inf) */
- /* Not the fastest way to code it, but easy to understand! */
- #define INF_QUAD_TEST(A,B,C,D) \
- if (q.A.x < 0 && q.A.y < 0 && q.B.x < 0 && q.B.y > 0 && q.C.x > 0 && q.C.y > 0 && q.D.x > 0 && q.D.y < 0) return 1
- INF_QUAD_TEST(ll, ul, ur, lr);
- INF_QUAD_TEST(ul, ur, lr, ll);
- INF_QUAD_TEST(ur, lr, ll, ul);
- INF_QUAD_TEST(lr, ll, ul, ur);
- INF_QUAD_TEST(ll, lr, ur, ul);
- INF_QUAD_TEST(lr, ur, ul, ll);
- INF_QUAD_TEST(ur, ul, ll, lr);
- INF_QUAD_TEST(ul, ll, lr, ur);
- #undef INF_QUAD_TEST
- return 0;
- }
- int fz_is_empty_quad(fz_quad q)
- {
- /* Using "Shoelace" formula */
- float area;
- if (fz_is_infinite_quad(q))
- return 0;
- if (!fz_is_valid_quad(q))
- return 1; /* All invalid quads are empty */
- area = q.ll.x * q.lr.y +
- q.lr.x * q.ur.y +
- q.ur.x * q.ul.y +
- q.ul.x * q.ll.y -
- q.lr.x * q.ll.y -
- q.ur.x * q.lr.y -
- q.ul.x * q.ur.y -
- q.ll.x * q.ul.y;
- return area == 0;
- }
- fz_rect
- fz_rect_from_quad(fz_quad q)
- {
- fz_rect r;
- if (!fz_is_valid_quad(q))
- return fz_invalid_rect;
- if (fz_is_infinite_quad(q))
- return fz_infinite_rect;
- r.x0 = MIN4(q.ll.x, q.lr.x, q.ul.x, q.ur.x);
- r.y0 = MIN4(q.ll.y, q.lr.y, q.ul.y, q.ur.y);
- r.x1 = MAX4(q.ll.x, q.lr.x, q.ul.x, q.ur.x);
- r.y1 = MAX4(q.ll.y, q.lr.y, q.ul.y, q.ur.y);
- return r;
- }
- fz_quad
- fz_transform_quad(fz_quad q, fz_matrix m)
- {
- if (!fz_is_valid_quad(q))
- return q;
- if (fz_is_infinite_quad(q))
- return q;
- q.ul = fz_transform_point(q.ul, m);
- q.ur = fz_transform_point(q.ur, m);
- q.ll = fz_transform_point(q.ll, m);
- q.lr = fz_transform_point(q.lr, m);
- return q;
- }
- fz_quad
- fz_quad_from_rect(fz_rect r)
- {
- fz_quad q;
- if (!fz_is_valid_rect(r))
- return fz_invalid_quad;
- if (fz_is_infinite_rect(r))
- return fz_infinite_quad;
- q.ul = fz_make_point(r.x0, r.y0);
- q.ur = fz_make_point(r.x1, r.y0);
- q.ll = fz_make_point(r.x0, r.y1);
- q.lr = fz_make_point(r.x1, r.y1);
- return q;
- }
- int fz_is_point_inside_rect(fz_point p, fz_rect r)
- {
- return (p.x >= r.x0 && p.x < r.x1 && p.y >= r.y0 && p.y < r.y1);
- }
- int fz_is_point_inside_irect(int x, int y, fz_irect r)
- {
- return (x >= r.x0 && x < r.x1 && y >= r.y0 && y < r.y1);
- }
- int fz_is_rect_inside_rect(fz_rect inner, fz_rect outer)
- {
- if (!fz_is_valid_rect(outer))
- return 0;
- if (!fz_is_valid_rect(inner))
- return 0;
- if (inner.x0 >= outer.x0 && inner.x1 <= outer.x1 && inner.y0 >= outer.y0 && inner.y1 <= outer.y1)
- return 1;
- return 0;
- }
- int fz_is_irect_inside_irect(fz_irect inner, fz_irect outer)
- {
- if (!fz_is_valid_irect(outer))
- return 0;
- if (!fz_is_valid_irect(inner))
- return 0;
- if (inner.x0 >= outer.x0 && inner.x1 <= outer.x1 && inner.y0 >= outer.y0 && inner.y1 <= outer.y1)
- return 1;
- return 0;
- }
- /* cross (b-a) with (p-a) */
- static float
- cross(fz_point a, fz_point b, fz_point p)
- {
- b.x -= a.x;
- b.y -= a.y;
- p.x -= a.x;
- p.y -= a.y;
- return b.x * p.y - b.y * p.x;
- }
- static int fz_is_point_inside_triangle(fz_point p, fz_point a, fz_point b, fz_point c)
- {
- /* Consider the following:
- *
- * P
- * /|
- * / |
- * / |
- * A +---+-------+ B
- * M
- *
- * The cross product of vector AB and vector AP is the distance PM.
- * The sign of this distance depends on what side of the line AB, P lies on.
- *
- * So, for a triangle ABC, if we take cross products of:
- *
- * AB and AP
- * BC and BP
- * CA and CP
- *
- * P can only be inside the triangle if the signs are all identical.
- *
- * One of the cross products being 0 indicates that the point is on a line.
- * Two of the cross products being 0 indicates that the point is on a vertex.
- *
- * If 2 of the vertices are the same, the algorithm still works.
- * Iff all 3 of the vertices are the same, the cross products are all zero. The
- * value of p is irrelevant.
- */
- float crossa = cross(a, b, p);
- float crossb = cross(b, c, p);
- float crossc = cross(c, a, p);
- /* Check for degenerate case. All vertices the same. */
- if (crossa == 0 && crossb == 0 && crossc == 0)
- return a.x == p.x && a.y == p.y;
- if (crossa >= 0 && crossb >= 0 && crossc >= 0)
- return 1;
- if (crossa <= 0 && crossb <= 0 && crossc <= 0)
- return 1;
- return 0;
- }
- int fz_is_point_inside_quad(fz_point p, fz_quad q)
- {
- if (!fz_is_valid_quad(q))
- return 0;
- if (fz_is_infinite_quad(q))
- return 1;
- return
- fz_is_point_inside_triangle(p, q.ul, q.ur, q.lr) ||
- fz_is_point_inside_triangle(p, q.ul, q.lr, q.ll);
- }
- int fz_is_quad_inside_quad(fz_quad needle, fz_quad haystack)
- {
- if (!fz_is_valid_quad(needle) || !fz_is_valid_quad(haystack))
- return 0;
- if (fz_is_infinite_quad(haystack))
- return 1;
- return
- fz_is_point_inside_quad(needle.ul, haystack) &&
- fz_is_point_inside_quad(needle.ur, haystack) &&
- fz_is_point_inside_quad(needle.ll, haystack) &&
- fz_is_point_inside_quad(needle.lr, haystack);
- }
- int fz_is_quad_intersecting_quad(fz_quad a, fz_quad b)
- {
- fz_rect ar = fz_rect_from_quad(a);
- fz_rect br = fz_rect_from_quad(b);
- return !fz_is_empty_rect(fz_intersect_rect(ar, br));
- }
|