/* Canonical units that can be used before compute time * *OurcompatibilityisabitstricterthanCSS,sincewe *haveadpiproperty,soPXandthedpi-dependentunits *can'tbeunifiedbeforecomputetime.
*/ static GtkCssUnit
canonical_unit (GtkCssUnit unit)
{ switch (unit)
{ case GTK_CSS_NUMBER: return GTK_CSS_NUMBER; case GTK_CSS_PERCENT: return GTK_CSS_PERCENT; case GTK_CSS_PX: return GTK_CSS_PX; case GTK_CSS_EM: return GTK_CSS_EM; case GTK_CSS_EX: return GTK_CSS_EM; case GTK_CSS_REM: return GTK_CSS_REM; case GTK_CSS_PT: return GTK_CSS_MM; case GTK_CSS_PC: return GTK_CSS_MM; case GTK_CSS_IN: return GTK_CSS_MM; case GTK_CSS_CM: return GTK_CSS_MM; case GTK_CSS_MM: return GTK_CSS_MM; case GTK_CSS_RAD: return GTK_CSS_DEG; case GTK_CSS_DEG: return GTK_CSS_DEG; case GTK_CSS_GRAD: return GTK_CSS_DEG; case GTK_CSS_TURN: return GTK_CSS_DEG; case GTK_CSS_S: return GTK_CSS_S; case GTK_CSS_MS: return GTK_CSS_S; default: g_assert_not_reached ();
}
}
/* Units are compatible if they have the same compute time *dependency.Thisstillallowssomeoperationstoapplied *early.
*/ static gboolean
units_compatible (GtkCssValue *v1,
GtkCssValue *v2)
{ if ((v1 && v1->type != TYPE_DIMENSION) || (v2 && v2->type != TYPE_DIMENSION)) returnFALSE;
if (v1 && v2) return canonical_unit (v1->dimension.unit) == canonical_unit (v2->dimension.unit);
returnTRUE;
}
/* Assumes that value is a dimension value and *unitiscanonicalandcompatibleitsunit.
*/ staticdouble
get_converted_value (GtkCssValue *value,
GtkCssUnit unit)
{ double v;
if (value->type != TYPE_DIMENSION) return NAN;
v = gtk_css_number_value_get (value, 100);
if (unit == value->dimension.unit)
{ return v;
} elseif (unit == GTK_CSS_MM)
{ switch ((int) value->dimension.unit)
{ case GTK_CSS_PT: return v * 0.35277778; case GTK_CSS_PC: return v * 4.2333333; case GTK_CSS_IN: return v * 25.4; case GTK_CSS_CM: return v * 10; default: return NAN;
}
} elseif (unit == GTK_CSS_EM)
{ switch ((int) value->dimension.unit)
{ case GTK_CSS_EX: return v * 0.5; default: return NAN;
}
} elseif (unit == GTK_CSS_DEG)
{ switch ((int) value->dimension.unit)
{ case GTK_CSS_RAD: return v * 180.0 / G_PI; case GTK_CSS_GRAD: return v * 360.0 / 400.0; case GTK_CSS_TURN: return v * 360.0; default: return NAN;
}
} elseif (unit == GTK_CSS_S)
{ switch ((int) value->dimension.unit)
{ case GTK_CSS_MS: return v / 1000.0; default: return NAN;
}
} else
{ return NAN;
}
}
if (changed)
{
result = gtk_css_math_value_new (number->type, number->calc.mode, new_values, n_terms);
} else
{ for (gsize i = 0; i < n_terms; i++)
gtk_css_value_unref (new_values[i]);
switch ((guint)unit)
{ case GTK_CSS_NUMBER: if (value == 0 || value == 1) return gtk_css_value_ref (&number_singletons[(int) value]);
if (value == 96) return gtk_css_value_ref (&number_singletons[2]);
break;
case GTK_CSS_PX: if (value == 0 || value == 1 || value == 2 || value == 3 ||
value == 4 || value == 5 || value == 6 || value == 7 ||
value == 8) return gtk_css_value_ref (&px_singletons[(int) value]); if (value == 16) return gtk_css_value_ref (&px_singletons[9]); if (value == 32) return gtk_css_value_ref (&px_singletons[10]); if (value == 64) return gtk_css_value_ref (&px_singletons[11]);
break;
case GTK_CSS_PERCENT: if (value == 0) return gtk_css_value_ref (&percent_singletons[0]); if (value == 50) return gtk_css_value_ref (&percent_singletons[1]); if (value == 100) return gtk_css_value_ref (&percent_singletons[2]);
break;
case GTK_CSS_S: if (value == 0 || value == 1) return gtk_css_value_ref (&second_singletons[(int)value]);
break;
case GTK_CSS_DEG: if (value == 0) return gtk_css_value_ref (°_singletons[0]); if (value == 90) return gtk_css_value_ref (°_singletons[1]); if (value == 180) return gtk_css_value_ref (°_singletons[2]); if (value == 270) return gtk_css_value_ref (°_singletons[3]);
break;
default:
;
}
result = gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_NUMBER);
result->type = TYPE_DIMENSION;
result->dimension.unit = unit;
result->dimension.value = value;
result->is_computed = value == 0 ||
unit == GTK_CSS_NUMBER ||
unit == GTK_CSS_PX ||
unit == GTK_CSS_DEG ||
unit == GTK_CSS_S; return result;
}
case TYPE_CALC: case TYPE_MIN: case TYPE_MAX: case TYPE_HYPOT: case TYPE_ABS: case TYPE_ROUND: case TYPE_MOD: case TYPE_REM: case TYPE_CLAMP:
{
GtkCssDimension dimension = GTK_CSS_DIMENSION_PERCENTAGE;
for (guint i = 0; i < value->calc.n_terms && dimension == GTK_CSS_DIMENSION_PERCENTAGE; i++)
{
dimension = gtk_css_number_value_get_dimension (value->calc.terms[i]); if (dimension != GTK_CSS_DIMENSION_PERCENTAGE) break;
} return dimension;
}
case TYPE_PRODUCT: if (gtk_css_number_value_get_dimension (value->calc.terms[0]) != GTK_CSS_DIMENSION_NUMBER) return gtk_css_number_value_get_dimension (value->calc.terms[0]); else return gtk_css_number_value_get_dimension (value->calc.terms[1]);
case TYPE_SIGN: case TYPE_SIN: case TYPE_COS: case TYPE_TAN: case TYPE_EXP: case TYPE_SQRT: case TYPE_POW: case TYPE_LOG: case TYPE_COLOR_COORD: return GTK_CSS_DIMENSION_NUMBER;
case TYPE_ASIN: case TYPE_ACOS: case TYPE_ATAN: case TYPE_ATAN2: return GTK_CSS_DIMENSION_ANGLE;
default:
g_assert_not_reached ();
}
}
gboolean
gtk_css_number_value_has_percent (const GtkCssValue *value)
{ if (value->type == TYPE_COLOR_COORD)
{ returnFALSE;
} elseif (value->type == TYPE_DIMENSION)
{ return gtk_css_unit_get_dimension (value->dimension.unit) == GTK_CSS_DIMENSION_PERCENTAGE;
} else
{ for (guint i = 0; i < value->calc.n_terms; i++)
{ if (gtk_css_number_value_has_percent (value->calc.terms[i])) returnTRUE;
}
if (min)
min = gtk_css_number_value_multiply (min, factor);
center = gtk_css_number_value_multiply (center, factor); if (max)
max = gtk_css_number_value_multiply (max, factor);
if (factor < 0)
{
GtkCssValue *tmp = min;
min = max;
max = tmp;
}
return gtk_css_clamp_value_new (min, center, max);
}
if (value_is_compute_time (value)) return gtk_css_calc_value_new (type, 0, &value, 1);
a = get_converted_value (value, canonical_unit (value->dimension.unit));
if (type == TYPE_SIN || type == TYPE_COS || type == TYPE_TAN)
{ if (gtk_css_unit_get_dimension (value->dimension.unit) == GTK_CSS_DIMENSION_ANGLE)
a = DEG_TO_RAD (a);
}
switch (type)
{ case TYPE_SIN: v = sin (a); break; case TYPE_COS: v = cos (a); break; case TYPE_TAN: v = tan (a); break; case TYPE_ASIN: v = asin (a); break; case TYPE_ACOS: v = acos (a); break; case TYPE_ATAN: v = atan (a); break; case TYPE_SQRT: v = sqrt (a); break; case TYPE_EXP: v = exp (a); break; case TYPE_ABS: v = fabs (a); break; case TYPE_SIGN: v = _sign (a); break; default: g_assert_not_reached ();
}
if (type == TYPE_ASIN || type == TYPE_ACOS || type == TYPE_ATAN)
{
unit = GTK_CSS_DEG;
v = RAD_TO_DEG (v);
} elseif (type == TYPE_ABS)
{
unit = value->dimension.unit;
} else
{
unit = GTK_CSS_NUMBER;
}
a = get_converted_value (value1, canonical_unit (value1->dimension.unit)); if (value2)
b = get_converted_value (value2, canonical_unit (value2->dimension.unit));
switch (type)
{ case TYPE_MOD: v = _mod (a, b); break; case TYPE_REM: v = _rem (a, b); break; case TYPE_ATAN2: v = atan2 (a, b); break; case TYPE_POW: v = pow (a, b); break; case TYPE_LOG: v = value2 ? log (a) / log (b) : log (a); break; default: g_assert_not_reached ();
}
if (type == TYPE_ATAN2)
{
unit = GTK_CSS_DEG;
v = RAD_TO_DEG (v);
} else
{
unit = GTK_CSS_NUMBER;
}
/* This function is called at parsing time, so units are not *canonical,andlengthvaluescan'tnecessarilybeunified.
*/
GtkCssValue *
gtk_css_math_value_new (guint type,
guint mode,
GtkCssValue **values,
guint n_values)
{ switch ((NumberValueType) type)
{ case TYPE_DIMENSION: case TYPE_COLOR_COORD:
g_assert_not_reached ();
case TYPE_ROUND: return gtk_css_round_value_new (mode, values[0], values[1]);
case TYPE_CLAMP: return gtk_css_clamp_value_new (values[0], values[1], values[2]);
case TYPE_HYPOT: return gtk_css_hypot_value_new (values, n_values);
case TYPE_MIN: case TYPE_MAX: return gtk_css_minmax_value_new (type, values, n_values);
case TYPE_SIN: case TYPE_COS: case TYPE_TAN: case TYPE_ASIN: case TYPE_ACOS: case TYPE_ATAN: case TYPE_SQRT: case TYPE_EXP: case TYPE_ABS: case TYPE_SIGN: return gtk_css_arg1_value_new (type, values[0]);
case TYPE_MOD: case TYPE_REM: case TYPE_ATAN2: case TYPE_POW: case TYPE_LOG: return gtk_css_arg2_value_new (type, values[0], values[1]);
case TYPE_PRODUCT: case TYPE_CALC: default: return gtk_css_calc_value_new (type, mode, values, n_values);
}
}
switch ((int) token->type)
{ case GTK_CSS_TOKEN_SIGNED_NUMBER: case GTK_CSS_TOKEN_SIGNLESS_NUMBER: case GTK_CSS_TOKEN_SIGNED_INTEGER: case GTK_CSS_TOKEN_SIGNLESS_INTEGER: case GTK_CSS_TOKEN_PERCENTAGE: case GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION: case GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION: case GTK_CSS_TOKEN_SIGNED_DIMENSION: case GTK_CSS_TOKEN_SIGNLESS_DIMENSION: returnTRUE;
case GTK_CSS_TOKEN_FUNCTION:
{ constchar *name = gtk_css_token_get_string (token);
for (guint i = 0; i < G_N_ELEMENTS (function_name); i++)
{ if (g_ascii_strcasecmp (function_name[i], name) == 0) returnTRUE;
}
} break;
/* This function is safe to call on computed values, since all *unitsarecanonicalandalllengthsareinpxatthattime.
*/ double
gtk_css_number_value_get (const GtkCssValue *value, double one_hundred_percent)
{
guint type = value->type;
guint mode = value->calc.mode;
GtkCssValue * const *terms = value->calc.terms;
guint n_terms = value->calc.n_terms;
switch ((NumberValueType) type)
{ case TYPE_DIMENSION: if (value->dimension.unit == GTK_CSS_PERCENT) return value->dimension.value * one_hundred_percent / 100; else return value->dimension.value;
case TYPE_CALC:
{ double result = 0.0;
for (guint i = 0; i < n_terms; i++)
result += gtk_css_number_value_get (terms[i], one_hundred_percent);
return result;
}
case TYPE_PRODUCT:
{ double result = 1.0;
for (guint i = 0; i < n_terms; i++)
result *= gtk_css_number_value_get (terms[i], one_hundred_percent);
return result;
}
case TYPE_MIN:
{ double result = G_MAXDOUBLE;
for (guint i = 0; i < n_terms; i++)
result = MIN (result, gtk_css_number_value_get (terms[i], one_hundred_percent));
return result;
}
case TYPE_MAX:
{ double result = -G_MAXDOUBLE;
for (guint i = 0; i < n_terms; i++)
result = MAX (result, gtk_css_number_value_get (terms[i], one_hundred_percent));
result = gtk_css_number_value_get (center, one_hundred_percent);
if (max)
result = MIN (result, gtk_css_number_value_get (max, one_hundred_percent)); if (min)
result = MAX (result, gtk_css_number_value_get (min, one_hundred_percent));
return result;
}
case TYPE_ROUND:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
case TYPE_MOD:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent); double b = gtk_css_number_value_get (terms[1], one_hundred_percent);
return _mod (a, b);
}
case TYPE_REM:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent); double b = gtk_css_number_value_get (terms[1], one_hundred_percent);
return _rem (a, b);
}
case TYPE_ABS:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
return fabs (a);
}
case TYPE_SIGN:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
return _sign (a);
}
case TYPE_SIN:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
if (gtk_css_number_value_get_dimension (value) == GTK_CSS_DIMENSION_ANGLE)
a = DEG_TO_RAD (a);
return sin (a);
}
case TYPE_COS:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
if (gtk_css_number_value_get_dimension (value) == GTK_CSS_DIMENSION_ANGLE)
a = DEG_TO_RAD (a);
return cos (a);
}
case TYPE_TAN:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
if (gtk_css_number_value_get_dimension (value) == GTK_CSS_DIMENSION_ANGLE)
a = DEG_TO_RAD (a);
return tan (a);
}
case TYPE_ASIN:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
return RAD_TO_DEG (asin (a));
}
case TYPE_ACOS:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
return RAD_TO_DEG (acos (a));
}
case TYPE_ATAN:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
return RAD_TO_DEG (atan (a));
}
case TYPE_ATAN2:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent); double b = gtk_css_number_value_get (terms[1], one_hundred_percent);
return RAD_TO_DEG (atan2 (a, b));
}
case TYPE_POW:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent); double b = gtk_css_number_value_get (terms[1], one_hundred_percent);
return pow (a, b);
}
case TYPE_SQRT:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
return sqrt (a);
}
case TYPE_EXP:
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent);
return exp (a);
}
case TYPE_LOG: if (n_terms > 1)
{ double a = gtk_css_number_value_get (terms[0], one_hundred_percent); double b = gtk_css_number_value_get (terms[1], one_hundred_percent);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.