Compare commits

...

6 Commits

Author SHA1 Message Date
Alexander Larsson
46982d1234 GtkWidgetPath: No need to lazily initiate GtkBitmaps
We already handle NULL meaning an initialized empty bitmask.
2012-02-08 14:35:51 +01:00
Alexander Larsson
f9d9b26d98 Store GtkBitmap data inline in the pointer
Bitmaps are often sparse in some way, which we can use by storing such
bitmaps inside the actual GtkBitmap pointer, which we detect by looking at
the least significant bit (which is never set for normal objects due to
alignment rules).

There are two basic approaches, you can store the bitmasks smaller than
31/63 bits directly in the pointer, or you can use the pointer as a
single bit number, considering that bit set.

I did some measurements on this, and it turns out that 63 bits is enought
for most bitmaps right now, but not 31bit, which means this is only efficient
on 64bit arches. Additionally it doesn't scale well as the number of style
classes and regions increase.

Using the data to store a single bit number however was almost as good as 63
bits always and sometimes better, and it will continue to scale as we
add more classes and regions.

With this change we use an additional 116KB ram in Nautilus after
startup.
2012-02-08 14:27:29 +01:00
Alexander Larsson
493b7f2719 Allocate GtkBitmap data inline, not using GArray
This alone saves ~240k of GtkBitmap data after just starting up
nautilus.
2012-02-08 11:40:03 +01:00
Alexander Larsson
0fa10388dd Change all gtk_bitmask modifier functions to take a GtkBitmask**
This way we can do some smart things when modifiying bitmasks,
like:
 * Special case empty bitmasks as NULL (yet still allow them to be modified)
 * Use the GtkBitmask object to contain the actual array of items,
   rather than a pointer to it
 * Use bit trickery to store "small" data in the actual pointer
2012-02-08 10:41:17 +01:00
Alexander Larsson
1ffc8ebb8a Initial version of using bitmaps for regions and styles 2012-02-08 00:27:13 +01:00
Alexander Larsson
c18d21f312 Add various new functions to gtkbitmask
These are needed for later commits
2012-02-07 23:35:56 +01:00
8 changed files with 870 additions and 488 deletions

View File

@@ -20,7 +20,6 @@
#include <config.h>
#define GTK_INSIDE_BITMASK_C
#include "gtk/gtkbitmaskprivate.h"
#define VALUE_TYPE gsize
@@ -28,10 +27,163 @@
#define VALUE_SIZE_BITS (sizeof (VALUE_TYPE) * 8)
#define VALUE_BIT(idx) (((VALUE_TYPE) 1) << (idx))
struct _GtkBitmask {
guint len;
guint alloc;
VALUE_TYPE data[1];
};
typedef struct {
GtkBitmask bitmask;
VALUE_TYPE more_data[3];
const GtkBitmask *orig;
} GtkBitmaskPrealloc;
static GtkBitmask *
_gtk_bitmask_allocate (guint size)
{
GtkBitmask *mask;
mask = g_malloc (sizeof (GtkBitmask) + sizeof(VALUE_TYPE) * (size - 1));
mask->len = 0;
mask->alloc = size;
return mask;
}
static void
_gtk_bitmask_resize (GtkBitmask **mask, guint len)
{
GtkBitmask *new, *old;
int i;
old = *mask;
if (old->alloc < len)
{
new = _gtk_bitmask_allocate (len);
for (i = 0; i < old->len; i++)
new->data[i] = old->data[i];
new->len = old->len;
g_free (old);
*mask = new;
}
/* If expanding, clear the new data */
if (len > (*mask)->len)
{
for (i = (*mask)->len; i < len; i++)
(*mask)->data[i] = 0;
}
(*mask)->len = len;
}
static gboolean
gtk_bitmask_is_bit (const GtkBitmask *mask)
{
return (((gsize)mask) & 1);
}
static GtkBitmask *
gtk_bitmask_for_bit (guint bit)
{
gsize mask;
mask = bit;
mask <<= 1;
mask |= 1;
return (GtkBitmask *)mask;
}
static guint
gtk_bitmask_get_bit (const GtkBitmask *mask)
{
return ((gsize)mask) >> 1;
}
static gboolean
gtk_bitmask_is_inline (const GtkBitmask *mask)
{
return mask == NULL || gtk_bitmask_is_bit (mask);
}
static void
gtk_bitmask_realize_for_write (GtkBitmask **mask, guint size_hint)
{
GtkBitmask *realized;
if (*mask == NULL)
{
realized = _gtk_bitmask_allocate (MAX (size_hint, 1));
realized->len = 0;
*mask = realized;
}
else if (gtk_bitmask_is_bit (*mask))
{
guint bit = gtk_bitmask_get_bit (*mask);
guint len = (bit / VALUE_SIZE_BITS) + 1;
int i;
realized = _gtk_bitmask_allocate (MAX (len, size_hint));
realized->len = len;
for (i = 0; i < len; i++)
realized->data[i] = 0;
_gtk_bitmask_set (&realized, bit, TRUE);
*mask = realized;
}
}
static void
gtk_bitmask_realize (const GtkBitmask **mask, GtkBitmaskPrealloc *prealloc)
{
prealloc->orig = *mask;
if (*mask == NULL)
{
prealloc->bitmask.len = 0;
prealloc->bitmask.alloc = 4;
*mask = &prealloc->bitmask;
}
else if (gtk_bitmask_is_bit (*mask))
{
GtkBitmask *realized;
int i;
guint bit = gtk_bitmask_get_bit (*mask);
guint len = (bit / VALUE_SIZE_BITS) + 1;
if (len <= 4)
{
prealloc->bitmask.alloc = 4;
realized = &prealloc->bitmask;
}
else
realized = _gtk_bitmask_allocate (len);
for (i = 0; i < len; i++)
realized->data[i] = 0;
realized->len = len;
_gtk_bitmask_set (&realized, bit, TRUE);
*mask = realized;
}
}
static void
gtk_bitmask_unrealize (const GtkBitmask *mask, GtkBitmaskPrealloc *prealloc)
{
if (mask != prealloc->orig &&
mask != &prealloc->bitmask)
g_free ((GtkBitmask *)mask);
}
GtkBitmask *
_gtk_bitmask_new (void)
{
return g_array_new (FALSE, TRUE, sizeof (VALUE_TYPE));
return NULL;
}
GtkBitmask *
@@ -39,10 +191,11 @@ _gtk_bitmask_copy (const GtkBitmask *mask)
{
GtkBitmask *copy;
g_return_val_if_fail (mask != NULL, NULL);
if (gtk_bitmask_is_inline (mask))
return (GtkBitmask *)mask;
copy = _gtk_bitmask_new ();
_gtk_bitmask_union (copy, mask);
_gtk_bitmask_union (&copy, mask);
return copy;
}
@@ -50,29 +203,31 @@ _gtk_bitmask_copy (const GtkBitmask *mask)
void
_gtk_bitmask_free (GtkBitmask *mask)
{
g_return_if_fail (mask != NULL);
g_array_free (mask, TRUE);
if (!gtk_bitmask_is_inline (mask))
g_free (mask);
}
void
_gtk_bitmask_print (const GtkBitmask *mask,
GString *string)
GString *string)
{
GtkBitmaskPrealloc mask_prealloc;
int i;
g_return_if_fail (mask != NULL);
gtk_bitmask_realize (&mask, &mask_prealloc);
g_return_if_fail (string != NULL);
for (i = mask->len * VALUE_SIZE_BITS - 1; i >= 0; i--)
{
if (_gtk_bitmask_get (mask, i))
break;
break;
}
if (i < 0)
{
g_string_append_c (string, '0');
gtk_bitmask_unrealize (mask, &mask_prealloc);
return;
}
@@ -80,13 +235,15 @@ _gtk_bitmask_print (const GtkBitmask *mask,
{
g_string_append_c (string, _gtk_bitmask_get (mask, i) ? '1' : '0');
}
gtk_bitmask_unrealize (mask, &mask_prealloc);
}
char *
_gtk_bitmask_to_string (const GtkBitmask *mask)
{
GString *string;
string = g_string_new (NULL);
_gtk_bitmask_print (mask, string);
return g_string_free (string, FALSE);
@@ -97,74 +254,139 @@ _gtk_bitmask_to_string (const GtkBitmask *mask)
* _gtk_bitmask_is_empty() depends on this.
*/
static void
gtk_bitmask_shrink (GtkBitmask *mask)
gtk_bitmask_shrink (GtkBitmask **mask)
{
guint i;
for (i = mask->len; i; i--)
if (gtk_bitmask_is_inline (*mask))
return;
for (i = (*mask)->len; i; i--)
{
if (g_array_index (mask, VALUE_TYPE, i - 1))
break;
if ((*mask)->data[i - 1])
break;
}
g_array_set_size (mask, i);
if (i == 0)
{
g_free (*mask);
*mask = NULL;
}
else
(*mask)->len = i;
}
void
_gtk_bitmask_intersect (GtkBitmask *mask,
const GtkBitmask *other)
_gtk_bitmask_intersect (GtkBitmask **mask,
const GtkBitmask *other)
{
GtkBitmaskPrealloc other_prealloc;
guint i;
g_return_if_fail (mask != NULL);
g_return_if_fail (other != NULL);
g_array_set_size (mask, MIN (mask->len, other->len));
for (i = 0; i < mask->len; i++)
if (gtk_bitmask_is_inline (*mask) &&
gtk_bitmask_is_inline (other))
{
g_array_index (mask, VALUE_TYPE, i) &= g_array_index (other, VALUE_TYPE, i);
if (mask == NULL || other == NULL)
*mask = NULL;
else
{
/* Different bits, the intersection is empty */
if (*mask != other)
*mask = NULL;
/* If same bit, the value is already right */
}
return;
}
gtk_bitmask_realize (&other, &other_prealloc);
gtk_bitmask_realize_for_write (mask, 0);
_gtk_bitmask_resize (mask, MIN ((*mask)->len, other->len));
for (i = 0; i < (*mask)->len; i++)
(*mask)->data[i] &= other->data[i];
gtk_bitmask_shrink (mask);
gtk_bitmask_unrealize (other, &other_prealloc);
}
void
_gtk_bitmask_union (GtkBitmask *mask,
const GtkBitmask *other)
_gtk_bitmask_union (GtkBitmask **mask,
const GtkBitmask *other)
{
GtkBitmaskPrealloc other_prealloc;
guint i;
g_return_if_fail (mask != NULL);
g_return_if_fail (other != NULL);
g_array_set_size (mask, MAX (mask->len, other->len));
for (i = 0; i < other->len; i++)
if (gtk_bitmask_is_inline (*mask) &&
gtk_bitmask_is_inline (other))
{
g_array_index (mask, VALUE_TYPE, i) |= g_array_index (other, VALUE_TYPE, i);
/* Union nothing with something is something */
if (*mask == NULL)
{
*mask = (GtkBitmask *)other;
return;
}
/* Union with nothing or same is same */
if (other == NULL ||
*mask == other)
return;
}
gtk_bitmask_realize (&other, &other_prealloc);
gtk_bitmask_realize_for_write (mask, other->len);
_gtk_bitmask_resize (mask, MAX ((*mask)->len, other->len));
for (i = 0; i < other->len; i++)
(*mask)->data[i] |= other->data[i];
gtk_bitmask_unrealize (other, &other_prealloc);
}
void
_gtk_bitmask_subtract (GtkBitmask *mask,
const GtkBitmask *other)
_gtk_bitmask_subtract (GtkBitmask **mask,
const GtkBitmask *other)
{
GtkBitmaskPrealloc other_prealloc;
guint i;
g_return_if_fail (mask != NULL);
g_return_if_fail (other != NULL);
if (gtk_bitmask_is_inline (*mask) &&
gtk_bitmask_is_inline (other))
{
/* Subtract from nothing, or subtract nothing => no change */
if (*mask == NULL ||
other == NULL)
return;
/* Subtract the same bit => nothing */
if (*mask == other)
*mask = NULL;
/* Subtract other bit => no change */
return;
}
gtk_bitmask_realize (&other, &other_prealloc);
gtk_bitmask_realize_for_write (mask, 0);
for (i = 0; i < other->len; i++)
{
g_array_index (mask, VALUE_TYPE, i) &= ~g_array_index (other, VALUE_TYPE, i);
}
(*mask)->data[i] &= ~(other->data[i]);
gtk_bitmask_shrink (mask);
gtk_bitmask_unrealize (other, &other_prealloc);
}
static void
gtk_bitmask_indexes (guint index_,
guint *array_index,
guint *bit_index)
guint *array_index,
guint *bit_index)
{
*array_index = index_ / VALUE_SIZE_BITS;
*bit_index = index_ % VALUE_SIZE_BITS;
@@ -172,52 +394,79 @@ gtk_bitmask_indexes (guint index_,
gboolean
_gtk_bitmask_get (const GtkBitmask *mask,
guint index_)
guint index_)
{
guint array_index, bit_index;
g_return_val_if_fail (mask != NULL, FALSE);
if (mask == NULL)
return FALSE;
if (gtk_bitmask_is_bit (mask))
{
guint bit = gtk_bitmask_get_bit (mask);
if (bit == index_)
return TRUE;
else
return FALSE;
}
gtk_bitmask_indexes (index_, &array_index, &bit_index);
if (array_index >= mask->len)
return FALSE;
return (g_array_index (mask, VALUE_TYPE, array_index) & VALUE_BIT (bit_index)) ? TRUE : FALSE;
return (mask->data[array_index] & VALUE_BIT (bit_index)) ? TRUE : FALSE;
}
void
_gtk_bitmask_set (GtkBitmask *mask,
guint index_,
gboolean value)
_gtk_bitmask_set (GtkBitmask **mask,
guint index_,
gboolean value)
{
guint array_index, bit_index;
g_return_if_fail (mask != NULL);
if (*mask == NULL)
{
if (value)
*mask = gtk_bitmask_for_bit (index_);
return;
}
if (gtk_bitmask_is_bit (*mask) &&
gtk_bitmask_get_bit (*mask) == index_)
{
if (!value)
*mask = NULL;
return;
}
gtk_bitmask_realize_for_write (mask, 0);
gtk_bitmask_indexes (index_, &array_index, &bit_index);
if (value)
{
if (array_index >= mask->len)
g_array_set_size (mask, array_index + 1);
g_array_index (mask, VALUE_TYPE, array_index) |= VALUE_BIT (bit_index);
if (array_index >= (*mask)->len)
_gtk_bitmask_resize (mask, array_index + 1);
(*mask)->data[array_index] |= VALUE_BIT (bit_index);
}
else
{
if (array_index < mask->len)
{
g_array_index (mask, VALUE_TYPE, array_index) &= ~ VALUE_BIT (bit_index);
gtk_bitmask_shrink (mask);
}
if (array_index < (*mask)->len)
{
(*mask)->data[array_index] &= ~ VALUE_BIT (bit_index);
gtk_bitmask_shrink (mask);
}
}
}
void
_gtk_bitmask_invert_range (GtkBitmask *mask,
guint start,
guint end)
_gtk_bitmask_invert_range (GtkBitmask **mask,
guint start,
guint end)
{
guint i;
@@ -227,53 +476,231 @@ _gtk_bitmask_invert_range (GtkBitmask *mask,
/* I CAN HAS SPEEDUP? */
for (i = start; i < end; i++)
_gtk_bitmask_set (mask, i, !_gtk_bitmask_get (mask, i));
_gtk_bitmask_set (mask, i, !_gtk_bitmask_get (*mask, i));
}
gboolean
_gtk_bitmask_is_empty (const GtkBitmask *mask)
{
g_return_val_if_fail (mask != NULL, FALSE);
return mask->len == 0;
return mask == NULL;
}
gboolean
_gtk_bitmask_equals (const GtkBitmask *mask,
const GtkBitmask *other)
const GtkBitmask *other)
{
GtkBitmaskPrealloc mask_prealloc;
GtkBitmaskPrealloc other_prealloc;
guint i;
g_return_val_if_fail (mask != NULL, FALSE);
g_return_val_if_fail (other != NULL, FALSE);
if (gtk_bitmask_is_inline (mask) &&
gtk_bitmask_is_inline (other))
return mask == other;
gtk_bitmask_realize (&mask, &mask_prealloc);
gtk_bitmask_realize (&other, &other_prealloc);
if (mask->len != other->len)
return FALSE;
for (i = 0; i < mask->len; i++)
{
if (g_array_index (mask, VALUE_TYPE, i) != g_array_index (other, VALUE_TYPE, i))
return FALSE;
if (mask->data[i] != other->data[i])
return FALSE;
}
gtk_bitmask_unrealize (mask, &mask_prealloc);
gtk_bitmask_unrealize (other, &other_prealloc);
return TRUE;
}
gboolean
_gtk_bitmask_intersects (const GtkBitmask *mask,
const GtkBitmask *other)
const GtkBitmask *other)
{
GtkBitmaskPrealloc mask_prealloc;
GtkBitmaskPrealloc other_prealloc;
int i;
gboolean res;
g_return_val_if_fail (mask != NULL, FALSE);
g_return_val_if_fail (other != NULL, FALSE);
if (gtk_bitmask_is_inline (mask) &&
gtk_bitmask_is_inline (other))
{
if (mask == NULL || other == NULL)
return FALSE;
if (mask == other)
return TRUE;
return FALSE;
}
gtk_bitmask_realize (&mask, &mask_prealloc);
gtk_bitmask_realize (&other, &other_prealloc);
res = FALSE;
for (i = MIN (mask->len, other->len) - 1; i >= 0; i--)
{
if (g_array_index (mask, VALUE_TYPE, i) & g_array_index (other, VALUE_TYPE, i))
return TRUE;
if (mask->data[i] & other->data[i])
{
res = TRUE;
break;
}
}
gtk_bitmask_unrealize (mask, &mask_prealloc);
gtk_bitmask_unrealize (other, &other_prealloc);
return res;
}
void
_gtk_bitmask_clear (GtkBitmask **mask)
{
_gtk_bitmask_free (*mask);
*mask = NULL;
}
guint
_gtk_bitmask_get_uint (const GtkBitmask *mask,
guint index_)
{
GtkBitmaskPrealloc mask_prealloc;
guint array_index, bit_index;
VALUE_TYPE value1, value2;
gtk_bitmask_realize (&mask, &mask_prealloc);
gtk_bitmask_indexes (index_, &array_index, &bit_index);
value1 = value2 = 0;
if (array_index < mask->len)
value1 = mask->data[array_index];
if (array_index + 1 < mask->len)
value2 = mask->data[array_index + 1];
value1 >>= bit_index;
if (bit_index != 0)
value2 <<= VALUE_SIZE_BITS - bit_index;
else
value2 = 0;
gtk_bitmask_unrealize (mask, &mask_prealloc);
return (guint)(value1 | value2);
}
void
_gtk_bitmask_set_uint (GtkBitmask **mask,
guint index_,
guint bits)
{
guint array_index, bit_index;
VALUE_TYPE value1, value2;
VALUE_TYPE new_value1, new_value2;
g_return_if_fail (mask != NULL);
gtk_bitmask_realize_for_write (mask, 0);
gtk_bitmask_indexes (index_, &array_index, &bit_index);
value1 = value2 = 0;
if (array_index < (*mask)->len)
value1 = (*mask)->data[array_index];
if (array_index + 1 < (*mask)->len)
value2 = (*mask)->data[array_index + 1];
/* Mask out old uint value */
new_value1 = ((VALUE_TYPE)G_MAXUINT) << bit_index;
if (bit_index != 0)
new_value2 = ((VALUE_TYPE)G_MAXUINT) >> (VALUE_SIZE_BITS - bit_index);
else
new_value2 = 0;
value1 &= ~new_value1;
value2 &= ~new_value2;
/* merge in new uint value */
new_value1 = ((VALUE_TYPE)bits) << bit_index;
if (bit_index != 0)
new_value2 = ((VALUE_TYPE)bits) >> (VALUE_SIZE_BITS - bit_index);
else
new_value2 = 0;
value1 |= new_value1;
value2 |= new_value2;
/* Ensure there is space to write back */
_gtk_bitmask_resize (mask, MAX ((*mask)->len, array_index + 2));
(*mask)->data[array_index] = value1;
(*mask)->data[array_index + 1] = value2;
gtk_bitmask_shrink (mask);
}
guint
_gtk_bitmask_hash (const GtkBitmask *mask)
{
GtkBitmaskPrealloc mask_prealloc;
int i;
VALUE_TYPE value, hash;
if (mask == NULL)
return 0;
gtk_bitmask_realize (&mask, &mask_prealloc);
hash = 0;
for (i = mask->len - 1; i >= 0; i--)
{
value = mask->data[i];
hash = hash ^ value;
}
if (sizeof (hash) > sizeof (guint))
hash = hash ^ (hash >> 32);
gtk_bitmask_unrealize (mask, &mask_prealloc);
return hash;
}
gboolean
_gtk_bitmask_find_next_set (const GtkBitmask *mask,
guint *pos)
{
GtkBitmaskPrealloc mask_prealloc;
guint array_index, bit_index;
VALUE_TYPE value;
if (mask == NULL)
return FALSE;
gtk_bitmask_realize (&mask, &mask_prealloc);
gtk_bitmask_indexes (*pos, &array_index, &bit_index);
while (array_index < mask->len)
{
value = mask->data[array_index];
/* TODO: This could use ffsl if bit_index == 0 */
while (bit_index < VALUE_SIZE_BITS)
{
if (value & VALUE_BIT (bit_index))
{
*pos = array_index * VALUE_SIZE_BITS + bit_index;
return TRUE;
}
bit_index++;
}
array_index++;
bit_index = 0;
}
gtk_bitmask_unrealize (mask, &mask_prealloc);
return FALSE;
}

View File

@@ -25,11 +25,7 @@
G_BEGIN_DECLS
#ifdef GTK_INSIDE_BITMASK_C
typedef GArray GtkBitmask;
#else
typedef struct _GtkBitmask GtkBitmask;
#endif
GtkBitmask * _gtk_bitmask_new (void);
@@ -40,20 +36,26 @@ char * _gtk_bitmask_to_string (const GtkBitmask *mask);
void _gtk_bitmask_print (const GtkBitmask *mask,
GString *string);
void _gtk_bitmask_intersect (GtkBitmask *mask,
void _gtk_bitmask_intersect (GtkBitmask **mask,
const GtkBitmask *other);
void _gtk_bitmask_union (GtkBitmask *mask,
void _gtk_bitmask_union (GtkBitmask **mask,
const GtkBitmask *other);
void _gtk_bitmask_subtract (GtkBitmask *mask,
void _gtk_bitmask_subtract (GtkBitmask **mask,
const GtkBitmask *other);
gboolean _gtk_bitmask_get (const GtkBitmask *mask,
guint index_);
void _gtk_bitmask_set (GtkBitmask *mask,
void _gtk_bitmask_set (GtkBitmask **mask,
guint index_,
gboolean value);
void _gtk_bitmask_clear (GtkBitmask **mask);
guint _gtk_bitmask_get_uint (const GtkBitmask *mask,
guint index_);
void _gtk_bitmask_set_uint (GtkBitmask **mask,
guint index_,
guint bits);
void _gtk_bitmask_invert_range (GtkBitmask *mask,
void _gtk_bitmask_invert_range (GtkBitmask **mask,
guint start,
guint end);
@@ -62,6 +64,9 @@ gboolean _gtk_bitmask_equals (const GtkBitmask *mask,
const GtkBitmask *other);
gboolean _gtk_bitmask_intersects (const GtkBitmask *mask,
const GtkBitmask *other);
guint _gtk_bitmask_hash (const GtkBitmask *mask);
gboolean _gtk_bitmask_find_next_set (const GtkBitmask *mask,
guint *pos);
G_END_DECLS

View File

@@ -45,7 +45,7 @@ _gtk_css_lookup_new (void)
lookup = g_malloc0 (sizeof (GtkCssLookup) + sizeof (GtkCssLookupValue) * n);
lookup->missing = _gtk_bitmask_new ();
_gtk_bitmask_invert_range (lookup->missing, 0, n);
_gtk_bitmask_invert_range (&lookup->missing, 0, n);
return lookup;
}
@@ -99,7 +99,7 @@ _gtk_css_lookup_set (GtkCssLookup *lookup,
g_return_if_fail (_gtk_bitmask_get (lookup->missing, id));
g_return_if_fail (value != NULL);
_gtk_bitmask_set (lookup->missing, id, FALSE);
_gtk_bitmask_set (&lookup->missing, id, FALSE);
lookup->values[id].value = value;
lookup->values[id].section = section;
}
@@ -133,7 +133,7 @@ _gtk_css_lookup_set_computed (GtkCssLookup *lookup,
g_return_if_fail (_gtk_bitmask_get (lookup->missing, id));
g_return_if_fail (value != NULL);
_gtk_bitmask_set (lookup->missing, id, FALSE);
_gtk_bitmask_set (&lookup->missing, id, FALSE);
lookup->values[id].computed = value;
lookup->values[id].section = section;
}

View File

@@ -1216,7 +1216,7 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
g_return_if_fail (_gtk_css_style_property_is_specified_type (GTK_CSS_STYLE_PROPERTY (prop),
G_VALUE_TYPE (&value->value)));
_gtk_bitmask_set (ruleset->set_styles,
_gtk_bitmask_set (&ruleset->set_styles,
_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)),
TRUE);
g_hash_table_insert (ruleset->style, prop, value);

View File

@@ -307,12 +307,6 @@ typedef struct PropertyValue PropertyValue;
typedef struct AnimationInfo AnimationInfo;
typedef struct StyleData StyleData;
struct GtkRegion
{
GQuark class_quark;
GtkRegionFlags flags;
};
struct GtkStyleProviderData
{
GtkStyleProvider *provider;
@@ -329,8 +323,8 @@ struct PropertyValue
struct GtkStyleInfo
{
GArray *style_classes;
GArray *regions;
GtkBitmask *style_classes;
GtkBitmask *regions;
GtkJunctionSides junction_sides;
GtkStateFlags state_flags;
};
@@ -477,8 +471,8 @@ style_info_new (void)
GtkStyleInfo *info;
info = g_slice_new0 (GtkStyleInfo);
info->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
info->regions = g_array_new (FALSE, FALSE, sizeof (GtkRegion));
info->style_classes = _gtk_bitmask_new ();
info->regions = _gtk_bitmask_new ();
return info;
}
@@ -486,8 +480,8 @@ style_info_new (void)
static void
style_info_free (GtkStyleInfo *info)
{
g_array_free (info->style_classes, TRUE);
g_array_free (info->regions, TRUE);
_gtk_bitmask_free (info->style_classes);
_gtk_bitmask_free (info->regions);
g_slice_free (GtkStyleInfo, info);
}
@@ -497,13 +491,10 @@ style_info_copy (const GtkStyleInfo *info)
GtkStyleInfo *copy;
copy = style_info_new ();
g_array_insert_vals (copy->style_classes, 0,
info->style_classes->data,
info->style_classes->len);
g_array_insert_vals (copy->regions, 0,
info->regions->data,
info->regions->len);
_gtk_bitmask_union (&copy->style_classes,
info->style_classes);
_gtk_bitmask_union (&copy->regions,
info->regions);
copy->junction_sides = info->junction_sides;
copy->state_flags = info->state_flags;
@@ -515,25 +506,12 @@ static guint
style_info_hash (gconstpointer elem)
{
const GtkStyleInfo *info;
guint i, hash = 0;
guint hash = 0;
info = elem;
for (i = 0; i < info->style_classes->len; i++)
{
hash += g_array_index (info->style_classes, GQuark, i);
hash <<= 5;
}
for (i = 0; i < info->regions->len; i++)
{
GtkRegion *region;
region = &g_array_index (info->regions, GtkRegion, i);
hash += region->class_quark;
hash += region->flags;
hash <<= 5;
}
hash = _gtk_bitmask_hash (info->style_classes);
hash ^= _gtk_bitmask_hash (info->regions);
return hash ^ info->state_flags;
}
@@ -553,20 +531,12 @@ style_info_equal (gconstpointer elem1,
if (info1->junction_sides != info2->junction_sides)
return FALSE;
if (info1->style_classes->len != info2->style_classes->len)
if (!_gtk_bitmask_equals (info1->style_classes,
info2->style_classes))
return FALSE;
if (memcmp (info1->style_classes->data,
info2->style_classes->data,
info1->style_classes->len * sizeof (GQuark)) != 0)
return FALSE;
if (info1->regions->len != info2->regions->len)
return FALSE;
if (memcmp (info1->regions->data,
info2->regions->data,
info1->regions->len * sizeof (GtkRegion)) != 0)
if (!_gtk_bitmask_equals (info1->regions,
info2->regions))
return FALSE;
return TRUE;
@@ -1034,7 +1004,7 @@ create_query_path (GtkStyleContext *context)
GtkStyleContextPrivate *priv;
GtkWidgetPath *path;
GtkStyleInfo *info;
guint i, pos;
guint pos;
priv = context->priv;
path = gtk_widget_path_copy (priv->widget_path);
@@ -1042,26 +1012,11 @@ create_query_path (GtkStyleContext *context)
info = priv->info_stack->data;
/* Set widget regions */
for (i = 0; i < info->regions->len; i++)
{
GtkRegion *region;
region = &g_array_index (info->regions, GtkRegion, i);
gtk_widget_path_iter_add_region (path, pos,
g_quark_to_string (region->class_quark),
region->flags);
}
_gtk_widget_path_iter_add_regions (path, pos,
info->regions);
/* Set widget classes */
for (i = 0; i < info->style_classes->len; i++)
{
GQuark quark;
quark = g_array_index (info->style_classes, GQuark, i);
gtk_widget_path_iter_add_class (path, pos,
g_quark_to_string (quark));
}
_gtk_widget_path_iter_add_classes (path, pos, info->style_classes);
return path;
}
@@ -1861,96 +1816,79 @@ gtk_style_context_restore (GtkStyleContext *context)
priv->current_data = NULL;
}
static gboolean
style_class_find (GArray *array,
GQuark class_quark,
guint *position)
static GHashTable *style_class_masks;
static GPtrArray *style_class_masks_reverse;
static guint style_class_masks_next;
static GHashTable *style_region_masks;
static GPtrArray *style_region_masks_reverse;
static guint style_region_masks_next;
guint
_gtk_style_class_get_mask (const gchar *class_name)
{
gint min, max, mid;
gboolean found = FALSE;
guint pos;
guint value;
gpointer ptr_value;
if (position)
*position = 0;
if (!array || array->len == 0)
return FALSE;
min = 0;
max = array->len - 1;
do
if (style_class_masks == NULL)
{
GQuark item;
mid = (min + max) / 2;
item = g_array_index (array, GQuark, mid);
if (class_quark == item)
{
found = TRUE;
pos = mid;
}
else if (class_quark > item)
min = pos = mid + 1;
else
{
max = mid - 1;
pos = mid;
}
style_class_masks = g_hash_table_new (g_str_hash, g_str_equal);
style_class_masks_reverse = g_ptr_array_new ();
}
while (!found && min <= max);
if (position)
*position = pos;
return found;
if (g_hash_table_lookup_extended (style_class_masks, class_name,
NULL, &ptr_value))
value = GPOINTER_TO_INT (ptr_value);
else
{
char *str = (char *)g_intern_string (class_name);
value = style_class_masks_next++;
ptr_value = GINT_TO_POINTER (value);
g_hash_table_insert (style_class_masks, str, ptr_value);
g_ptr_array_add (style_class_masks_reverse, str);
}
return value;
}
static gboolean
region_find (GArray *array,
GQuark class_quark,
guint *position)
const gchar *
_gtk_style_class_get_name_from_mask (guint mask)
{
gint min, max, mid;
gboolean found = FALSE;
guint pos;
if (mask < style_class_masks_next)
return g_ptr_array_index (style_class_masks_reverse, mask);
return NULL;
}
if (position)
*position = 0;
guint
_gtk_style_region_get_mask (const gchar *region_name)
{
guint value;
gpointer ptr_value;
if (!array || array->len == 0)
return FALSE;
min = 0;
max = array->len - 1;
do
if (style_region_masks == NULL)
{
GtkRegion *region;
mid = (min + max) / 2;
region = &g_array_index (array, GtkRegion, mid);
if (region->class_quark == class_quark)
{
found = TRUE;
pos = mid;
}
else if (region->class_quark > class_quark)
min = pos = mid + 1;
else
{
max = mid - 1;
pos = mid;
}
style_region_masks = g_hash_table_new (g_str_hash, g_str_equal);
style_region_masks_reverse = g_ptr_array_new ();
}
while (!found && min <= max);
if (position)
*position = pos;
if (g_hash_table_lookup_extended (style_region_masks, region_name,
NULL, &ptr_value))
value = GPOINTER_TO_INT (ptr_value);
else
{
char *str = (char *)g_intern_string (region_name);
value = style_region_masks_next++;
ptr_value = GINT_TO_POINTER (value);
g_hash_table_insert (style_region_masks, str, ptr_value);
g_ptr_array_add (style_region_masks_reverse, str);
}
return value;
}
return found;
const gchar *
_gtk_style_region_get_name_from_mask (guint mask)
{
if (mask < style_region_masks_next)
return g_ptr_array_index (style_region_masks_reverse, mask);
return NULL;
}
/**
@@ -1983,21 +1921,20 @@ gtk_style_context_add_class (GtkStyleContext *context,
{
GtkStyleContextPrivate *priv;
GtkStyleInfo *info;
GQuark class_quark;
guint position;
guint class_mask;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (class_name != NULL);
priv = context->priv;
class_quark = g_quark_from_string (class_name);
class_mask = _gtk_style_class_get_mask (class_name);
g_assert (priv->info_stack != NULL);
info = priv->info_stack->data;
if (!style_class_find (info->style_classes, class_quark, &position))
if (!_gtk_bitmask_get (info->style_classes, class_mask))
{
g_array_insert_val (info->style_classes, position, class_quark);
_gtk_bitmask_set (&info->style_classes, class_mask, TRUE);
/* Unset current data, as it likely changed due to the class change */
priv->current_data = NULL;
@@ -2019,25 +1956,21 @@ gtk_style_context_remove_class (GtkStyleContext *context,
{
GtkStyleContextPrivate *priv;
GtkStyleInfo *info;
GQuark class_quark;
guint position;
guint class_mask;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (class_name != NULL);
class_quark = g_quark_try_string (class_name);
if (!class_quark)
return;
class_mask = _gtk_style_class_get_mask (class_name);
priv = context->priv;
g_assert (priv->info_stack != NULL);
info = priv->info_stack->data;
if (style_class_find (info->style_classes, class_quark, &position))
if (_gtk_bitmask_get (info->style_classes, class_mask))
{
g_array_remove_index (info->style_classes, position);
_gtk_bitmask_set (&info->style_classes, class_mask, FALSE);
/* Unset current data, as it likely changed due to the class change */
priv->current_data = NULL;
@@ -2062,25 +1995,19 @@ gtk_style_context_has_class (GtkStyleContext *context,
{
GtkStyleContextPrivate *priv;
GtkStyleInfo *info;
GQuark class_quark;
guint class_mask;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
g_return_val_if_fail (class_name != NULL, FALSE);
class_quark = g_quark_try_string (class_name);
if (!class_quark)
return FALSE;
class_mask = _gtk_style_class_get_mask (class_name);
priv = context->priv;
g_assert (priv->info_stack != NULL);
info = priv->info_stack->data;
if (style_class_find (info->style_classes, class_quark, NULL))
return TRUE;
return FALSE;
return _gtk_bitmask_get (info->style_classes, class_mask);
}
/**
@@ -2111,12 +2038,12 @@ gtk_style_context_list_classes (GtkStyleContext *context)
g_assert (priv->info_stack != NULL);
info = priv->info_stack->data;
for (i = 0; i < info->style_classes->len; i++)
i = 0;
while (_gtk_bitmask_find_next_set (info->style_classes, &i))
{
GQuark quark;
quark = g_array_index (info->style_classes, GQuark, i);
classes = g_list_prepend (classes, (gchar *) g_quark_to_string (quark));
classes = g_list_prepend (classes,
(gchar *) _gtk_style_class_get_name_from_mask (i));
i++;
}
return classes;
@@ -2150,15 +2077,16 @@ gtk_style_context_list_regions (GtkStyleContext *context)
g_assert (priv->info_stack != NULL);
info = priv->info_stack->data;
for (i = 0; i < info->regions->len; i++)
i = 0;
while (_gtk_bitmask_find_next_set (info->regions, &i))
{
GtkRegion *region;
const gchar *class_name;
guint region = i / GTK_REGION_FLAGS_NUM_BITS;
i = region * GTK_REGION_FLAGS_NUM_BITS;
region = &g_array_index (info->regions, GtkRegion, i);
classes = g_list_prepend (classes,
(gchar *)_gtk_style_region_get_name_from_mask (region));
class_name = g_quark_to_string (region->class_quark);
classes = g_list_prepend (classes, (gchar *) class_name);
i += GTK_REGION_FLAGS_NUM_BITS;
}
return classes;
@@ -2222,27 +2150,29 @@ gtk_style_context_add_region (GtkStyleContext *context,
{
GtkStyleContextPrivate *priv;
GtkStyleInfo *info;
GQuark region_quark;
guint position;
guint region;
guint i;
guint old_flags;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (region_name != NULL);
g_return_if_fail (_gtk_style_context_check_region_name (region_name));
priv = context->priv;
region_quark = g_quark_from_string (region_name);
g_assert (priv->info_stack != NULL);
info = priv->info_stack->data;
if (!region_find (info->regions, region_quark, &position))
region = _gtk_style_region_get_mask (region_name);
i = region * GTK_REGION_FLAGS_NUM_BITS;
old_flags = _gtk_bitmask_get_uint (info->regions, i);
if ((old_flags & GTK_REGION_ADDED) == 0)
{
GtkRegion region;
/* Ensure *some* flag is always set so we know this is added */
old_flags |= flags | GTK_REGION_ADDED;
region.class_quark = region_quark;
region.flags = flags;
g_array_insert_val (info->regions, position, region);
_gtk_bitmask_set_uint (&info->regions, i, old_flags);
/* Unset current data, as it likely changed due to the region change */
priv->current_data = NULL;
@@ -2264,25 +2194,28 @@ gtk_style_context_remove_region (GtkStyleContext *context,
{
GtkStyleContextPrivate *priv;
GtkStyleInfo *info;
GQuark region_quark;
guint position;
guint region;
guint i, old_flags;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (region_name != NULL);
region_quark = g_quark_try_string (region_name);
if (!region_quark)
return;
priv = context->priv;
g_assert (priv->info_stack != NULL);
info = priv->info_stack->data;
if (region_find (info->regions, region_quark, &position))
region = _gtk_style_region_get_mask (region_name);
i = region * GTK_REGION_FLAGS_NUM_BITS;
if (info->regions == NULL)
return;
old_flags = _gtk_bitmask_get_uint (info->regions, i);
if ((old_flags & GTK_REGION_ADDED) != 0)
{
g_array_remove_index (info->regions, position);
old_flags &= ~(GTK_REGION_FLAGS_MASK | GTK_REGION_ADDED);
_gtk_bitmask_set_uint (&info->regions, i, old_flags);
/* Unset current data, as it likely changed due to the region change */
priv->current_data = NULL;
@@ -2310,8 +2243,8 @@ gtk_style_context_has_region (GtkStyleContext *context,
{
GtkStyleContextPrivate *priv;
GtkStyleInfo *info;
GQuark region_quark;
guint position;
guint region;
guint i, flags;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
g_return_val_if_fail (region_name != NULL, FALSE);
@@ -2319,25 +2252,19 @@ gtk_style_context_has_region (GtkStyleContext *context,
if (flags_return)
*flags_return = 0;
region_quark = g_quark_try_string (region_name);
if (!region_quark)
return FALSE;
priv = context->priv;
g_assert (priv->info_stack != NULL);
info = priv->info_stack->data;
if (region_find (info->regions, region_quark, &position))
region = _gtk_style_region_get_mask (region_name);
i = region * GTK_REGION_FLAGS_NUM_BITS;
flags = _gtk_bitmask_get_uint (info->regions, i);
if ((flags & GTK_REGION_ADDED) != 0)
{
if (flags_return)
{
GtkRegion *region;
region = &g_array_index (info->regions, GtkRegion, position);
*flags_return = region->flags;
}
*flags_return = flags & GTK_REGION_FLAGS_MASK;
return TRUE;
}

View File

@@ -22,6 +22,7 @@
#include "gtkstylecontext.h"
#include "gtksymboliccolor.h"
#include "gtkbitmaskprivate.h"
G_BEGIN_DECLS
@@ -46,6 +47,22 @@ void _gtk_style_context_get_cursor_color (GtkStyleContext *c
GdkRGBA *primary_color,
GdkRGBA *secondary_color);
guint _gtk_style_class_get_mask (const gchar *class_name);
const gchar * _gtk_style_class_get_name_from_mask (guint mask);
guint _gtk_style_region_get_mask (const gchar *region_name);
const gchar * _gtk_style_region_get_name_from_mask (guint mask);
void _gtk_widget_path_iter_add_classes (GtkWidgetPath *path,
gint pos,
GtkBitmask *classes);
void _gtk_widget_path_iter_add_regions (GtkWidgetPath *path,
gint pos,
GtkBitmask *regions);
#define GTK_REGION_FLAGS_MASK ((1 << 6) - 1)
#define GTK_REGION_FLAGS_NUM_BITS 7
#define GTK_REGION_ADDED (1 << 6)
G_END_DECLS
#endif /* __GTK_STYLE_CONTEXT_PRIVATE_H__ */

View File

@@ -91,8 +91,8 @@ struct GtkPathElement
{
GType type;
GQuark name;
GHashTable *regions;
GArray *classes;
GtkBitmask *regions;
GtkBitmask *classes;
GtkWidgetPath *siblings;
guint sibling_index;
};
@@ -137,23 +137,8 @@ gtk_path_element_copy (GtkPathElement *dest,
dest->siblings = gtk_widget_path_ref (src->siblings);
dest->sibling_index = src->sibling_index;
if (src->regions)
{
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, src->regions);
dest->regions = g_hash_table_new (NULL, NULL);
while (g_hash_table_iter_next (&iter, &key, &value))
g_hash_table_insert (dest->regions, key, value);
}
if (src->classes)
{
dest->classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
g_array_append_vals (dest->classes, src->classes->data, src->classes->len);
}
dest->regions = _gtk_bitmask_copy (src->regions);
dest->classes = _gtk_bitmask_copy (src->classes);
}
/**
@@ -235,11 +220,8 @@ gtk_widget_path_unref (GtkWidgetPath *path)
elem = &g_array_index (path->elems, GtkPathElement, i);
if (elem->regions)
g_hash_table_destroy (elem->regions);
if (elem->classes)
g_array_free (elem->classes, TRUE);
_gtk_bitmask_free (elem->regions);
_gtk_bitmask_free (elem->classes);
if (elem->siblings)
gtk_widget_path_unref (elem->siblings);
@@ -304,7 +286,8 @@ char *
gtk_widget_path_to_string (const GtkWidgetPath *path)
{
GString *string;
guint i, j;
guint i, j, k;
guint pos;
g_return_val_if_fail (path != NULL, NULL);
@@ -336,22 +319,23 @@ gtk_widget_path_to_string (const GtkWidgetPath *path)
if (elem->classes)
{
for (j = 0; j < elem->classes->len; j++)
{
pos = 0;
while (_gtk_bitmask_find_next_set (elem->classes, &pos))
{
g_string_append_c (string, '.');
g_string_append (string, g_quark_to_string (g_array_index (elem->classes, GQuark, j)));
}
g_string_append (string,
_gtk_style_class_get_name_from_mask (pos));
pos++;
}
}
if (elem->regions)
{
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, elem->regions);
while (g_hash_table_iter_next (&iter, &key, &value))
{
GtkRegionFlags flags = GPOINTER_TO_UINT (value);
k = 0;
while (_gtk_bitmask_find_next_set (elem->regions, &k))
{
guint region = k / GTK_REGION_FLAGS_NUM_BITS;
guint flags;
static const char *flag_names[] = {
"even",
"odd",
@@ -361,8 +345,12 @@ gtk_widget_path_to_string (const GtkWidgetPath *path)
"sorted"
};
k = region * GTK_REGION_FLAGS_NUM_BITS;
flags = _gtk_bitmask_get_uint (elem->regions, k);
g_string_append_c (string, ' ');
g_string_append (string, g_quark_to_string (GPOINTER_TO_UINT (key)));
g_string_append (string, _gtk_style_region_get_name_from_mask (region));
for (j = 0; j < G_N_ELEMENTS(flag_names); j++)
{
if (flags & (1 << j))
@@ -371,7 +359,9 @@ gtk_widget_path_to_string (const GtkWidgetPath *path)
g_string_append (string, flag_names[j]);
}
}
}
k += GTK_REGION_FLAGS_NUM_BITS;
}
}
}
@@ -715,9 +705,6 @@ gtk_widget_path_iter_add_class (GtkWidgetPath *path,
const gchar *name)
{
GtkPathElement *elem;
gboolean added = FALSE;
GQuark qname;
guint i;
g_return_if_fail (path != NULL);
g_return_if_fail (path->elems->len != 0);
@@ -727,33 +714,26 @@ gtk_widget_path_iter_add_class (GtkWidgetPath *path,
pos = path->elems->len - 1;
elem = &g_array_index (path->elems, GtkPathElement, pos);
qname = g_quark_from_string (name);
if (!elem->classes)
elem->classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
_gtk_bitmask_set (&elem->classes, _gtk_style_class_get_mask (name), TRUE);
}
for (i = 0; i < elem->classes->len; i++)
{
GQuark quark;
void
_gtk_widget_path_iter_add_classes (GtkWidgetPath *path,
gint pos,
GtkBitmask *classes)
{
GtkPathElement *elem;
quark = g_array_index (elem->classes, GQuark, i);
g_return_if_fail (path != NULL);
g_return_if_fail (path->elems->len != 0);
if (qname == quark)
{
/* Already there */
added = TRUE;
break;
}
if (qname < quark)
{
g_array_insert_val (elem->classes, i, qname);
added = TRUE;
break;
}
}
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;
if (!added)
g_array_append_val (elem->classes, qname);
elem = &g_array_index (path->elems, GtkPathElement, pos);
_gtk_bitmask_union (&elem->classes, classes);
}
/**
@@ -773,8 +753,6 @@ gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
const gchar *name)
{
GtkPathElement *elem;
GQuark qname;
guint i;
g_return_if_fail (path != NULL);
g_return_if_fail (path->elems->len != 0);
@@ -783,30 +761,9 @@ gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;
qname = g_quark_try_string (name);
if (qname == 0)
return;
elem = &g_array_index (path->elems, GtkPathElement, pos);
if (!elem->classes)
return;
for (i = 0; i < elem->classes->len; i++)
{
GQuark quark;
quark = g_array_index (elem->classes, GQuark, i);
if (quark > qname)
break;
else if (quark == qname)
{
g_array_remove_index (elem->classes, i);
break;
}
}
_gtk_bitmask_set (&elem->classes, _gtk_style_class_get_mask (name), FALSE);
}
/**
@@ -836,8 +793,7 @@ gtk_widget_path_iter_clear_classes (GtkWidgetPath *path,
if (!elem->classes)
return;
if (elem->classes->len > 0)
g_array_remove_range (elem->classes, 0, elem->classes->len);
_gtk_bitmask_clear (&elem->classes);
}
/**
@@ -874,12 +830,11 @@ gtk_widget_path_iter_list_classes (const GtkWidgetPath *path,
if (!elem->classes)
return NULL;
for (i = 0; i < elem->classes->len; i++)
i = 0;
while (_gtk_bitmask_find_next_set (elem->classes, &i))
{
GQuark quark;
quark = g_array_index (elem->classes, GQuark, i);
list = g_slist_prepend (list, (gchar *) g_quark_to_string (quark));
list = g_slist_prepend (list, (gchar *) _gtk_style_class_get_name_from_mask (i));
i++;
}
return g_slist_reverse (list);
@@ -903,34 +858,8 @@ gtk_widget_path_iter_has_qclass (const GtkWidgetPath *path,
gint pos,
GQuark qname)
{
GtkPathElement *elem;
guint i;
g_return_val_if_fail (path != NULL, FALSE);
g_return_val_if_fail (path->elems->len != 0, FALSE);
g_return_val_if_fail (qname != 0, FALSE);
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;
elem = &g_array_index (path->elems, GtkPathElement, pos);
if (!elem->classes)
return FALSE;
for (i = 0; i < elem->classes->len; i++)
{
GQuark quark;
quark = g_array_index (elem->classes, GQuark, i);
if (quark == qname)
return TRUE;
else if (quark > qname)
break;
}
return FALSE;
return gtk_widget_path_iter_has_class (path, pos,
g_quark_to_string (qname));
}
/**
@@ -951,7 +880,8 @@ gtk_widget_path_iter_has_class (const GtkWidgetPath *path,
gint pos,
const gchar *name)
{
GQuark qname;
GtkPathElement *elem;
guint mask;
g_return_val_if_fail (path != NULL, FALSE);
g_return_val_if_fail (path->elems->len != 0, FALSE);
@@ -960,12 +890,14 @@ gtk_widget_path_iter_has_class (const GtkWidgetPath *path,
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;
qname = g_quark_try_string (name);
elem = &g_array_index (path->elems, GtkPathElement, pos);
if (qname == 0)
if (!elem->classes)
return FALSE;
return gtk_widget_path_iter_has_qclass (path, pos, qname);
mask = _gtk_style_class_get_mask (name);
return _gtk_bitmask_get (elem->classes, mask);
}
/**
@@ -991,7 +923,9 @@ gtk_widget_path_iter_add_region (GtkWidgetPath *path,
GtkRegionFlags flags)
{
GtkPathElement *elem;
GQuark qname;
guint region;
guint i;
guint old_flags;
g_return_if_fail (path != NULL);
g_return_if_fail (path->elems->len != 0);
@@ -1002,14 +936,33 @@ gtk_widget_path_iter_add_region (GtkWidgetPath *path,
pos = path->elems->len - 1;
elem = &g_array_index (path->elems, GtkPathElement, pos);
qname = g_quark_from_string (name);
if (!elem->regions)
elem->regions = g_hash_table_new (NULL, NULL);
region = _gtk_style_region_get_mask (name);
i = region * GTK_REGION_FLAGS_NUM_BITS;
g_hash_table_insert (elem->regions,
GUINT_TO_POINTER (qname),
GUINT_TO_POINTER (flags));
old_flags = _gtk_bitmask_get_uint (elem->regions, i);
old_flags &= ~(GTK_REGION_FLAGS_MASK | GTK_REGION_ADDED);
/* Ensure *some* flag is always set so we know this is added */
old_flags |= flags | GTK_REGION_ADDED;
_gtk_bitmask_set_uint (&elem->regions, i, old_flags);
}
void
_gtk_widget_path_iter_add_regions (GtkWidgetPath *path,
gint pos,
GtkBitmask *regions)
{
GtkPathElement *elem;
g_return_if_fail (path != NULL);
g_return_if_fail (path->elems->len != 0);
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;
elem = &g_array_index (path->elems, GtkPathElement, pos);
_gtk_bitmask_union (&elem->regions, regions);
}
/**
@@ -1029,7 +982,9 @@ gtk_widget_path_iter_remove_region (GtkWidgetPath *path,
const gchar *name)
{
GtkPathElement *elem;
GQuark qname;
guint region;
guint i;
guint old_flags;
g_return_if_fail (path != NULL);
g_return_if_fail (path->elems->len != 0);
@@ -1038,15 +993,17 @@ gtk_widget_path_iter_remove_region (GtkWidgetPath *path,
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;
qname = g_quark_try_string (name);
if (qname == 0)
return;
elem = &g_array_index (path->elems, GtkPathElement, pos);
if (elem->regions)
g_hash_table_remove (elem->regions, GUINT_TO_POINTER (qname));
if (elem->regions == NULL)
return;
region = _gtk_style_region_get_mask (name);
i = region * GTK_REGION_FLAGS_NUM_BITS;
old_flags = _gtk_bitmask_get_uint (elem->regions, i);
old_flags &= ~(GTK_REGION_FLAGS_MASK | GTK_REGION_ADDED);
_gtk_bitmask_set_uint (&elem->regions, i, old_flags);
}
/**
@@ -1074,7 +1031,7 @@ gtk_widget_path_iter_clear_regions (GtkWidgetPath *path,
elem = &g_array_index (path->elems, GtkPathElement, pos);
if (elem->regions)
g_hash_table_remove_all (elem->regions);
_gtk_bitmask_clear (&elem->regions);
}
/**
@@ -1097,9 +1054,8 @@ gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
gint pos)
{
GtkPathElement *elem;
GHashTableIter iter;
GSList *list = NULL;
gpointer key;
guint i;
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (path->elems->len != 0, NULL);
@@ -1112,14 +1068,16 @@ gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
if (!elem->regions)
return NULL;
g_hash_table_iter_init (&iter, elem->regions);
while (g_hash_table_iter_next (&iter, &key, NULL))
i = 0;
while (_gtk_bitmask_find_next_set (elem->regions, &i))
{
GQuark qname;
guint region = i / GTK_REGION_FLAGS_NUM_BITS;
i = region * GTK_REGION_FLAGS_NUM_BITS;
qname = GPOINTER_TO_UINT (key);
list = g_slist_prepend (list, (gchar *) g_quark_to_string (qname));
list = g_slist_prepend (list,
(gchar *) _gtk_style_region_get_name_from_mask (region));
i += GTK_REGION_FLAGS_NUM_BITS;
}
return list;
@@ -1145,30 +1103,8 @@ gtk_widget_path_iter_has_qregion (const GtkWidgetPath *path,
GQuark qname,
GtkRegionFlags *flags)
{
GtkPathElement *elem;
gpointer value;
g_return_val_if_fail (path != NULL, FALSE);
g_return_val_if_fail (path->elems->len != 0, FALSE);
g_return_val_if_fail (qname != 0, FALSE);
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;
elem = &g_array_index (path->elems, GtkPathElement, pos);
if (!elem->regions)
return FALSE;
if (!g_hash_table_lookup_extended (elem->regions,
GUINT_TO_POINTER (qname),
NULL, &value))
return FALSE;
if (flags)
*flags = GPOINTER_TO_UINT (value);
return TRUE;
return gtk_widget_path_iter_has_region (path, pos,
g_quark_to_string (qname), flags);
}
/**
@@ -1189,9 +1125,11 @@ gboolean
gtk_widget_path_iter_has_region (const GtkWidgetPath *path,
gint pos,
const gchar *name,
GtkRegionFlags *flags)
GtkRegionFlags *flags_return)
{
GQuark qname;
GtkPathElement *elem;
guint region;
guint i, flags;
g_return_val_if_fail (path != NULL, FALSE);
g_return_val_if_fail (path->elems->len != 0, FALSE);
@@ -1200,12 +1138,23 @@ gtk_widget_path_iter_has_region (const GtkWidgetPath *path,
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;
qname = g_quark_try_string (name);
elem = &g_array_index (path->elems, GtkPathElement, pos);
if (qname == 0)
if (!elem->regions)
return FALSE;
return gtk_widget_path_iter_has_qregion (path, pos, qname, flags);
region = _gtk_style_region_get_mask (name);
i = region * GTK_REGION_FLAGS_NUM_BITS;
flags = _gtk_bitmask_get_uint (elem->regions, i);
if ((flags & GTK_REGION_ADDED) != 0)
{
if (flags_return)
*flags_return = flags & GTK_REGION_FLAGS_MASK;
return TRUE;
}
return FALSE;
}
/**

View File

@@ -48,9 +48,9 @@ gtk_bitmask_new_parse (const char *string)
for (i = 0; i < length; i++)
{
if (string[i] == '0')
_gtk_bitmask_set (mask, length - i - 1, FALSE);
_gtk_bitmask_set (&mask, length - i - 1, FALSE);
else if (string[i] == '1')
_gtk_bitmask_set (mask, length - i - 1, TRUE);
_gtk_bitmask_set (&mask, length - i - 1, TRUE);
else
g_assert_not_reached ();
}
@@ -142,12 +142,12 @@ test_set (void)
for (j = 0; j < N_TRIES; j++)
{
indexes[j] = g_test_rand_int_range (0, MAX_INDEX);
_gtk_bitmask_set (copy, indexes[j], g_test_rand_bit ());
_gtk_bitmask_set (&copy, indexes[j], g_test_rand_bit ());
}
for (j = 0; j < N_TRIES; j++)
{
_gtk_bitmask_set (copy, indexes[j], _gtk_bitmask_get (mask, indexes[j]));
_gtk_bitmask_set (&copy, indexes[j], _gtk_bitmask_get (mask, indexes[j]));
}
assert_cmpmasks (copy, mask);
@@ -155,6 +155,61 @@ test_set (void)
}
}
static void
test_set_uint (void)
{
guint i, j, k;
guint index;
GtkBitmask *copy;
GtkBitmask *mask;
guint val;
for (i = 0; i < N_RUNS; i++)
{
mask = _gtk_bitmask_copy (masks[g_test_rand_int_range (0, G_N_ELEMENTS (tests))]);
val = g_test_rand_int ();
copy = _gtk_bitmask_copy (mask);
for (j = 0; j < N_TRIES; j++)
{
index = g_test_rand_int_range (0, MAX_INDEX);
_gtk_bitmask_set_uint (&copy, index, val);
for (k = 0; k < sizeof (guint) * 8; k++)
_gtk_bitmask_set (&mask, index + k, val & (1<<k));
assert_cmpmasks (copy, mask);
}
_gtk_bitmask_free (copy);
}
}
static void
test_get_uint (void)
{
guint i, j, k;
guint index;
GtkBitmask *mask;
guint val;
for (i = 0; i < N_RUNS; i++)
{
mask = masks[g_test_rand_int_range (0, G_N_ELEMENTS (tests))];
for (j = 0; j < N_TRIES; j++)
{
index = g_test_rand_int_range (0, 100);
val = _gtk_bitmask_get_uint (mask, index);
for (k = 0; k < sizeof (guint) * 8; k++)
g_assert_cmpint (!!_gtk_bitmask_get (mask, index + k), ==, !!(val & (1<<k)));
}
}
}
static void
test_union (void)
{
@@ -173,15 +228,15 @@ test_union (void)
guint id = g_test_rand_int_range (0, MAX_INDEX);
if (g_test_rand_bit ())
_gtk_bitmask_set (left, id, TRUE);
_gtk_bitmask_set (&left, id, TRUE);
else
_gtk_bitmask_set (right, id, TRUE);
_gtk_bitmask_set (&right, id, TRUE);
_gtk_bitmask_set (expected, id, TRUE);
_gtk_bitmask_set (&expected, id, TRUE);
}
_gtk_bitmask_union (left, right);
_gtk_bitmask_union (right, left);
_gtk_bitmask_union (&left, right);
_gtk_bitmask_union (&right, left);
assert_cmpmasks (left, expected);
assert_cmpmasks (right, expected);
@@ -211,13 +266,13 @@ test_intersect (void)
if (g_test_rand_bit ())
{
_gtk_bitmask_set (left, id, set);
_gtk_bitmask_set (expected, id, set ? _gtk_bitmask_get (right, id) : 0);
_gtk_bitmask_set (&left, id, set);
_gtk_bitmask_set (&expected, id, set ? _gtk_bitmask_get (right, id) : 0);
}
else
{
_gtk_bitmask_set (right, id, set);
_gtk_bitmask_set (expected, id, set ? _gtk_bitmask_get (left, id) : 0);
_gtk_bitmask_set (&right, id, set);
_gtk_bitmask_set (&expected, id, set ? _gtk_bitmask_get (left, id) : 0);
}
}
@@ -225,8 +280,8 @@ test_intersect (void)
g_assert_cmpint (intersects, ==, _gtk_bitmask_intersects (right, left));
g_assert_cmpint (intersects, !=, _gtk_bitmask_is_empty (expected));
_gtk_bitmask_intersect (left, right);
_gtk_bitmask_intersect (right, left);
_gtk_bitmask_intersect (&left, right);
_gtk_bitmask_intersect (&right, left);
assert_cmpmasks (left, expected);
assert_cmpmasks (right, expected);
@@ -267,19 +322,19 @@ test_invert_range (void)
end = MIN (left_end, right_end);
if (left_start != left_end)
_gtk_bitmask_invert_range (left, left_start, left_end);
_gtk_bitmask_invert_range (&left, left_start, left_end);
if (right_start != right_end)
_gtk_bitmask_invert_range (right, right_start, right_end);
_gtk_bitmask_invert_range (&right, right_start, right_end);
if (start < end)
_gtk_bitmask_invert_range (expected, start, end);
_gtk_bitmask_invert_range (&expected, start, end);
intersection = _gtk_bitmask_copy (left);
_gtk_bitmask_intersect (intersection, right);
_gtk_bitmask_intersect (&intersection, right);
assert_cmpmasks (intersection, expected);
if (start < end)
_gtk_bitmask_invert_range (expected, start, end);
_gtk_bitmask_invert_range (&expected, start, end);
g_assert_cmpint (_gtk_bitmask_is_empty (expected), ==, TRUE);
@@ -328,6 +383,8 @@ main (int argc, char *argv[])
g_test_add_func ("/bitmask/is_empty", test_is_empty);
g_test_add_func ("/bitmask/equals", test_equals);
g_test_add_func ("/bitmask/set", test_set);
g_test_add_func ("/bitmask/set_uint", test_set_uint);
g_test_add_func ("/bitmask/get_uint", test_get_uint);
g_test_add_func ("/bitmask/union", test_union);
g_test_add_func ("/bitmask/intersect", test_intersect);
g_test_add_func ("/bitmask/invert_range", test_invert_range);