[Fontconfig] how to detect `fontconfig needs a long time'

Masamichi Hosoda trueroad at trueroad.jp
Wed Nov 23 15:41:13 UTC 2016


>>> OK.  So how can an application find out that the font cache
>>> creation (or update) is very time consuming?  Is it at least
>>> possible to catch the situation of a first run?
>> 
>> current implementation assumes the users will runs fc-cache to
>> create caches before running.  as such APIs isn't available at this
>> point, so no, it isn't.  though we discussed a bit these days, if it
>> is wrong assumption, we may need to think about another way IMHO.
> 
> Given that many applications that use fontconfig are ported to Windows
> today, the assumption of running `fc-cache' in advance is becoming
> much weaker IMHO – there is no longer a global fontconfig cache, since
> every program comes with its own stuff.[*] I hate this approach a lot,
> but we have to face the reality on this platform...

I propose to export an inner API, FcDirCacheValidConfig ().
I've attached the patch `0001-Export-FcDirCacheValidConfig'.

Currently there is no way for applications to detect
`fontconfig needs a long time' for cache updating.

There is also no way for applications to find out
whether font cache updating is necessary or not, in a short time.
The already exported FcDirCacheValid () API updates all caches.
In other words, it takes a long time when updating is necessary.

I've investigated the point where FcDirCacheValid () takes a long time.
As a result, I noticed that inner API, FcDirCacheValidConfig ()
does not take a long time, that is, it does not update the cache.
So applications can find out whether updating caches are
necessary or not by this function, in a short time.

I've attached `is_neccesary_update.cc' as a sample application
using this function.
It can display directories that require cache updates.

An application may be able to estimate `fontconfig needs a long time'
for cache updating, since it become to be able to find out the directories
that requires cache updates.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Export-FcDirCacheValidConfig.patch
Type: text/x-patch
Size: 2014 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/fontconfig/attachments/20161124/80fcf5ff/attachment.bin>
-------------- next part --------------
#include <cstdio>
#include <iostream>

#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>

#include <fontconfig/fontconfig.h>

int check_cache (FcConfig *config);
int scan_dirs (FcStrList *list, FcConfig *config);
int scan_dir (const FcChar8 *dir, FcConfig *config);

int main ()
{
  FcInitLoadConfig ();
  FcConfig *config = FcConfigCreate ();

  FcChar8 *default_conf = FcConfigFilename (NULL);
  FcConfigParseAndLoad (config, default_conf, FcTrue);
  FcStrFree (default_conf);

  int ret = check_cache (config);

  std::cout << std::endl << "font cache updating is ";
  if (ret)
    std::cout << "neccesary (" << ret << " dirs) " << std::endl;
  else
    std::cout << "not neccesary" << std::endl;

  return 0;
}

int check_cache (FcConfig *config)
{
  FcStrList *list = FcConfigGetConfigDirs (config);
  int ret = scan_dirs (list, config);
  FcStrListDone (list);

  return ret;
}

int scan_dirs (FcStrList *list, FcConfig *config)
{
  int ret = 0;
  const FcChar8 *dir;

  while ((dir = FcStrListNext (list)))
    ret += scan_dir (dir, config);

  return ret;
}

int scan_dir (const FcChar8 *dir, FcConfig *config)
{
  std::cout << dir << " - " << std::flush;

  struct stat statb;
  if (stat ((char *)dir, &statb) == -1)
    {
      switch (errno)
	{
	case ENOENT:
	case ENOTDIR:
	  std::cout << "no such directory" << std::endl;
	  return 0;
	default:
	  perror ("");
	  return 0;
	}
    }

  int ret = 0;
  if (FcDirCacheValidConfig (dir, config))
    {
      std::cout << "valid" << std::endl;
    }
  else
    {
      std::cout << "***INVALID*** - neccesary updating" << std::endl;
      ret++;
    }

  DIR *dp = opendir ((char*)dir);
  struct dirent *dent;
  while ((dent = readdir (dp)) != NULL)
    {
      if (dent->d_type == DT_DIR && dent->d_name[0] != '.')
	{
	  std::string subdir ((char*)dir);
	  subdir += "/";
	  subdir += dent->d_name;
	  ret += scan_dir ((FcChar8*)subdir.c_str (), config);
	}
    }
  closedir (dp);

  return ret;
}


More information about the Fontconfig mailing list