On 13-12-01 01:26 PM, Lex Trotman wrote:
Hi,

**gint** utils_strtod()??  Sheesh.

s/b renamed utils_hexcolor() or similar, thats what it does.

As for "end", the original strtod() and friends used it to extract several
whitespace separated strings from the one string by just passing "end" to
the next call, but if we don't use it and its wrong anyways we might as
well drop it when we change the name to utils_hexcolor().


Agree the name is bad, and also the colour parsing isn't very robust. I meant to improve it when adding the named_colors support but never got around to it.

Attached patch uses GDK colour parsing instead of own-rolled thing which supports more colour specification formats as well as cleans up some related code while remaining compatible with legacy colour notation and GTK2 and GTK3 builds.

If nobody objects, I can commit the patch.

Cheers,
Matthew Brush

diff --git a/src/highlighting.c b/src/highlighting.c
index de7cd43..1b70f7a 100644
--- a/src/highlighting.c
+++ b/src/highlighting.c
@@ -213,15 +213,14 @@ static gboolean read_named_style(const gchar *named_style, GeanyLexerStyle *styl
 
 
 /* Parses a color in `str` which can be an HTML color (ex. #0099cc),
- * an abbreviated HTML color (ex. #09c) or a hex string color
- * (ex. 0x0099cc). The result of the conversion is stored into the
- * location pointed to by `clr`. */
+ * an abbreviated HTML color (ex. #09c), a hex string color (ex. 0x0099cc)
+ * or CSS-style format (ex. rgb(1,2,3) or rgba(1,2,3,0.4)). If the colour
+ * refers to one of the keys in the "named_colors" section, the colour
+ * specified by the named colour will be parsed. The result of the conversion
+ * is stored into the location pointed to by `clr`. */
 static void parse_color(GKeyFile *kf, const gchar *str, gint *clr)
 {
-	gint c;
-	gchar hex_clr[9] = { 0 };
 	gchar *named_color = NULL;
-	const gchar *start;
 
 	g_return_if_fail(clr != NULL);
 
@@ -230,37 +229,12 @@ static void parse_color(GKeyFile *kf, const gchar *str, gint *clr)
 
 	named_color = g_key_file_get_string(kf, "named_colors", str, NULL);
 	if  (named_color)
-		str = named_color;
-
-	if (str[0] == '#')
-		start = str + 1;
-	else if (strlen(str) > 1 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
-		start = str + 2;
-	else
 	{
-		geany_debug("Bad color '%s'", str);
+		*clr = utils_parse_color(named_color, NULL);
 		g_free(named_color);
-		return;
-	}
-
-	if (strlen(start) == 3)
-	{
-		g_snprintf(hex_clr, 9, "0x%c%c%c%c%c%c", start[0], start[0],
-			start[1], start[1], start[2], start[2]);
 	}
 	else
-		g_snprintf(hex_clr, 9, "0x%s", start);
-
-	g_free(named_color);
-
-	c = utils_strtod(hex_clr, NULL, FALSE);
-
-	if (c > -1)
-	{
-		*clr = c;
-		return;
-	}
-	geany_debug("Bad color '%s'", str);
+		*clr = utils_parse_color(str, NULL);
 }
 
 
@@ -343,15 +317,6 @@ static void get_keyfile_style(GKeyFile *config, GKeyFile *configh,
 }
 
 
-/* Convert 0xRRGGBB to 0xBBGGRR, which scintilla expects. */
-static gint rotate_rgb(gint color)
-{
-	return ((color & 0xFF0000) >> 16) +
-		(color & 0x00FF00) +
-		((color & 0x0000FF) << 16);
-}
-
-
 static void convert_int(const gchar *int_str, gint *val)
 {
 	gchar *end;
@@ -695,7 +660,7 @@ static void styleset_common(ScintillaObject *sci, guint ft_id)
 
 	/* Error indicator */
 	SSM(sci, SCI_INDICSETSTYLE, GEANY_INDICATOR_ERROR, INDIC_SQUIGGLEPIXMAP);
-	SSM(sci, SCI_INDICSETFORE, GEANY_INDICATOR_ERROR, invert(rotate_rgb(0xff0000)));
+	SSM(sci, SCI_INDICSETFORE, GEANY_INDICATOR_ERROR, invert(utils_parse_color("#f00", NULL)));
 
 	/* Search indicator, used for 'Mark' matches */
 	SSM(sci, SCI_INDICSETSTYLE, GEANY_INDICATOR_SEARCH, INDIC_ROUNDBOX);
diff --git a/src/sciwrappers.c b/src/sciwrappers.c
index 5baa8ed..b5cb744 100644
--- a/src/sciwrappers.c
+++ b/src/sciwrappers.c
@@ -69,8 +69,6 @@ void sci_set_line_numbers(ScintillaObject *sci, gboolean set, gint extra_width)
 
 void sci_set_mark_long_lines(ScintillaObject *sci, gint type, gint column, const gchar *colour)
 {
-	glong colour_val = utils_strtod(colour, NULL, TRUE); /* Scintilla uses a "long" value */
-
 	if (column == 0)
 		type = 2;
 	switch (type)
@@ -92,7 +90,7 @@ void sci_set_mark_long_lines(ScintillaObject *sci, gint type, gint column, const
 		}
 	}
 	SSM(sci, SCI_SETEDGECOLUMN, (uptr_t) column, 0);
-	SSM(sci, SCI_SETEDGECOLOUR, (uptr_t) colour_val, 0);
+	SSM(sci, SCI_SETEDGECOLOUR, (uptr_t) utils_parse_color(colour, NULL), 0);
 }
 
 
diff --git a/src/utils.c b/src/utils.c
index 9cb7c7e..584d5ef 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -964,50 +964,74 @@ gchar *utils_make_human_readable_str(guint64 size, gulong block_size,
 }
 
 
- static guint utils_get_value_of_hex(const gchar ch)
-{
-	if (ch >= '0' && ch <= '9')
-		return ch - '0';
-	else if (ch >= 'A' && ch <= 'F')
-		return ch - 'A' + 10;
-	else if (ch >= 'a' && ch <= 'f')
-		return ch - 'a' + 10;
-	else
-		return 0;
-}
-
-
-/* utils_strtod() converts a string containing a hex colour ("0x00ff00") into an integer.
- * Basically, it is the same as strtod() would do, but it does not understand hex colour values,
- * before ANSI-C99. With with_route set, it takes strings of the format "#00ff00".
- * Returns -1 on failure. */
-gint utils_strtod(const gchar *source, gchar **end, gboolean with_route)
+/*
+ * Parses a colour specification string and returns a BGR packed integer
+ * compatible with Scintilla.
+ *
+ * The input string can either be in C-style hex notation like '0Xrrggbb',
+ * one of the colour names (from X11 rgb.txt file) or it can be in HTML-style
+ * hex notation like #rgb, #rrggbb, #rrrgggbbb, #rrrrggggbbbb.
+ *
+ * If using GTK+ > 3.0, the color string can also be in CSS-style rgb(r,g,b)
+ * or rgba(r,g,b,a) form. If an Alpha value is parsed, and @a alpha is not
+ * @c NULL, it is stored in the location pointed to by @a alpha.
+ *
+ * @param color_spec The colour specification string.
+ * @param alpha Location to store the Alpha value if one is parsed from the
+ * colour, otherwise 0. Pass @c NULL if you don't need the alpha value.
+ *
+ * @return An integer packed like 0xBBGGRR or -1 on failure.
+ */
+gint utils_parse_color(const gchar *color_spec, guint8 *alpha)
 {
-	guint red, green, blue, offset = 0;
+#define TEMP_COLOR_MAX 63
+	gsize len;
+	gint r, g, b;
+	gchar temp_color[TEMP_COLOR_MAX + 1] = { 0 };
 
-	g_return_val_if_fail(source != NULL, -1);
+	g_return_val_if_fail(color_spec != NULL, -1);
 
-	if (with_route && (strlen(source) != 7 || source[0] != '#'))
-		return -1;
-	else if (! with_route && (strlen(source) != 8 || source[0] != '0' ||
-		(source[1] != 'x' && source[1] != 'X')))
+	/* Convert 0x prefix to # prefix to support legacy colour notation */
+	len = strlen(color_spec);
+	if (len > 2 && color_spec[0] == '0' && (color_spec[1] == 'x' || color_spec[1] == 'X'))
 	{
-		return -1;
+		strncpy(temp_color + 1, color_spec + 2, MIN(TEMP_COLOR_MAX - 1, len - 1));
+		temp_color[0] = '#';
 	}
+	else
+		strncpy(temp_color, color_spec, TEMP_COLOR_MAX);
 
-	/* offset is set to 1 when the string starts with 0x, otherwise it starts with #
-	 * and we don't need to increase the index */
-	if (! with_route)
-		offset = 1;
-
-	red = utils_get_value_of_hex(
-					source[1 + offset]) * 16 + utils_get_value_of_hex(source[2 + offset]);
-	green = utils_get_value_of_hex(
-					source[3 + offset]) * 16 + utils_get_value_of_hex(source[4 + offset]);
-	blue = utils_get_value_of_hex(
-					source[5 + offset]) * 16 + utils_get_value_of_hex(source[6 + offset]);
+	/* Parse colour spec */
+#if GTK_CHECK_VERSION(3,0,0)
+	GdkRGBA color = { 0 };
+	if (gdk_rgba_parse(&color, temp_color))
+	{
+		r = (gint)(color.red * 255.0) & 0xFF;
+		g = (gint)(color.green * 255.0) & 0xFF;
+		b = (gint)(color.blue * 255.0) & 0xFF;
+		if (alpha != NULL)
+			*alpha = (guint8)(color.alpha * 255.0);
+	}
+#else
+	GdkColor color = { 0 };
+	if (gdk_color_parse(temp_color, &color))
+	{
+		r = (color.red / 256) & 0xFF;
+		g = (color.green / 256) & 0xFF;
+		b = (color.blue / 256) & 0xFF;
+		if (alpha != NULL)
+			*alpha = 0;
+	}
+#endif
+	else
+	{
+		geany_debug("Unable to parse color '%s'", color_spec);
+		return -1;
+	}
 
-	return (red | (green << 8) | (blue << 16));
+	/* Convert to Scintilla packed notation */
+	return (r | (g << 8) | (b << 16));
+#undef TEMP_COLOR_MAX
 }
 
 
diff --git a/src/utils.h b/src/utils.h
index 4219e65..9c0e6bb 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -220,7 +220,7 @@ void utils_beep(void);
 gchar *utils_make_human_readable_str(guint64 size, gulong block_size,
 									 gulong display_unit);
 
-gint utils_strtod(const gchar *source, gchar **end, gboolean with_route);
+gint utils_parse_color(const gchar *color_spec, guint8 *alpha);
 
 gchar *utils_get_current_time_string(void);
 
diff --git a/src/win32.c b/src/win32.c
index b6aa9c4..1ef7555 100644
--- a/src/win32.c
+++ b/src/win32.c
@@ -565,7 +565,7 @@ void win32_show_color_dialog(const gchar *colour)
 	cc.lStructSize = sizeof(cc);
 	cc.hwndOwner = GDK_WINDOW_HWND(gtk_widget_get_window(main_widgets.window));
 	cc.lpCustColors = (LPDWORD) acr_cust_clr;
-	cc.rgbResult = (colour != NULL) ? utils_strtod(colour, NULL, colour[0] == '#') : 0;
+	cc.rgbResult = (colour != NULL) ? utils_parse_color(color, NULL) : 0;
 	cc.Flags = CC_FULLOPEN | CC_RGBINIT;
 
 	if (ChooseColor(&cc))
_______________________________________________
Devel mailing list
Devel@lists.geany.org
https://lists.geany.org/cgi-bin/mailman/listinfo/devel

Reply via email to