[twin] Reorganize matching code to better reflect the code in Pango

Makes it easier to update later.
This commit is contained in:
Behdad Esfahbod 2009-03-17 19:22:31 -04:00
parent 2b4044a36f
commit 922c108365
2 changed files with 135 additions and 42 deletions

View file

@ -57,6 +57,8 @@ static cairo_user_data_key_t twin_properties_key;
/* We synthesize multiple faces from the twin data. Here is the parameters. */
/* The following tables and matching code are copied from Pango */
/* CSS weight */
typedef enum {
TWIN_WEIGHT_THIN = 100,
@ -85,6 +87,64 @@ typedef enum {
TWIN_STRETCH_ULTRA_EXPANDED
} twin_face_stretch_t;
typedef struct
{
int value;
const char str[16];
} FieldMap;
static const FieldMap slant_map[] = {
{ CAIRO_FONT_SLANT_NORMAL, "" },
{ CAIRO_FONT_SLANT_NORMAL, "Roman" },
{ CAIRO_FONT_SLANT_OBLIQUE, "Oblique" },
{ CAIRO_FONT_SLANT_ITALIC, "Italic" }
};
static const FieldMap smallcaps_map[] = {
{ FALSE, "" },
{ TRUE, "Small-Caps" }
};
static const FieldMap weight_map[] = {
{ TWIN_WEIGHT_THIN, "Thin" },
{ TWIN_WEIGHT_ULTRALIGHT, "Ultra-Light" },
{ TWIN_WEIGHT_ULTRALIGHT, "Extra-Light" },
{ TWIN_WEIGHT_LIGHT, "Light" },
{ TWIN_WEIGHT_BOOK, "Book" },
{ TWIN_WEIGHT_NORMAL, "" },
{ TWIN_WEIGHT_NORMAL, "Regular" },
{ TWIN_WEIGHT_MEDIUM, "Medium" },
{ TWIN_WEIGHT_SEMIBOLD, "Semi-Bold" },
{ TWIN_WEIGHT_SEMIBOLD, "Demi-Bold" },
{ TWIN_WEIGHT_BOLD, "Bold" },
{ TWIN_WEIGHT_ULTRABOLD, "Ultra-Bold" },
{ TWIN_WEIGHT_ULTRABOLD, "Extra-Bold" },
{ TWIN_WEIGHT_HEAVY, "Heavy" },
{ TWIN_WEIGHT_HEAVY, "Black" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Heavy" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Extra-Heavy" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Black" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Extra-Black" }
};
static const FieldMap stretch_map[] = {
{ TWIN_STRETCH_ULTRA_CONDENSED, "Ultra-Condensed" },
{ TWIN_STRETCH_EXTRA_CONDENSED, "Extra-Condensed" },
{ TWIN_STRETCH_CONDENSED, "Condensed" },
{ TWIN_STRETCH_SEMI_CONDENSED, "Semi-Condensed" },
{ TWIN_STRETCH_NORMAL, "" },
{ TWIN_STRETCH_SEMI_EXPANDED, "Semi-Expanded" },
{ TWIN_STRETCH_EXPANDED, "Expanded" },
{ TWIN_STRETCH_EXTRA_EXPANDED, "Extra-Expanded" },
{ TWIN_STRETCH_ULTRA_EXPANDED, "Ultra-Expanded" }
};
static const FieldMap monospace_map[] = {
{ FALSE, "" },
{ TRUE, "Mono" },
{ TRUE, "Monospace" }
};
typedef struct _twin_face_properties {
cairo_font_slant_t slant;
@ -124,52 +184,84 @@ field_matches (const char *s1,
return len == 0 && *s1 == '\0';
}
static cairo_bool_t
parse_int (const char *word,
size_t wordlen,
int *out)
{
char *end;
long val = strtol (word, &end, 10);
int i = val;
if (end != word && (end == word + wordlen) && val >= 0 && val == i)
{
if (out)
*out = i;
return TRUE;
}
return FALSE;
}
static cairo_bool_t
find_field (const char *what,
const FieldMap *map,
int n_elements,
const char *str,
int len,
int *val)
{
int i;
cairo_bool_t had_prefix = FALSE;
if (what)
{
i = strlen (what);
if (len > i && 0 == strncmp (what, str, i) && str[i] == '=')
{
str += i + 1;
len -= i + 1;
had_prefix = TRUE;
}
}
for (i=0; i<n_elements; i++)
{
if (map[i].str[0] && field_matches (map[i].str, str, len))
{
if (val)
*val = map[i].value;
return TRUE;
}
}
if (!what || had_prefix)
return parse_int (str, len, val);
return FALSE;
}
static void
parse_field (twin_face_properties_t *props,
const char *s,
const char *str,
int len)
{
#define MATCH(s1, var, value) \
if (field_matches (s1, s, len)) var = value
if (field_matches ("Normal", str, len))
return;
if (0) ;
#define FIELD(NAME) \
if (find_field (STRINGIFY (NAME), NAME##_map, ARRAY_LENGTH (NAME##_map), str, len, \
(int *)(void *)&props->NAME)) \
return; \
else MATCH ("Oblique", props->slant, CAIRO_FONT_SLANT_OBLIQUE);
else MATCH ("Italic", props->slant, CAIRO_FONT_SLANT_ITALIC);
FIELD (weight);
FIELD (slant);
FIELD (stretch);
FIELD (smallcaps);
FIELD (monospace);
else MATCH ("Thin", props->weight, TWIN_WEIGHT_THIN);
else MATCH ("Ultra-Light", props->weight, TWIN_WEIGHT_ULTRALIGHT);
else MATCH ("Extra-Light", props->weight, TWIN_WEIGHT_ULTRALIGHT);
else MATCH ("Light", props->weight, TWIN_WEIGHT_LIGHT);
else MATCH ("Book", props->weight, TWIN_WEIGHT_BOOK);
else MATCH ("Regular", props->weight, TWIN_WEIGHT_NORMAL);
else MATCH ("Medium", props->weight, TWIN_WEIGHT_MEDIUM);
else MATCH ("Semi-Bold", props->weight, TWIN_WEIGHT_SEMIBOLD);
else MATCH ("Demi-Bold", props->weight, TWIN_WEIGHT_SEMIBOLD);
else MATCH ("Bold", props->weight, TWIN_WEIGHT_BOLD);
else MATCH ("Ultra-Bold", props->weight, TWIN_WEIGHT_ULTRABOLD);
else MATCH ("Extra-Bold", props->weight, TWIN_WEIGHT_ULTRABOLD);
else MATCH ("Heavy", props->weight, TWIN_WEIGHT_HEAVY);
else MATCH ("Black", props->weight, TWIN_WEIGHT_HEAVY);
else MATCH ("Ultra-Heavy", props->weight, TWIN_WEIGHT_ULTRAHEAVY);
else MATCH ("Extra-Heavy", props->weight, TWIN_WEIGHT_ULTRAHEAVY);
else MATCH ("Ultra-Black", props->weight, TWIN_WEIGHT_ULTRAHEAVY);
else MATCH ("Extra-Black", props->weight, TWIN_WEIGHT_ULTRAHEAVY);
else MATCH ("Ultra-Condensed", props->stretch, TWIN_STRETCH_ULTRA_CONDENSED);
else MATCH ("Extra-Condensed", props->stretch, TWIN_STRETCH_EXTRA_CONDENSED);
else MATCH ("Condensed", props->stretch, TWIN_STRETCH_CONDENSED);
else MATCH ("Semi-Condensed", props->stretch, TWIN_STRETCH_SEMI_CONDENSED);
else MATCH ("Semi-Expanded", props->stretch, TWIN_STRETCH_SEMI_EXPANDED);
else MATCH ("Expanded", props->stretch, TWIN_STRETCH_EXPANDED);
else MATCH ("Extra-Expanded", props->stretch, TWIN_STRETCH_EXTRA_EXPANDED);
else MATCH ("Ultra-Expanded", props->stretch, TWIN_STRETCH_ULTRA_EXPANDED);
else MATCH ("Mono", props->monospace, TRUE);
else MATCH ("Monospace", props->monospace, TRUE);
else MATCH ("Small-Caps", props->smallcaps, TRUE);
#undef FIELD
}
static void
@ -178,11 +270,8 @@ face_props_parse (twin_face_properties_t *props,
{
const char *start, *end;
#define ISALPHA(c) \
(((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
for (start = end = s; *end; end++) {
if (ISALPHA (*end) || *end == '-')
if (*end != ' ' && *end != ':')
continue;
if (start < end)

View file

@ -120,6 +120,10 @@ _cairo_win32_tmpfile (void);
#undef ARRAY_LENGTH
#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
#undef STRINGIFY
#undef STRINGIFY_ARG
#define STRINGIFY(macro_or_string) STRINGIFY_ARG (macro_or_string)
#define STRINGIFY_ARG(contents) #contents
/* This has to be updated whenever #cairo_status_t is extended. That's
* a bit of a pain, but it should be easy to always catch as long as