| /* |
| * fontconfig/src/fcrange.c |
| * |
| * Copyright © 2002 Keith Packard |
| * |
| * Permission to use, copy, modify, distribute, and sell this software and its |
| * documentation for any purpose is hereby granted without fee, provided that |
| * the above copyright notice appear in all copies and that both that |
| * copyright notice and this permission notice appear in supporting |
| * documentation, and that the name of the author(s) not be used in |
| * advertising or publicity pertaining to distribution of the software without |
| * specific, written prior permission. The authors make no |
| * representations about the suitability of this software for any purpose. It |
| * is provided "as is" without express or implied warranty. |
| * |
| * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include "fcint.h" |
| |
| |
| FcRange * |
| FcRangeCreateDouble (double begin, double end) |
| { |
| FcRange *ret = malloc (sizeof (FcRange)); |
| |
| if (ret) |
| { |
| ret->is_double = FcTrue; |
| ret->is_inclusive = FcDoubleCmpEQ (begin, end); |
| ret->u.d.begin = begin; |
| ret->u.d.end = end; |
| } |
| |
| return ret; |
| } |
| |
| FcRange * |
| FcRangeCreateInteger (FcChar32 begin, FcChar32 end) |
| { |
| FcRange *ret = malloc (sizeof (FcRange)); |
| |
| if (ret) |
| { |
| ret->is_double = FcFalse; |
| ret->is_inclusive = (begin == end); |
| ret->u.i.begin = begin; |
| ret->u.i.end = end; |
| } |
| |
| return ret; |
| } |
| |
| void |
| FcRangeDestroy (FcRange *range) |
| { |
| free (range); |
| } |
| |
| FcRange * |
| FcRangeCopy (const FcRange *range) |
| { |
| FcRange *ret; |
| |
| if (range->is_double) |
| ret = FcRangeCreateDouble (range->u.d.begin, range->u.d.end); |
| else |
| ret = FcRangeCreateInteger (range->u.i.begin, range->u.i.end); |
| |
| return ret; |
| } |
| |
| FcBool |
| FcRangeGetDouble(const FcRange *range, double *begin, double *end) |
| { |
| if (!range) |
| return FcFalse; |
| if (range->is_double) |
| { |
| if (begin) |
| *begin = range->u.d.begin; |
| if (end) |
| *end = range->u.d.end; |
| } |
| else |
| { |
| if (begin) |
| *begin = (double)range->u.i.begin; |
| if (end) |
| *end = (double)range->u.i.end; |
| } |
| |
| return FcTrue; |
| } |
| |
| FcRange |
| FcRangeCanonicalize (const FcRange *range) |
| { |
| FcRange new; |
| |
| if (range->is_double) |
| new = *range; |
| else |
| { |
| new.is_double = FcTrue; |
| new.is_inclusive = range->is_inclusive; |
| new.u.d.begin = (double)range->u.i.begin; |
| new.u.d.end = (double)range->u.i.end; |
| } |
| return new; |
| } |
| |
| FcRange * |
| FcRangePromote (double v, FcValuePromotionBuffer *vbuf) |
| { |
| typedef struct { |
| FcRange r; |
| } FcRangePromotionBuffer; |
| FcRangePromotionBuffer *buf = (FcRangePromotionBuffer *) vbuf; |
| |
| FC_ASSERT_STATIC (sizeof (FcRangePromotionBuffer) <= sizeof (FcValuePromotionBuffer)); |
| buf->r.is_double = FcTrue; |
| buf->r.is_inclusive = FcTrue; |
| buf->r.u.d.begin = v; |
| buf->r.u.d.end = v; |
| |
| return &buf->r; |
| } |
| |
| FcBool |
| FcRangeIsZero (const FcRange *r) |
| { |
| FcRange c; |
| |
| if (!r) |
| return FcFalse; |
| c = FcRangeCanonicalize (r); |
| |
| return FcDoubleIsZero (c.u.d.begin) && FcDoubleIsZero (c.u.d.end); |
| } |
| |
| FcBool |
| FcRangeIsInRange (const FcRange *a, const FcRange *b) |
| { |
| FcRange ca, cb; |
| FcBool f; |
| |
| if (!a || !b) |
| return FcFalse; |
| |
| ca = FcRangeCanonicalize (a); |
| cb = FcRangeCanonicalize (b); |
| if (ca.is_inclusive & cb.is_inclusive) |
| f = ca.u.d.end <= cb.u.d.end; |
| else |
| f = ca.u.d.end < cb.u.d.end; |
| |
| return FcDoubleCmpGE (ca.u.d.begin, cb.u.d.begin) && f; |
| } |
| |
| FcBool |
| FcRangeCompare (FcOp op, const FcRange *a, const FcRange *b) |
| { |
| FcRange ca, cb; |
| |
| switch ((int) op) { |
| case FcOpEqual: |
| case FcOpContains: |
| case FcOpListing: |
| return FcRangeIsInRange (a, b); |
| case FcOpNotEqual: |
| case FcOpNotContains: |
| return !FcRangeIsInRange (a, b); |
| case FcOpLess: |
| ca = FcRangeCanonicalize (a); |
| cb = FcRangeCanonicalize (b); |
| return ca.u.d.begin < cb.u.d.begin; |
| case FcOpLessEqual: |
| ca = FcRangeCanonicalize (a); |
| cb = FcRangeCanonicalize (b); |
| return FcDoubleCmpLE (ca.u.d.begin, cb.u.d.begin); |
| case FcOpMore: |
| ca = FcRangeCanonicalize (a); |
| cb = FcRangeCanonicalize (b); |
| return ca.u.d.end > cb.u.d.end; |
| case FcOpMoreEqual: |
| ca = FcRangeCanonicalize (a); |
| cb = FcRangeCanonicalize (b); |
| return FcDoubleCmpGE (ca.u.d.end, cb.u.d.end); |
| default: |
| break; |
| } |
| return FcFalse; |
| } |
| |
| FcChar32 |
| FcRangeHash (const FcRange *r) |
| { |
| FcRange c = FcRangeCanonicalize (r); |
| int b = (int) (c.u.d.begin * 100); |
| int e = (int) (c.u.d.end * 100); |
| |
| return b ^ (b << 1) ^ (e << 9); |
| } |
| |
| FcBool |
| FcRangeSerializeAlloc (FcSerialize *serialize, const FcRange *r) |
| { |
| if (!FcSerializeAlloc (serialize, r, sizeof (FcRange))) |
| return FcFalse; |
| return FcTrue; |
| } |
| |
| FcRange * |
| FcRangeSerialize (FcSerialize *serialize, const FcRange *r) |
| { |
| FcRange *r_serialize = FcSerializePtr (serialize, r); |
| |
| if (!r_serialize) |
| return NULL; |
| memcpy (r_serialize, r, sizeof (FcRange)); |
| |
| return r_serialize; |
| } |
| |
| #define __fcrange__ |
| #include "fcaliastail.h" |
| #undef __fcrange__ |