[Fontconfig] fontconfig: Branch 'master' - 3 commits

Akira TAGOH tagoh at kemper.freedesktop.org
Wed Mar 26 00:12:21 PDT 2014


 configure.ac              |    4 
 doc/Makefile.am           |    1 
 doc/fcpattern.fncs        |   27 +++++-
 doc/fcrange.fncs          |   64 ++++++++++++++
 doc/fontconfig-devel.sgml |    7 +
 fontconfig/fcprivate.h    |    3 
 fontconfig/fontconfig.h   |   28 +++++-
 src/Makefile.am           |    1 
 src/fccfg.c               |   48 ++++++----
 src/fcdbg.c               |   13 ++
 src/fcdefault.c           |   47 +++++-----
 src/fcfreetype.c          |   35 +++++++
 src/fcint.h               |   85 +++++++++++++++---
 src/fclist.c              |    2 
 src/fcmatch.c             |   45 ++++++++++
 src/fcname.c              |   49 ++++++++++
 src/fcobjs.h              |    2 
 src/fcpat.c               |   73 ++++++++++++++++
 src/fcrange.c             |  207 ++++++++++++++++++++++++++++++++++++++++++++++
 src/fcxml.c               |  108 ++++++++++++++++++------
 20 files changed, 755 insertions(+), 94 deletions(-)

New commits:
commit fcba9ef01c978323fc71c17e455d3cd6ae35edcc
Author: Akira TAGOH <akira at tagoh.org>
Date:   Wed Mar 26 16:01:49 2014 +0900

    Fix missing docs

diff --git a/doc/Makefile.am b/doc/Makefile.am
index 78a7cdb..7503219 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -81,6 +81,7 @@ DOC_FUNCS_FNCS =		\
 	fcobjectset.fncs	\
 	fcobjecttype.fncs	\
 	fcpattern.fncs		\
+	fcrange.fncs		\
 	fcstring.fncs		\
 	fcstrset.fncs		\
 	fcvalue.fncs		\
diff --git a/doc/fcpattern.fncs b/doc/fcpattern.fncs
index 1df1c4f..1049d77 100644
--- a/doc/fcpattern.fncs
+++ b/doc/fcpattern.fncs
@@ -181,12 +181,21 @@ values added to the list have binding <parameter>weak</parameter> instead of <pa
 @TYPE2+++++++@	const char *			@ARG2+++++++@	object
 @TYPE3+++++++@	const FcLangSet *		@ARG3+++++++@	l
 
+ at PROTOTYPE++++++++@
+ at RET++++++++@	FcBool
+ at FUNC++++++++@	FcPatternAddRange
+ at TYPE1++++++++@	FcPattern *			@ARG1++++++++@	p
+ at TYPE2++++++++@	const char *			@ARG2++++++++@	object
+ at TYPE3++++++++@	const FcRange *			@ARG3++++++++@	r
+
 @PURPOSE@	Add a typed value to a pattern
 @DESC@
 These are all convenience functions that insert objects of the specified
 type into the pattern.  Use these in preference to FcPatternAdd as they
 will provide compile-time typechecking.  These all append values to
 any existing list of values.
+
+<function>FcPatternAddRange</function> are available since 2.11.91.
 @@
 
 @RET@		FcResult
@@ -257,16 +266,24 @@ within the pattern directly.  Applications must not free this value.
 @FUNC++++++@	FcPatternGetFTFace
 @TYPE1++++++@ 	FcPattern * 			@ARG1++++++@ 	p
 @TYPE2++++++@	const char *			@ARG2++++++@	object
- at TYPE3+++++@ 	int%  				@ARG3+++++@ 	n
- at TYPE3++++++@	FT_Face *			@ARG3++++++@	f
+ at TYPE3++++++@ 	int%  				@ARG3++++++@ 	n
+ at TYPE4++++++@	FT_Face *			@ARG4++++++@	f
 
 @PROTOTYPE+++++++@
 @RET+++++++@	FcResult
 @FUNC+++++++@	FcPatternGetLangSet
 @TYPE1+++++++@ 	FcPattern * 			@ARG1+++++++@ 	p
 @TYPE2+++++++@	const char *			@ARG2+++++++@	object
- at TYPE3+++++@ 	int%  				@ARG3+++++@ 	n
- at TYPE3+++++++@	FcLangSet **			@ARG3+++++++@	l
+ at TYPE3+++++++@ 	int%  				@ARG3+++++++@ 	n
+ at TYPE4+++++++@	FcLangSet **			@ARG4+++++++@	l
+
+ at PROTOTYPE++++++++@
+ at RET++++++++@	FcResult
+ at FUNC++++++++@	FcPatternGetRange
+ at TYPE1++++++++@	FcPattern *			@ARG1++++++++@	p
+ at TYPE2++++++++@	const char *			@ARG2++++++++@	object
+ at TYPE3++++++++@	int%  	   			@ARG3++++++++@	n
+ at TYPE4++++++++@	FcRange **			@ARG4++++++++@	r
 
 @PURPOSE@	Return a typed value from a pattern
 @DESC@
@@ -275,6 +292,8 @@ returned data is of the expected type. They return FcResultTypeMismatch if
 this is not the case.  Note that these (like FcPatternGet) do not make a
 copy of any data structure referenced by the return value.  Use these
 in preference to FcPatternGet to provide compile-time typechecking.
+
+<function>FcPatternGetRange</function> are available since 2.11.91.
 @@
 
 @RET@		FcPattern *
diff --git a/doc/fcrange.fncs b/doc/fcrange.fncs
new file mode 100644
index 0000000..6054595
--- /dev/null
+++ b/doc/fcrange.fncs
@@ -0,0 +1,64 @@
+/*
+ * fontconfig/doc/fcrange.fncs
+ *
+ * Copyright © 2003 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.
+ */
+ at RET@		FcRange *
+ at FUNC@		FcRangeCopy
+ at TYPE1@		const FcRange *			@ARG1@		range
+ at PURPOSE@	Copy a range object
+ at DESC@
+<function>FcRangeCopy</function> creates a new FcRange object and
+populates it with the contents of <parameter>range</parameter>.
+ at SINCE@		2.11.91
+@@
+
+ at RET@		FcRange *
+ at FUNC@		FcRangeCreateDouble
+ at TYPE1@		double				@ARG1@		begin
+ at TYPE2@		double				@ARG2@		end
+ at PURPOSE@	create a range object for double
+ at DESC@
+<function>FcRangeCreateDouble</function> creates a new FcRange object with
+double sized value.
+ at SINCE@		2.11.91
+@@
+
+ at RET@		FcRange *
+ at FUNC@		FcRangeCreateInteger
+ at TYPE1@		int				@ARG1@		begin
+ at TYPE2@		int				@ARG2@		end
+ at PURPOSE@	create a range object for integer
+ at DESC@
+<function>FcRangeCreateInteger</function> creates a new FcRange object with
+integer sized value.
+ at SINCE@		2.11.91
+@@
+
+ at RET@		void
+ at FUNC@		FcRangeDestroy
+ at TYPE1@		FcRange *			@ARG1@		range
+ at PURPOSE@	destroy a range object
+ at DESC@
+<function>FcRangeDestroy</function> destroys a FcRange object, freeing
+all memory associated with it.
+ at SINCE@		2.11.91
+@@
diff --git a/doc/fontconfig-devel.sgml b/doc/fontconfig-devel.sgml
index 7306d79..e2cb1c2 100644
--- a/doc/fontconfig-devel.sgml
+++ b/doc/fontconfig-devel.sgml
@@ -16,6 +16,7 @@
 <!ENTITY fcobjectset SYSTEM "fcobjectset.sgml">
 <!ENTITY fcobjecttype SYSTEM "fcobjecttype.sgml">
 <!ENTITY fcpattern SYSTEM "fcpattern.sgml">
+<!ENTITY fcrange SYSTEM "fcrange.sgml">
 <!ENTITY fcstring SYSTEM "fcstring.sgml">
 <!ENTITY fcstrset SYSTEM "fcstrset.sgml">
 <!ENTITY fcvalue SYSTEM "fcvalue.sgml">
@@ -508,6 +509,12 @@ FcMatrix structures hold an affine transformation in matrix form.
     </para>
     &fcmatrix;
   </sect2>
+  <sect2><title>FcRange</title>
+    <para>
+An FcRange holds two variables to indicate a range in between.
+    </para>
+    &fcrange;
+  </sect2>
   <sect2><title>FcConfig</title>
     <para>
 An FcConfig object holds the internal representation of a configuration.
commit fff91eee7df5a71ed9a63a4b6e3b02c14eaf9cb3
Author: Akira TAGOH <akira at tagoh.org>
Date:   Wed Mar 26 12:22:02 2014 +0900

    Fix a build issue with freetype <2.5.1

diff --git a/src/fcfreetype.c b/src/fcfreetype.c
index 53f0c91..d0932b3 100644
--- a/src/fcfreetype.c
+++ b/src/fcfreetype.c
@@ -1108,10 +1108,7 @@ FcFreeTypeQueryFace (const FT_Face  face,
     FT_Error	    err;
     FT_ULong	    len = 0, alen;
     FcRange	    *r = NULL;
-#if defined (HAVE_TT_OS2_USUPPEROPTICALPOINTSIZE) && defined (HAVE_TT_OS2_USLOWEROPTICALPOINTSIZE)
     double	    lower_size = 0.0L, upper_size = DBL_MAX;
-#endif
-
 
     pat = FcPatternCreate ();
     if (!pat)
commit 3cd573fc1fb67db75cd356cad3e901d24af1ce8a
Author: Akira TAGOH <akira at tagoh.org>
Date:   Wed Nov 20 18:44:59 2013 +0900

    Bug 71287 - size specific design selection support in OS/2 table version 5
    
    This feature requires the FreeType 2.5.1 or later at the build time.
    
    Besides <range> element allows <double> elements with this changes.
    
    This may breaks the cache but not bumping in this change sets at this moment.
    please be aware if you want to try it and run fc-cache before/after to
    avoid the weird thing against it.

diff --git a/configure.ac b/configure.ac
index 1086a9a..80875df 100644
--- a/configure.ac
+++ b/configure.ac
@@ -321,6 +321,10 @@ AC_CHECK_MEMBER(FT_Bitmap_Size.y_ppem,
 #include FT_FREETYPE_H])
 AC_DEFINE_UNQUOTED(HAVE_FT_BITMAP_SIZE_Y_PPEM,$HAVE_FT_BITMAP_SIZE_Y_PPEM,
 		   [FT_Bitmap_Size structure includes y_ppem field])
+AC_CHECK_MEMBERS([TT_OS2.usLowerOpticalPointSize, TT_OS2.usUpperOpticalPointSize], [], [], [[
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H]])
 CFLAGS="$fontconfig_save_cflags"
 LIBS="$fontconfig_save_libs"
 
diff --git a/fontconfig/fcprivate.h b/fontconfig/fcprivate.h
index 210c1d8..a6ee5c2 100644
--- a/fontconfig/fcprivate.h
+++ b/fontconfig/fcprivate.h
@@ -77,6 +77,9 @@
 	case FcTypeLangSet:					    \
 	    __v__.u.l = va_arg (va, const FcLangSet *);		    \
 	    break;						    \
+	case FcTypeRange:					    \
+	    __v__.u.r = va_arg (va, const FcRange *);		    \
+	    break;						    \
 	}							    \
 	if (!FcPatternAdd (__p__, __o__, __v__, FcTrue))	    \
 	    goto _FcPatternVapBuild_bail1;			    \
diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
index 2258251..069cb60 100644
--- a/fontconfig/fontconfig.h
+++ b/fontconfig/fontconfig.h
@@ -75,7 +75,7 @@ typedef int		FcBool;
 #define FC_STYLE	    "style"		/* String */
 #define FC_SLANT	    "slant"		/* Int */
 #define FC_WEIGHT	    "weight"		/* Int */
-#define FC_SIZE		    "size"		/* Double */
+#define FC_SIZE		    "size"		/* Range (double) */
 #define FC_ASPECT	    "aspect"		/* Double */
 #define FC_PIXEL_SIZE	    "pixelsize"		/* Double */
 #define FC_SPACING	    "spacing"		/* Int */
@@ -194,7 +194,8 @@ typedef enum _FcType {
     FcTypeMatrix,
     FcTypeCharSet,
     FcTypeFTFace,
-    FcTypeLangSet
+    FcTypeLangSet,
+    FcTypeRange
 } FcType;
 
 typedef struct _FcMatrix {
@@ -231,6 +232,8 @@ typedef struct _FcPattern   FcPattern;
 
 typedef struct _FcLangSet   FcLangSet;
 
+typedef struct _FcRange	    FcRange;
+
 typedef struct _FcValue {
     FcType	type;
     union {
@@ -242,6 +245,7 @@ typedef struct _FcValue {
 	const FcCharSet	*c;
 	void		*f;
 	const FcLangSet	*l;
+	const FcRange	*r;
     } u;
 } FcValue;
 
@@ -853,6 +857,9 @@ FcPatternAddBool (FcPattern *p, const char *object, FcBool b);
 FcPublic FcBool
 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls);
 
+FcPublic FcBool
+FcPatternAddRange (FcPattern *p, const char *object, const FcRange *r);
+
 FcPublic FcResult
 FcPatternGetInteger (const FcPattern *p, const char *object, int n, int *i);
 
@@ -874,6 +881,9 @@ FcPatternGetBool (const FcPattern *p, const char *object, int n, FcBool *b);
 FcPublic FcResult
 FcPatternGetLangSet (const FcPattern *p, const char *object, int n, FcLangSet **ls);
 
+FcPublic FcResult
+FcPatternGetRange (const FcPattern *p, const char *object, int id, FcRange **r);
+
 FcPublic FcPattern *
 FcPatternVaBuild (FcPattern *p, va_list va);
     
@@ -883,6 +893,20 @@ FcPatternBuild (FcPattern *p, ...) FC_ATTRIBUTE_SENTINEL(0);
 FcPublic FcChar8 *
 FcPatternFormat (FcPattern *pat, const FcChar8 *format);
 
+/* fcrange.c */
+FcPublic FcRange *
+FcRangeCreateDouble (double begin, double end);
+
+FcPublic FcRange *
+FcRangeCreateInteger (FcChar32 begin, FcChar32 end);
+
+FcPublic void
+FcRangeDestroy (FcRange *range);
+
+FcPublic FcRange *
+FcRangeCopy (const FcRange *r);
+
+
 /* fcstr.c */
 
 FcPublic FcChar8 *
diff --git a/src/Makefile.am b/src/Makefile.am
index 066cc03..be20eba 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -151,6 +151,7 @@ libfontconfig_la_SOURCES = \
 	fcobjs.h \
 	fcobjshash.h \
 	fcpat.c \
+	fcrange.c \
 	fcserialize.c \
 	fcstat.c \
 	fcstr.c \
diff --git a/src/fccfg.c b/src/fccfg.c
index 6377fd7..cdb8c0f 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -722,6 +722,11 @@ FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
 	v.u.l = FcLangSetPromote (v.u.s, buf);
 	v.type = FcTypeLangSet;
     }
+    if (buf && v.type == FcTypeDouble && u.type == FcTypeRange)
+    {
+	v.u.r = FcRangePromote (v.u.d, buf);
+	v.type = FcTypeRange;
+    }
     return v;
 }
 
@@ -894,6 +899,9 @@ FcConfigCompareValue (const FcValue	*left_o,
 		break;
 	    }
 	    break;
+	case FcTypeRange:
+	    ret = FcRangeCompare (op, left.u.r, right.u.r);
+	    break;
 	}
     }
     else
@@ -915,10 +923,11 @@ FcConfigCompareValue (const FcValue	*left_o,
 static FcValue
 FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
 {
-    FcValue	v, vl, vr;
+    FcValue	v, vl, vr, vle, vre;
     FcMatrix	*m;
     FcChar8     *str;
     FcOp	op = FC_OP_GET_OP (e->op);
+    FcValuePromotionBuffer buf1, buf2;
 
     switch ((int) op) {
     case FcOpInteger:
@@ -967,6 +976,11 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
 	v.u.l = e->u.lval;
 	v = FcValueSave (v);
 	break;
+    case FcOpRange:
+	v.type = FcTypeRange;
+	v.u.r = e->u.rval;
+	v = FcValueSave (v);
+	break;
     case FcOpBool:
 	v.type = FcTypeBool;
 	v.u.b = e->u.bval;
@@ -1033,28 +1047,28 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
     case FcOpDivide:
 	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
 	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
-	vl = FcConfigPromote (vl, vr, NULL);
-	vr = FcConfigPromote (vr, vl, NULL);
-	if (vl.type == vr.type)
+	vle = FcConfigPromote (vl, vr, &buf1);
+	vre = FcConfigPromote (vr, vle, &buf2);
+	if (vle.type == vre.type)
 	{
-	    switch ((int) vl.type) {
+	    switch ((int) vle.type) {
 	    case FcTypeDouble:
 		switch ((int) op) {
 		case FcOpPlus:	
 		    v.type = FcTypeDouble;
-		    v.u.d = vl.u.d + vr.u.d;
+		    v.u.d = vle.u.d + vre.u.d;
 		    break;
 		case FcOpMinus:
 		    v.type = FcTypeDouble;
-		    v.u.d = vl.u.d - vr.u.d;
+		    v.u.d = vle.u.d - vre.u.d;
 		    break;
 		case FcOpTimes:
 		    v.type = FcTypeDouble;
-		    v.u.d = vl.u.d * vr.u.d;
+		    v.u.d = vle.u.d * vre.u.d;
 		    break;
 		case FcOpDivide:
 		    v.type = FcTypeDouble;
-		    v.u.d = vl.u.d / vr.u.d;
+		    v.u.d = vle.u.d / vre.u.d;
 		    break;
 		default:
 		    v.type = FcTypeVoid;
@@ -1071,11 +1085,11 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
 		switch ((int) op) {
 		case FcOpOr:
 		    v.type = FcTypeBool;
-		    v.u.b = vl.u.b || vr.u.b;
+		    v.u.b = vle.u.b || vre.u.b;
 		    break;
 		case FcOpAnd:
 		    v.type = FcTypeBool;
-		    v.u.b = vl.u.b && vr.u.b;
+		    v.u.b = vle.u.b && vre.u.b;
 		    break;
 		default:
 		    v.type = FcTypeVoid;
@@ -1086,7 +1100,7 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
 		switch ((int) op) {
 		case FcOpPlus:
 		    v.type = FcTypeString;
-		    str = FcStrPlus (vl.u.s, vr.u.s);
+		    str = FcStrPlus (vle.u.s, vre.u.s);
 		    v.u.s = FcStrdup (str);
 		    FcStrFree (str);
 			
@@ -1105,7 +1119,7 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
 		    m = malloc (sizeof (FcMatrix));
 		    if (m)
 		    {
-			FcMatrixMultiply (m, vl.u.m, vr.u.m);
+			FcMatrixMultiply (m, vle.u.m, vre.u.m);
 			v.u.m = m;
 		    }
 		    else
@@ -1122,13 +1136,13 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
 		switch ((int) op) {
 		case FcOpPlus:
 		    v.type = FcTypeCharSet;
-		    v.u.c = FcCharSetUnion (vl.u.c, vr.u.c);
+		    v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
 		    if (!v.u.c)
 			v.type = FcTypeVoid;
 		    break;
 		case FcOpMinus:
 		    v.type = FcTypeCharSet;
-		    v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c);
+		    v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
 		    if (!v.u.c)
 			v.type = FcTypeVoid;
 		    break;
@@ -1141,13 +1155,13 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
 		switch ((int) op) {
 		case FcOpPlus:
 		    v.type = FcTypeLangSet;
-		    v.u.l = FcLangSetUnion (vl.u.l, vr.u.l);
+		    v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
 		    if (!v.u.l)
 			v.type = FcTypeVoid;
 		    break;
 		case FcOpMinus:
 		    v.type = FcTypeLangSet;
-		    v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l);
+		    v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
 		    if (!v.u.l)
 			v.type = FcTypeVoid;
 		    break;
diff --git a/src/fcdbg.c b/src/fcdbg.c
index d74bc27..ef038f0 100644
--- a/src/fcdbg.c
+++ b/src/fcdbg.c
@@ -29,6 +29,8 @@
 static void
 _FcValuePrintFile (FILE *f, const FcValue v)
 {
+    FcRange r;
+
     switch (v.type) {
     case FcTypeUnknown:
 	fprintf (f, "<unknown>");
@@ -61,6 +63,10 @@ _FcValuePrintFile (FILE *f, const FcValue v)
     case FcTypeFTFace:
 	fprintf (f, "face");
 	break;
+    case FcTypeRange:
+	r = FcRangeCanonicalize (v.u.r);
+	fprintf (f, "(%g, %g)", r.u.d.begin, r.u.d.end);
+	break;
     }
 }
 
@@ -261,6 +267,8 @@ FcOpPrint (FcOp op_)
 void
 FcExprPrint (const FcExpr *expr)
 {
+    FcRange r;
+
     if (!expr) printf ("none");
     else switch (FC_OP_GET_OP (expr->op)) {
     case FcOpInteger: printf ("%d", expr->u.ival); break;
@@ -277,7 +285,10 @@ FcExprPrint (const FcExpr *expr)
 	FcExprPrint (expr->u.mexpr->yy);
 	printf ("]");
 	break;
-    case FcOpRange: break;
+    case FcOpRange:
+	r = FcRangeCanonicalize (expr->u.rval);
+	printf ("(%g, %g)", r.u.d.begin, r.u.d.end);
+	break;
     case FcOpBool: printf ("%s", expr->u.bval ? "true" : "false"); break;
     case FcOpCharSet: printf ("charset\n"); break;
     case FcOpLangSet:
diff --git a/src/fcdefault.c b/src/fcdefault.c
index 4beda7c..7c16f48 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -219,6 +219,7 @@ FcDefaultSubstitute (FcPattern *pattern)
 {
     FcValue v, namelang, v2;
     int	    i;
+    double	dpi, size, scale, pixelsize;
 
     if (FcPatternObjectGet (pattern, FC_WEIGHT_OBJECT, 0, &v) == FcResultNoMatch )
 	FcPatternObjectAddInteger (pattern, FC_WEIGHT_OBJECT, FC_WEIGHT_NORMAL);
@@ -233,32 +234,30 @@ FcDefaultSubstitute (FcPattern *pattern)
 	if (FcPatternObjectGet (pattern, FcBoolDefaults[i].field, 0, &v) == FcResultNoMatch)
 	    FcPatternObjectAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value);
 
-    if (FcPatternObjectGet (pattern, FC_PIXEL_SIZE_OBJECT, 0, &v) == FcResultNoMatch)
-    {
-	double	dpi, size, scale;
+    if (FcPatternObjectGetDouble (pattern, FC_SIZE_OBJECT, 0, &size) != FcResultMatch)
+	size = 12.0L;
+    if (FcPatternObjectGetDouble (pattern, FC_SCALE_OBJECT, 0, &scale) != FcResultMatch)
+	scale = 1.0;
+    if (FcPatternObjectGetDouble (pattern, FC_DPI_OBJECT, 0, &dpi) != FcResultMatch)
+	dpi = 75.0;
 
-	if (FcPatternObjectGetDouble (pattern, FC_SIZE_OBJECT, 0, &size) != FcResultMatch)
-	{
-	    size = 12.0;
-	    (void) FcPatternObjectDel (pattern, FC_SIZE_OBJECT);
-	    FcPatternObjectAddDouble (pattern, FC_SIZE_OBJECT, size);
-	}
-	if (FcPatternObjectGetDouble (pattern, FC_SCALE_OBJECT, 0, &scale) != FcResultMatch)
-	{
-	    scale = 1.0;
-	    (void) FcPatternObjectDel (pattern, FC_SCALE_OBJECT);
-	    FcPatternObjectAddDouble (pattern, FC_SCALE_OBJECT, scale);
-	}
-	size *= scale;
-	if (FcPatternObjectGetDouble (pattern, FC_DPI_OBJECT, 0, &dpi) != FcResultMatch)
-	{
-	    dpi = 75.0;
-	    (void) FcPatternObjectDel (pattern, FC_DPI_OBJECT);
-	    FcPatternObjectAddDouble (pattern, FC_DPI_OBJECT, dpi);
-	}
-	size *= dpi / 72.0;
-	FcPatternObjectAddDouble (pattern, FC_PIXEL_SIZE_OBJECT, size);
+    if (FcPatternObjectGet (pattern, FC_PIXEL_SIZE_OBJECT, 0, &v) != FcResultMatch)
+    {
+	(void) FcPatternObjectDel (pattern, FC_SCALE_OBJECT);
+	FcPatternObjectAddDouble (pattern, FC_SCALE_OBJECT, scale);
+	pixelsize = size * scale;
+	(void) FcPatternObjectDel (pattern, FC_DPI_OBJECT);
+	FcPatternObjectAddDouble (pattern, FC_DPI_OBJECT, dpi);
+	pixelsize *= dpi / 72.0;
+	FcPatternObjectAddDouble (pattern, FC_PIXEL_SIZE_OBJECT, pixelsize);
+    }
+    else
+    {
+	size = v.u.d;
+	size = size / dpi * 72.0 / scale;
     }
+    (void) FcPatternObjectDel (pattern, FC_SIZE_OBJECT);
+    FcPatternObjectAddDouble (pattern, FC_SIZE_OBJECT, size);
 
     if (FcPatternObjectGet (pattern, FC_FONTVERSION_OBJECT, 0, &v) == FcResultNoMatch)
     {
diff --git a/src/fcfreetype.c b/src/fcfreetype.c
index d271d69..53f0c91 100644
--- a/src/fcfreetype.c
+++ b/src/fcfreetype.c
@@ -1107,6 +1107,11 @@ FcFreeTypeQueryFace (const FT_Face  face,
     FcChar8	    *hashstr = NULL;
     FT_Error	    err;
     FT_ULong	    len = 0, alen;
+    FcRange	    *r = NULL;
+#if defined (HAVE_TT_OS2_USUPPEROPTICALPOINTSIZE) && defined (HAVE_TT_OS2_USLOWEROPTICALPOINTSIZE)
+    double	    lower_size = 0.0L, upper_size = DBL_MAX;
+#endif
+
 
     pat = FcPatternCreate ();
     if (!pat)
@@ -1514,6 +1519,39 @@ FcFreeTypeQueryFace (const FT_Face  face,
 	free (complex_);
     }
 
+#if defined (HAVE_TT_OS2_USUPPEROPTICALPOINTSIZE) && defined (HAVE_TT_OS2_USLOWEROPTICALPOINTSIZE)
+    if (os2 && os2->version >= 0x0005 && os2->version != 0xffff)
+    {
+	/* usLowerPointSize and usUpperPointSize is actually twips */
+	lower_size = os2->usLowerOpticalPointSize / 20.0L;
+	upper_size = os2->usUpperOpticalPointSize / 20.0L;
+    }
+#endif
+    if (os2)
+    {
+	r = FcRangeCreateDouble (lower_size, upper_size);
+	if (!FcPatternAddRange (pat, FC_SIZE, r))
+	{
+	    FcRangeDestroy (r);
+	    goto bail1;
+	}
+	FcRangeDestroy (r);
+    }
+    else
+    {
+	for (i = 0; i < face->num_fixed_sizes; i++)
+	{
+	    double d = FcGetPixelSize (face, i);
+	    r = FcRangeCreateDouble (d, d);
+	    if (!FcPatternAddRange (pat, FC_SIZE, r))
+	    {
+		FcRangeDestroy (r);
+		goto bail1;
+	    }
+	    FcRangeDestroy (r);
+	}
+    }
+
     /*
      * Type 1: Check for FontInfo dictionary information
      * Code from g2 at magestudios.net (Gerard Escalante)
diff --git a/src/fcint.h b/src/fcint.h
index cdf2dab..dd26fd8 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -38,6 +38,8 @@
 #include <assert.h>
 #include <errno.h>
 #include <limits.h>
+#include <float.h>
+#include <math.h>
 #include <unistd.h>
 #include <stddef.h>
 #include <sys/types.h>
@@ -94,6 +96,11 @@ extern pfnSHGetFolderPathA pSHGetFolderPathA;
 #define FC_MAX(a,b) ((a) > (b) ? (a) : (b))
 #define FC_ABS(a)   ((a) < 0 ? -(a) : (a))
 
+#define FcDoubleIsZero(a)	(fabs ((a)) <= DBL_EPSILON)
+#define FcDoubleCmpEQ(a,b)	(fabs ((a) - (b)) <= DBL_EPSILON)
+#define FcDoubleCmpGE(a,b)	(FcDoubleCmpEQ (a, b) || (a) > (b))
+#define FcDoubleCmpLE(a,b)	(FcDoubleCmpEQ (a, b) || (a) < (b))
+
 /* slim_internal.h */
 #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
 #define FcPrivate		__attribute__((__visibility__("hidden")))
@@ -161,6 +168,7 @@ typedef enum _FcValueBinding {
 #define FcValueString(v)	FcPointerMember(v,u.s,FcChar8)
 #define FcValueCharSet(v)	FcPointerMember(v,u.c,const FcCharSet)
 #define FcValueLangSet(v)	FcPointerMember(v,u.l,const FcLangSet)
+#define FcValueRange(v)		FcPointerMember(v,u.r,const FcRange)
 
 typedef struct _FcValueList *FcValueListPtr;
 
@@ -244,20 +252,38 @@ typedef struct _FcExprName {
   FcMatchKind	kind;
 } FcExprName;
 
+typedef struct _FcRangeInt {
+    FcChar32 begin;
+    FcChar32 end;
+} FcRangeInt;
+typedef struct _FcRangeDouble {
+    double begin;
+    double end;
+} FcRangeDouble;
+struct _FcRange {
+    FcBool is_double;
+    FcBool is_inclusive;
+    union {
+	FcRangeInt i;
+	FcRangeDouble d;
+    } u;
+};
+
 
 typedef struct _FcExpr {
     FcOp   op;
     union {
-	int	    ival;
-	double	    dval;
-	const FcChar8	    *sval;
-	FcExprMatrix *mexpr;
-	FcBool	    bval;
-	FcCharSet   *cval;
-	FcLangSet   *lval;
-
-	FcExprName  name;
-	const FcChar8	    *constant;
+	int		ival;
+	double		dval;
+	const FcChar8	*sval;
+	FcExprMatrix	*mexpr;
+	FcBool		bval;
+	FcCharSet	*cval;
+	FcLangSet	*lval;
+	FcRange		*rval;
+
+	FcExprName	name;
+	const FcChar8	*constant;
 	struct {
 	    struct _FcExpr *left, *right;
 	} tree;
@@ -532,13 +558,6 @@ typedef struct _FcFileTime {
 
 typedef struct _FcCharMap FcCharMap;
 
-typedef struct _FcRange	    FcRange;
-
-struct _FcRange {
-    FcChar32 begin;
-    FcChar32 end;
-};
-
 typedef struct _FcStatFS    FcStatFS;
 
 struct _FcStatFS {
@@ -1008,6 +1027,9 @@ FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b);
 FcPrivate FcBool
 FcPatternObjectAddLangSet (FcPattern *p, FcObject object, const FcLangSet *ls);
 
+FcPrivate FcBool
+FcPatternObjectAddRange (FcPattern *p, FcObject object, const FcRange *r);
+
 FcPrivate FcResult
 FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int n, int *i);
 
@@ -1029,6 +1051,9 @@ FcPatternObjectGetBool (const FcPattern *p, FcObject object, int n, FcBool *b);
 FcPrivate FcResult
 FcPatternObjectGetLangSet (const FcPattern *p, FcObject object, int n, FcLangSet **ls);
 
+FcPrivate FcResult
+FcPatternObjectGetRange (const FcPattern *p, FcObject object, int id, FcRange **r);
+
 FcPrivate FcBool
 FcPatternAppend (FcPattern *p, FcPattern *s);
 
@@ -1056,6 +1081,32 @@ extern FcPrivate const FcMatrix    FcIdentityMatrix;
 FcPrivate void
 FcMatrixFree (FcMatrix *mat);
 
+/* fcrange.c */
+
+FcPrivate FcRange
+FcRangeCanonicalize (const FcRange *range);
+
+FcPrivate FcRange *
+FcRangePromote (double v, FcValuePromotionBuffer *vbuf);
+
+FcPrivate FcBool
+FcRangeIsZero (const FcRange *r);
+
+FcPrivate FcBool
+FcRangeIsInRange (const FcRange *a, const FcRange *b);
+
+FcPrivate FcBool
+FcRangeCompare (FcOp op, const FcRange *a, const FcRange *b);
+
+FcPrivate FcChar32
+FcRangeHash (const FcRange *r);
+
+FcPrivate FcBool
+FcRangeSerializeAlloc (FcSerialize *serialize, const FcRange *r);
+
+FcPrivate FcRange *
+FcRangeSerialize (FcSerialize *serialize, const FcRange *r);
+
 /* fcstat.c */
 
 FcPrivate int
diff --git a/src/fclist.c b/src/fclist.c
index a365098..6ad297c 100644
--- a/src/fclist.c
+++ b/src/fclist.c
@@ -273,6 +273,8 @@ FcListValueHash (FcValue    *value)
 	return (long) v.u.f;
     case FcTypeLangSet:
 	return FcLangSetHash (v.u.l);
+    case FcTypeRange:
+	return FcRangeHash (v.u.r);
     }
     return 0;
 }
diff --git a/src/fcmatch.c b/src/fcmatch.c
index 93e013f..0c0a067 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -189,6 +189,49 @@ FcCompareSize (FcValue *value1, FcValue *value2)
 }
 
 static double
+FcCompareSizeRange (FcValue *v1, FcValue *v2)
+{
+    FcValue value1 = FcValueCanonicalize (v1);
+    FcValue value2 = FcValueCanonicalize (v2);
+    FcRange *r1 = NULL, *r2 = NULL;
+    double ret = -1.0;
+
+    switch ((int) value1.type) {
+    case FcTypeDouble:
+	r1 = FcRangeCreateDouble (value1.u.d, value1.u.d);
+	break;
+    case FcTypeRange:
+	r1 = FcRangeCopy (value1.u.r);
+	break;
+    default:
+	goto bail;
+    }
+    switch ((int) value2.type) {
+    case FcTypeDouble:
+	r2 = FcRangeCreateDouble (value2.u.d, value2.u.d);
+	break;
+    case FcTypeRange:
+	r2 = FcRangeCopy (value2.u.r);
+	break;
+    default:
+	goto bail;
+    }
+
+    if (FcRangeIsInRange (r1, r2))
+	ret = 0.0;
+    else
+	ret = FC_MIN (fabs (r1->u.d.end - r2->u.d.begin), fabs (r1->u.d.begin - r2->u.d.end));
+
+bail:
+    if (r1)
+	FcRangeDestroy (r1);
+    if (r2)
+	FcRangeDestroy (r2);
+
+    return ret;
+}
+
+static double
 FcCompareFilename (FcValue *v1, FcValue *v2)
 {
     const FcChar8 *s1 = FcValueString (v1), *s2 = FcValueString (v2);
@@ -227,6 +270,7 @@ FcCompareHash (FcValue *v1, FcValue *v2)
 #define PRI_FcCompareLang(n)		PRI1(n)
 #define PRI_FcComparePostScript(n)	PRI1(n)
 #define PRI_FcCompareHash(n)		PRI1(n)
+#define PRI_FcCompareSizeRange(n)	PRI1(n)
 
 #define FC_OBJECT(NAME, Type, Cmp)	PRI_##Cmp(NAME)
 
@@ -255,6 +299,7 @@ typedef enum _FcMatcherPriority {
     PRI_FAMILY_WEAK,
     PRI_POSTSCRIPT_NAME_WEAK,
     PRI1(SPACING),
+    PRI1(SIZE),
     PRI1(PIXEL_SIZE),
     PRI1(STYLE),
     PRI1(SLANT),
diff --git a/src/fcname.c b/src/fcname.c
index f302948..4666178 100644
--- a/src/fcname.c
+++ b/src/fcname.c
@@ -87,6 +87,10 @@ FcObjectValidType (FcObject object, FcType type)
 	    if (type == FcTypeLangSet || type == FcTypeString)
 		return FcTrue;
 	    break;
+	case FcTypeRange:
+	    if (type == FcTypeRange || type == FcTypeDouble)
+		return FcTrue;
+	    break;
 	default:
 	    if (type == t->type)
 		return FcTrue;
@@ -273,6 +277,8 @@ FcNameConvert (FcType type, FcChar8 *string)
 {
     FcValue	v;
     FcMatrix	m;
+    double	b, e;
+    char	*p;
 
     v.type = type;
     switch ((int) v.type) {
@@ -307,6 +313,20 @@ FcNameConvert (FcType type, FcChar8 *string)
 	if (!v.u.l)
 	    v.type = FcTypeVoid;
 	break;
+    case FcTypeRange:
+	if (sscanf ((char *) string, "(%lg %lg)", &b, &e) != 2)
+	{
+	    v.u.d = strtod ((char *) string, &p);
+	    if (p != NULL && p[0] != 0)
+	    {
+		v.type = FcTypeVoid;
+		break;
+	    }
+	    v.type = FcTypeDouble;
+	}
+	else
+	    v.u.r = FcRangeCreateDouble (b, e);
+	break;
     default:
 	break;
     }
@@ -476,6 +496,7 @@ FcNameUnparseValue (FcStrBuf	*buf,
 {
     FcChar8	temp[1024];
     FcValue v = FcValueCanonicalize(v0);
+    FcRange r;
 
     switch (v.type) {
     case FcTypeUnknown:
@@ -501,6 +522,18 @@ FcNameUnparseValue (FcStrBuf	*buf,
 	return FcNameUnparseLangSet (buf, v.u.l);
     case FcTypeFTFace:
 	return FcTrue;
+    case FcTypeRange:
+	r = FcRangeCanonicalize (v.u.r);
+	if (!FcDoubleIsZero (r.u.d.begin) || !FcDoubleIsZero (r.u.d.end))
+	{
+	    if (FcDoubleCmpEQ (r.u.d.begin, r.u.d.end))
+		sprintf ((char *) temp, "%g", r.u.d.begin);
+	    else
+		sprintf ((char *) temp, "(%g %g)", r.u.d.begin, r.u.d.end);
+	    return FcNameUnparseString (buf, temp, 0);
+	}
+	else
+	    return FcTrue;
     }
     return FcFalse;
 }
@@ -533,12 +566,13 @@ FcNameUnparse (FcPattern *pat)
 FcChar8 *
 FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
 {
-    FcStrBuf		    buf;
-    FcChar8		    buf_static[8192];
+    FcStrBuf		    buf, buf2;
+    FcChar8		    buf_static[8192], buf2_static[256];
     int			    i;
     FcPatternElt	    *e;
 
     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
+    FcStrBufInit (&buf2, buf2_static, sizeof (buf2_static));
     e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
     if (e)
     {
@@ -548,10 +582,17 @@ FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
     e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
     if (e)
     {
-	if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
+	FcChar8 *p;
+
+	if (!FcNameUnparseString (&buf2, (FcChar8 *) "-", 0))
 	    goto bail0;
-	if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
+	if (!FcNameUnparseValueList (&buf2, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
 	    goto bail0;
+	p = FcStrBufDoneStatic (&buf2);
+	FcStrBufDestroy (&buf2);
+	if (strlen ((const char *)p) > 1)
+	    if (!FcStrBufString (&buf, p))
+		goto bail0;
     }
     for (i = 0; i < NUM_OBJECT_TYPES; i++)
     {
diff --git a/src/fcobjs.h b/src/fcobjs.h
index a0ee079..72e71f9 100644
--- a/src/fcobjs.h
+++ b/src/fcobjs.h
@@ -31,7 +31,7 @@ FC_OBJECT (FULLNAMELANG,	FcTypeString,	NULL)
 FC_OBJECT (SLANT,		FcTypeInteger,	FcCompareNumber)
 FC_OBJECT (WEIGHT,		FcTypeInteger,	FcCompareNumber)
 FC_OBJECT (WIDTH,		FcTypeInteger,	FcCompareNumber)
-FC_OBJECT (SIZE,		FcTypeDouble,	NULL)
+FC_OBJECT (SIZE,		FcTypeRange,	FcCompareSizeRange)
 FC_OBJECT (ASPECT,		FcTypeDouble,	NULL)
 FC_OBJECT (PIXEL_SIZE,		FcTypeDouble,	FcCompareSize)
 FC_OBJECT (SPACING,		FcTypeInteger,	FcCompareNumber)
diff --git a/src/fcpat.c b/src/fcpat.c
index 986cca3..7e7d54a 100644
--- a/src/fcpat.c
+++ b/src/fcpat.c
@@ -57,6 +57,9 @@ FcValueDestroy (FcValue v)
     case FcTypeLangSet:
 	FcLangSetDestroy ((FcLangSet *) v.u.l);
 	break;
+    case FcTypeRange:
+	FcRangeDestroy ((FcRange *) v.u.r);
+	break;
     default:
 	break;
     }
@@ -81,6 +84,10 @@ FcValueCanonicalize (const FcValue *v)
 	new.u.l = FcValueLangSet(v);
 	new.type = FcTypeLangSet;
 	break;
+    case FcTypeRange:
+	new.u.r = FcValueRange(v);
+	new.type = FcTypeRange;
+	break;
     default:
 	new = *v;
 	break;
@@ -112,6 +119,11 @@ FcValueSave (FcValue v)
 	if (!v.u.l)
 	    v.type = FcTypeVoid;
 	break;
+    case FcTypeRange:
+	v.u.r = FcRangeCopy (v.u.r);
+	if (!v.u.r)
+	    v.type = FcTypeVoid;
+	break;
     default:
 	break;
     }
@@ -145,6 +157,9 @@ FcValueListDestroy (FcValueListPtr l)
 	    FcLangSetDestroy
 		((FcLangSet *) (l->value.u.l));
 	    break;
+	case FcTypeRange:
+	    FcRangeDestroy ((FcRange *) (l->value.u.r));
+	    break;
 	default:
 	    break;
 	}
@@ -267,6 +282,8 @@ FcValueEqual (FcValue va, FcValue vb)
 	return va.u.f == vb.u.f;
     case FcTypeLangSet:
 	return FcLangSetEqual (va.u.l, vb.u.l);
+    case FcTypeRange:
+	return FcRangeIsInRange (va.u.r, vb.u.r);
     }
     return FcFalse;
 }
@@ -320,6 +337,8 @@ FcValueHash (const FcValue *v)
 	       FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
     case FcTypeLangSet:
 	return FcLangSetHash (FcValueLangSet(v));
+    case FcTypeRange:
+	return FcRangeHash (v->u.r);
     }
     return 0;
 }
@@ -841,6 +860,22 @@ FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
     return FcPatternAdd (p, object, v, FcTrue);
 }
 
+FcBool
+FcPatternObjectAddRange (FcPattern *p, FcObject object, const FcRange *r)
+{
+    FcValue v;
+
+    v.type = FcTypeRange;
+    v.u.r = (FcRange *)r;
+    return FcPatternObjectAdd (p, object, v, FcTrue);
+}
+
+FcBool
+FcPatternAddRange (FcPattern *p, const char *object, const FcRange *r)
+{
+    return FcPatternObjectAddRange (p, FcObjectFromName (object), r);
+}
+
 FcResult
 FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
 {
@@ -1025,6 +1060,31 @@ FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **
     return FcResultMatch;
 }
 
+FcResult
+FcPatternObjectGetRange (const FcPattern *p, FcObject object, int id, FcRange **r)
+{
+    FcValue	v;
+    FcResult	res;
+
+    res = FcPatternObjectGet (p, object, id, &v);
+    if (res != FcResultMatch)
+	return res;
+    switch ((int)v.type) {
+    case FcTypeRange:
+	*r = (FcRange *)v.u.r;
+	break;
+    default:
+	return FcResultTypeMismatch;
+    }
+    return FcResultMatch;
+}
+
+FcResult
+FcPatternGetRange (const FcPattern *p, const char *object, int id, FcRange **r)
+{
+    return FcPatternObjectGetRange (p, FcObjectFromName (object), id, r);
+}
+
 FcPattern *
 FcPatternDuplicate (const FcPattern *orig)
 {
@@ -1230,6 +1290,10 @@ FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
 	    if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
 		return FcFalse;
 	    break;
+	case FcTypeRange:
+	    if (!FcRangeSerializeAlloc (serialize, vl->value.u.r))
+		return FcFalse;
+	    break;
 	default:
 	    break;
 	}
@@ -1245,6 +1309,7 @@ FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
     FcChar8	*s_serialized;
     FcCharSet	*c_serialized;
     FcLangSet	*l_serialized;
+    FcRange	*r_serialized;
     FcValueList	*head_serialized = NULL;
     FcValueList	*prev_serialized = NULL;
 
@@ -1303,6 +1368,14 @@ FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
 							     l_serialized,
 							     FcLangSet);
 	    break;
+	case FcTypeRange:
+	    r_serialized = FcRangeSerialize (serialize, vl->value.u.r);
+	    if (!r_serialized)
+		return NULL;
+	    vl_serialized->value.u.r = FcPtrToEncodedOffset (&vl_serialized->value,
+							     r_serialized,
+							     FcRange);
+	    break;
 	default:
 	    break;
 	}
diff --git a/src/fcrange.c b/src/fcrange.c
new file mode 100644
index 0000000..7d0c1c0
--- /dev/null
+++ b/src/fcrange.c
@@ -0,0 +1,207 @@
+/*
+ * 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;
+}
+
+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;
+}
diff --git a/src/fcxml.c b/src/fcxml.c
index 91d166f..c68b0cf 100644
--- a/src/fcxml.c
+++ b/src/fcxml.c
@@ -169,6 +169,18 @@ FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
 }
 
 static FcExpr *
+FcExprCreateRange (FcConfig *config, FcRange *range)
+{
+    FcExpr *e = FcConfigAllocExpr (config);
+    if (e)
+    {
+	e->op = FcOpRange;
+	e->u.rval = FcRangeCopy (range);
+    }
+    return e;
+}
+
+static FcExpr *
 FcExprCreateBool (FcConfig *config, FcBool b)
 {
     FcExpr *e = FcConfigAllocExpr (config);
@@ -258,6 +270,7 @@ FcExprDestroy (FcExpr *e)
 	FcExprMatrixFree (e->u.mexpr);
 	break;
     case FcOpRange:
+	FcRangeDestroy (e->u.rval);
 	break;
     case FcOpCharSet:
 	FcCharSetDestroy (e->u.cval);
@@ -503,7 +516,7 @@ typedef struct _FcVStack {
 	int		integer;
 	double		_double;
 	FcExprMatrix	*matrix;
-	FcRange		range;
+	FcRange		*range;
 	FcBool		bool_;
 	FcCharSet	*charset;
 	FcLangSet	*langset;
@@ -593,6 +606,8 @@ FcTypeName (FcType type)
 	return "FT_Face";
     case FcTypeLangSet:
 	return "langset";
+    case FcTypeRange:
+	return "range";
     default:
 	return "unknown";
     }
@@ -608,7 +623,9 @@ FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
     if (value != type)
     {
 	if ((value == FcTypeLangSet && type == FcTypeString) ||
-	    (value == FcTypeString && type == FcTypeLangSet))
+	    (value == FcTypeString && type == FcTypeLangSet) ||
+	    (value == FcTypeInteger && type == FcTypeRange) ||
+	    (value == FcTypeDouble && type == FcTypeRange))
 	    return;
 	if (type ==  FcTypeUnknown)
 	    return;
@@ -651,6 +668,9 @@ FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
     case FcOpLangSet:
 	FcTypecheckValue (parse, FcTypeLangSet, type);
 	break;
+    case FcOpRange:
+	FcTypecheckValue (parse, FcTypeRange, type);
+	break;
     case FcOpNil:
 	break;
     case FcOpField:
@@ -865,11 +885,10 @@ FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
 static FcBool
 FcVStackPushRange (FcConfigParse *parse, FcRange *range)
 {
-    FcVStack	*vstack = FcVStackCreateAndPush (parse);
+    FcVStack 	*vstack = FcVStackCreateAndPush (parse);
     if (!vstack)
 	return FcFalse;
-    vstack->u.range.begin = range->begin;
-    vstack->u.range.end = range->end;
+    vstack->u.range = range;
     vstack->tag = FcVStackRange;
     return FcTrue;
 }
@@ -1017,9 +1036,11 @@ FcVStackPopAndDestroy (FcConfigParse *parse)
     case FcVStackMatrix:
 	FcExprMatrixFreeShallow (vstack->u.matrix);
 	break;
-    case FcVStackRange:
     case FcVStackBool:
 	break;
+    case FcVStackRange:
+	FcRangeDestroy (vstack->u.range);
+	break;
     case FcVStackCharSet:
 	FcCharSetDestroy (vstack->u.charset);
 	break;
@@ -1232,7 +1253,9 @@ static void
 FcParseBlank (FcConfigParse *parse)
 {
     int		n = FcVStackElements (parse);
-    FcChar32	i;
+    FcChar32	i, begin, end;
+    FcRange	r;
+
     while (n-- > 0)
     {
 	FcVStack    *v = FcVStackFetch (parse, n);
@@ -1248,9 +1271,12 @@ FcParseBlank (FcConfigParse *parse)
 		goto bail;
 	    break;
 	case FcVStackRange:
-	    if (v->u.range.begin <= v->u.range.end)
+	    r = FcRangeCanonicalize (v->u.range);
+	    begin = (FcChar32)r.u.d.begin;
+	    end = (FcChar32)r.u.d.end;
+	    if (begin <= end)
 	    {
-	      for (i = v->u.range.begin; i <= v->u.range.end; i++)
+	      for (i = begin; i <= end; i++)
 	      {
 		  if (!FcBlanksAdd (parse->config->blanks, i))
 		      goto bail;
@@ -1463,9 +1489,11 @@ static void
 FcParseRange (FcConfigParse *parse)
 {
     FcVStack	*vstack;
-    FcRange	r = {0, 0};
-    FcChar32	n;
+    FcRange	*r;
+    FcChar32	n[2] = {0, 0};
     int		count = 1;
+    double	d[2] = {0.0L, 0.0L};
+    FcBool	dflag = FcFalse;
 
     while ((vstack = FcVStackPeek (parse)))
     {
@@ -1476,31 +1504,52 @@ FcParseRange (FcConfigParse *parse)
 	}
 	switch ((int) vstack->tag) {
 	case FcVStackInteger:
-	    n = vstack->u.integer;
+	    if (dflag)
+		d[count] = (double)vstack->u.integer;
+	    else
+		n[count] = vstack->u.integer;
+	    break;
+	case FcVStackDouble:
+	    if (count == 0 && !dflag)
+		d[1] = (double)n[1];
+	    d[count] = vstack->u._double;
+	    dflag = FcTrue;
 	    break;
 	default:
 	    FcConfigMessage (parse, FcSevereError, "invalid element in range");
-	    n = 0;
+	    if (dflag)
+		d[count] = 0.0L;
+	    else
+		n[count] = 0;
 	    break;
 	}
-	if (count == 1)
-	    r.end = n;
-	else
-	    r.begin = n;
 	count--;
 	FcVStackPopAndDestroy (parse);
     }
-    if (count < 0)
+    if (count >= 0)
+    {
+	FcConfigMessage (parse, FcSevereError, "invalid range");
+	return;
+    }
+    if (dflag)
     {
-	if (r.begin > r.end)
+	if (d[0] > d[1])
 	{
 	    FcConfigMessage (parse, FcSevereError, "invalid range");
 	    return;
 	}
-	FcVStackPushRange (parse, &r);
+	r = FcRangeCreateDouble (d[0], d[1]);
     }
     else
-	FcConfigMessage (parse, FcSevereError, "invalid range");
+    {
+	if (n[0] > n[1])
+	{
+	    FcConfigMessage (parse, FcSevereError, "invalid range");
+	    return;
+	}
+	r = FcRangeCreateInteger (n[0], n[1]);
+    }
+    FcVStackPushRange (parse, r);
 }
 
 static FcBool
@@ -1536,7 +1585,8 @@ FcParseCharSet (FcConfigParse *parse)
 {
     FcVStack	*vstack;
     FcCharSet	*charset = FcCharSetCreate ();
-    FcChar32	i;
+    FcChar32	i, begin, end;
+    FcRange	r;
     int n = 0;
 
     while ((vstack = FcVStackPeek (parse)))
@@ -1551,9 +1601,13 @@ FcParseCharSet (FcConfigParse *parse)
 		n++;
 	    break;
 	case FcVStackRange:
-	    if (vstack->u.range.begin <= vstack->u.range.end)
+	    r = FcRangeCanonicalize (vstack->u.range);
+	    begin = (FcChar32)r.u.d.begin;
+	    end = (FcChar32)r.u.d.end;
+
+	    if (begin <= end)
 	    {
-	      for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
+	      for (i = begin; i <= end; i++)
 	      {
 		  if (!FcCharSetAddChar (charset, i))
 		  {
@@ -1888,6 +1942,7 @@ FcPopExpr (FcConfigParse *parse)
 	expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
 	break;
     case FcVStackRange:
+	expr = FcExprCreateRange (parse->config, vstack->u.range);
 	break;
     case FcVStackBool:
 	expr = FcExprCreateBool (parse->config, vstack->u.bool_);
@@ -2653,6 +2708,11 @@ FcPopValue (FcConfigParse *parse)
 	if (value.u.l)
 	    value.type = FcTypeLangSet;
 	break;
+    case FcVStackRange:
+	value.u.r = FcRangeCopy (vstack->u.range);
+	if (value.u.r)
+	    value.type = FcTypeRange;
+	break;
     default:
 	FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
 			 vstack->tag);


More information about the Fontconfig mailing list