St: avoid blocking IO to resolve relative urls

realpath() does a series of lstat() on each path component to resolve
symbolic links, but we just want to get an absolute path, and we don't
really care if it is physical or not. Going through a GFile does the
canonicalization we need, and is a lot faster.

https://bugzilla.gnome.org/show_bug.cgi?id=687881
This commit is contained in:
Giovanni Campagna 2012-11-22 01:13:59 +01:00
parent 468a855f04
commit f7af96dbb2
3 changed files with 53 additions and 77 deletions

View File

@ -1738,15 +1738,19 @@ _st_theme_node_ensure_background (StThemeNode *node)
else if (term->type == TERM_URI) else if (term->type == TERM_URI)
{ {
CRStyleSheet *base_stylesheet; CRStyleSheet *base_stylesheet;
GFile *file;
if (decl->parent_statement != NULL) if (decl->parent_statement != NULL)
base_stylesheet = decl->parent_statement->parent_sheet; base_stylesheet = decl->parent_statement->parent_sheet;
else else
base_stylesheet = NULL; base_stylesheet = NULL;
node->background_image = _st_theme_resolve_url (node->theme, file = _st_theme_resolve_url (node->theme,
base_stylesheet, base_stylesheet,
term->content.str->stryng->str); term->content.str->stryng->str);
node->background_image = g_strdup (g_file_get_path (file));
g_object_unref (file);
} }
} }
} }
@ -1843,6 +1847,7 @@ _st_theme_node_ensure_background (StThemeNode *node)
if (decl->value->type == TERM_URI) if (decl->value->type == TERM_URI)
{ {
CRStyleSheet *base_stylesheet; CRStyleSheet *base_stylesheet;
GFile *file;
if (decl->parent_statement != NULL) if (decl->parent_statement != NULL)
base_stylesheet = decl->parent_statement->parent_sheet; base_stylesheet = decl->parent_statement->parent_sheet;
@ -1850,9 +1855,12 @@ _st_theme_node_ensure_background (StThemeNode *node)
base_stylesheet = NULL; base_stylesheet = NULL;
g_free (node->background_image); g_free (node->background_image);
node->background_image = _st_theme_resolve_url (node->theme, file = _st_theme_resolve_url (node->theme,
base_stylesheet, base_stylesheet,
decl->value->content.str->stryng->str); decl->value->content.str->stryng->str);
node->background_image = g_strdup (g_file_get_path (file));
g_object_unref (file);
} }
else if (term_is_inherit (decl->value)) else if (term_is_inherit (decl->value))
{ {
@ -2668,6 +2676,7 @@ st_theme_node_get_border_image (StThemeNode *node)
int border_bottom; int border_bottom;
int border_left; int border_left;
GFile *file;
char *filename; char *filename;
/* Support border-image: none; to suppress a previously specified border image */ /* Support border-image: none; to suppress a previously specified border image */
@ -2746,7 +2755,10 @@ st_theme_node_get_border_image (StThemeNode *node)
else else
base_stylesheet = NULL; base_stylesheet = NULL;
filename = _st_theme_resolve_url (node->theme, base_stylesheet, url); file = _st_theme_resolve_url (node->theme, base_stylesheet, url);
filename = g_strdup (g_file_get_path (file));
g_object_unref (file);
if (filename == NULL) if (filename == NULL)
goto next_property; goto next_property;

View File

@ -29,10 +29,10 @@ G_BEGIN_DECLS
GPtrArray *_st_theme_get_matched_properties (StTheme *theme, GPtrArray *_st_theme_get_matched_properties (StTheme *theme,
StThemeNode *node); StThemeNode *node);
/* Resolve an URL from the stylesheet to a filename */ /* Resolve an URL from the stylesheet to a file */
char *_st_theme_resolve_url (StTheme *theme, GFile *_st_theme_resolve_url (StTheme *theme,
CRStyleSheet *base_stylesheet, CRStyleSheet *base_stylesheet,
const char *url); const char *url);
CRDeclaration *_st_theme_parse_declaration_list (const char *str); CRDeclaration *_st_theme_parse_declaration_list (const char *str);

View File

@ -849,9 +849,16 @@ add_matched_properties (StTheme *a_this,
char *filename = NULL; char *filename = NULL;
if (import_rule->url->stryng && import_rule->url->stryng->str) if (import_rule->url->stryng && import_rule->url->stryng->str)
filename = _st_theme_resolve_url (a_this, {
a_nodesheet, GFile *file;
import_rule->url->stryng->str);
file = _st_theme_resolve_url (a_this,
a_nodesheet,
import_rule->url->stryng->str);
filename = g_strdup (g_file_get_path (file));
g_object_unref (file);
}
if (filename) if (filename)
import_rule->sheet = parse_stylesheet (filename, NULL); import_rule->sheet = parse_stylesheet (filename, NULL);
@ -999,84 +1006,41 @@ _st_theme_get_matched_properties (StTheme *theme,
* local filename, if possible. The resolution here is distinctly lame and * local filename, if possible. The resolution here is distinctly lame and
* will fail on many examples. * will fail on many examples.
*/ */
char * GFile *
_st_theme_resolve_url (StTheme *theme, _st_theme_resolve_url (StTheme *theme,
CRStyleSheet *base_stylesheet, CRStyleSheet *base_stylesheet,
const char *url) const char *url)
{ {
const char *base_filename = NULL; char *scheme;
char *dirname; GFile *stylesheet, *resource;
char *filename;
char *canonicalized_path;
/* Handle absolute file:/ URLs */ if ((scheme = g_uri_parse_scheme (url)))
if (g_str_has_prefix (url, "file:") ||
g_str_has_prefix (url, "File:") ||
g_str_has_prefix (url, "FILE:"))
{ {
GError *error = NULL; g_free (scheme);
char *filename; resource = g_file_new_for_uri (url);
filename = g_filename_from_uri (url, NULL, &error);
if (filename == NULL)
{
g_warning ("%s", error->message);
g_error_free (error);
}
return filename;
} }
else if (base_stylesheet != NULL)
/* Guard against http:/ URLs */
if (g_str_has_prefix (url, "http:") ||
g_str_has_prefix (url, "Http:") ||
g_str_has_prefix (url, "HTTP:"))
{ {
g_warning ("Http URL '%s' in theme stylesheet is not supported", url); const char *base_filename = NULL;
return NULL; char *dirname;
}
/* Assume anything else is a relative URL, and "resolve" it base_filename = g_hash_table_lookup (theme->filenames_by_stylesheet, base_stylesheet);
*/
if (url[0] == '/')
{
canonicalized_path = realpath (url, NULL);
if (g_mem_is_system_malloc ())
{
filename = canonicalized_path;
}
else
{
filename = g_strdup (canonicalized_path);
free (canonicalized_path);
}
return filename;
}
base_filename = g_hash_table_lookup (theme->filenames_by_stylesheet, base_stylesheet); /* This is an internal function, if we get here with
a bad @base_stylesheet we have a problem. */
g_assert (base_filename);
if (base_filename == NULL) dirname = g_path_get_dirname (base_filename);
{ stylesheet = g_file_new_for_path (dirname);
g_warning ("Can't get base to resolve url '%s'", url); resource = g_file_resolve_relative_path (stylesheet, url);
return NULL;
}
dirname = g_path_get_dirname (base_filename); g_object_unref (stylesheet);
filename = g_build_filename (dirname, url, NULL); g_free (dirname);
canonicalized_path = realpath (filename, NULL);
g_free (dirname);
g_free (filename);
if (g_mem_is_system_malloc ())
{
filename = canonicalized_path;
} }
else else
{ {
filename = g_strdup (canonicalized_path); resource = g_file_new_for_path (url);
free (canonicalized_path);
} }
return filename; return resource;
} }