• R/O
  • HTTP
  • SSH
  • HTTPS

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

作図ソフト dia の改良版


File Info

Rev. f225364d27d9b450c9c91508049c3093c2463d9d
크기 28,948 bytes
Time 2004-05-21 22:58:46
Author Lars Clausen
Log Message

Fixes from Hans, random bug fixes from bugzilla.

Content

/* Dia -- an diagram creation/manipulation program
 * Copyright (C) 1998 Alexander Larsson
 * Font code completely reworked for the Pango conversion
 * Copyright (C) 2002 Cyrille Chepelov 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strlen */
#include <time.h>

#include <pango/pango.h>
#ifdef HAVE_FREETYPE
#include <pango/pangoft2.h>
#endif
#include <gdk/gdk.h>

#include "font.h"
#include "message.h"
#include "intl.h"

static PangoContext* pango_context = NULL;

/* This is the global factor that says what zoom factor is 100%.  It's
 * normally 20.0 (and likely to stay that way).  It is defined by how many
 * pixels one cm is represented as.
 */
static real global_zoom_factor = 20.0;

static int
compare(const void *p1, const void *p2) {
  return g_ascii_strcasecmp(pango_font_family_get_name(*(PangoFontFamily **)p1),
			    pango_font_family_get_name(*(PangoFontFamily **)p2));
}

/* For debugging: Sort families */
static int
cmp_families (const void *a, const void *b)
{
  const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
  const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
  
  return g_utf8_collate (a_name, b_name);
}

/* For debugging: List all font families */
static void
list_families()
{
  PangoFontFamily **families;
  int nfamilies;
  int i;

  pango_context_list_families(dia_font_get_context(), &families, &nfamilies);
  qsort (families, nfamilies, sizeof (PangoFontFamily *), cmp_families);
  for (i = 0; i < nfamilies; i++) {
    puts(pango_font_family_get_name(families[i]));
  }
}

static void
dia_font_check_for_font(int font) {
    DiaFont *check;
    PangoFont *loaded;

    check = dia_font_new_from_style(font, 1.0);
    loaded = pango_context_load_font(dia_font_get_context(),
				     check->pfd);
    if (loaded == NULL) {
      message_error(_("Can't load font %s.\n"), dia_font_get_family(check));
    }
}

void
dia_font_init(PangoContext* pcontext)
{
  pango_context = pcontext;
  /* We must have these three fonts! */
  dia_font_check_for_font(DIA_FONT_SANS);
  dia_font_check_for_font(DIA_FONT_SERIF);
  dia_font_check_for_font(DIA_FONT_MONOSPACE);
}

/* We might not need these anymore, when using FT2/Win32 fonts only */
static GList *pango_contexts;

void
dia_font_push_context(PangoContext *pcontext) {
  pango_contexts = g_list_prepend(pango_contexts, pango_context);
  pango_context = pcontext;
  pango_context_set_language (pango_context, gtk_get_default_language ());
  g_object_ref(pcontext);
}

void
dia_font_pop_context() {
  g_object_unref(pango_context);
  pango_context = (PangoContext*)pango_contexts->data;
  pango_context_set_language (pango_context, gtk_get_default_language ());
  pango_contexts = g_list_next(pango_contexts);
}

PangoContext *
dia_font_get_context() {
  if (pango_context == NULL) {
#ifdef HAVE_FREETYPE
    /* This is suggested by new Pango (1.2.4+), but doesn't get us the
     * right resolution:(
     dia_font_push_context(pango_ft2_font_map_create_context(pango_ft2_font_map_new()));
    */
    dia_font_push_context(pango_ft2_get_context(75,75));
#else
    dia_font_push_context(gdk_pango_context_get());
#endif
  }

  return pango_context;
}

    /* dia centimetres to pango device units */
static gint
dcm_to_pdu(real dcm) { return dcm * global_zoom_factor * PANGO_SCALE; }
    /* pango device units to dia centimetres */
static real
pdu_to_dcm(gint pdu) { return (real)pdu / (global_zoom_factor * PANGO_SCALE); }

static void dia_font_class_init(DiaFontClass* class);
static void dia_font_finalize(GObject* object);
static void dia_font_init_instance(DiaFont*);

GType
dia_font_get_type (void)
{
    static GType object_type = 0;

    if (!object_type) {
        static const GTypeInfo object_info =
            {
                sizeof (DiaFontClass),
                (GBaseInitFunc) NULL,
                (GBaseFinalizeFunc) NULL,
                (GClassInitFunc) dia_font_class_init, /* class_init */
                NULL,           /* class_finalize */
                NULL,           /* class_data */
                sizeof (DiaFont),
                0,              /* n_preallocs */
                (GInstanceInitFunc)dia_font_init_instance
            };
        object_type = g_type_register_static (G_TYPE_OBJECT,
                                              "DiaFont",
                                              &object_info, 0);
    }  
    return object_type;
}
static gpointer parent_class;

static void
dia_font_class_init(DiaFontClass* klass)
{
  GObjectClass* object_class = G_OBJECT_CLASS(klass);
  parent_class = g_type_class_peek_parent(klass);
  object_class->finalize = dia_font_finalize;
}

static void 
dia_font_init_instance(DiaFont* font)
{
        /*GObject *gobject = G_OBJECT(font);  */
}

DiaFont*
dia_font_new(const char *family, DiaFontStyle style, real height)
{
  DiaFont* retval = dia_font_new_from_style(style, height);

  pango_font_description_set_family(retval->pfd,family);

  pango_context_load_font(dia_font_get_context(), retval->pfd);

  return retval;
}

static void
dia_pfd_set_family(PangoFontDescription* pfd, DiaFontFamily fam) {
  switch (fam) {
  case DIA_FONT_SANS :
    pango_font_description_set_family(pfd, "sans");
    break;
  case DIA_FONT_SERIF :
    pango_font_description_set_family(pfd, "serif");
    break;
  case DIA_FONT_MONOSPACE :
    pango_font_description_set_family(pfd, "monospace");
    break;
  default :
          /* Pango does allow fonts without a name */
      ;
  }
}

static void
dia_pfd_set_weight(PangoFontDescription* pfd, DiaFontWeight fw) {
  switch (fw) {
  case DIA_FONT_ULTRALIGHT :
    pango_font_description_set_weight(pfd, PANGO_WEIGHT_ULTRALIGHT);
    break;
  case DIA_FONT_LIGHT :
    pango_font_description_set_weight(pfd, PANGO_WEIGHT_LIGHT);
    break;
  case DIA_FONT_WEIGHT_NORMAL :
    pango_font_description_set_weight(pfd, PANGO_WEIGHT_NORMAL);
    break;
  case DIA_FONT_MEDIUM : /* Pango doesn't have this, but 
                            'intermediate values are possible' */
    pango_font_description_set_weight(pfd, 500);
    break;
  case DIA_FONT_DEMIBOLD : /* Pango doesn't have this, ... */
    pango_font_description_set_weight(pfd, 600);
    break;
  case DIA_FONT_BOLD :
    pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
    break;
  case DIA_FONT_ULTRABOLD :
    pango_font_description_set_weight(pfd, PANGO_WEIGHT_ULTRABOLD);
    break;
  case DIA_FONT_HEAVY :
    pango_font_description_set_weight(pfd, PANGO_WEIGHT_HEAVY);
    break;
  default :
    g_assert_not_reached();
  }
}

static void
dia_pfd_set_slant(PangoFontDescription* pfd, DiaFontSlant fo) {
  switch (fo) {
  case DIA_FONT_NORMAL :
    pango_font_description_set_style(pfd,PANGO_STYLE_NORMAL);
    break;
  case DIA_FONT_OBLIQUE :
    pango_font_description_set_style(pfd,PANGO_STYLE_OBLIQUE);
    break;
  case DIA_FONT_ITALIC :
    pango_font_description_set_style(pfd,PANGO_STYLE_ITALIC);
    break;
  default :
    g_assert_not_reached();
  }
}

static void dia_pfd_set_size(PangoFontDescription* pfd, real height)
{ /* inline candidate... */
  pango_font_description_set_size(pfd, dcm_to_pdu(height) );
}


DiaFont*
dia_font_new_from_style(DiaFontStyle style, real height)
{
  DiaFont* retval;
  /* in the future we could establish Dia's own default font
   * matching to be as (font-)system independent as possible.
   * For now fall back to Pangos configuration --hb
   */
  PangoFontDescription* pfd = pango_font_description_new();
  dia_pfd_set_family(pfd,DIA_FONT_STYLE_GET_FAMILY(style));
  dia_pfd_set_weight(pfd,DIA_FONT_STYLE_GET_WEIGHT(style));
  dia_pfd_set_slant(pfd,DIA_FONT_STYLE_GET_SLANT(style));
  dia_pfd_set_size(pfd,height);
  
  retval = DIA_FONT(g_type_create_instance(dia_font_get_type()));
  retval->pfd = pfd;
  return retval;
}

DiaFont* dia_font_copy(const DiaFont* font)
{
    if (!font) return NULL;
    return dia_font_new(dia_font_get_family(font),
                            dia_font_get_style(font),
                            dia_font_get_height(font));
}

void
dia_font_finalize(GObject* object)
{
    DiaFont* font;
    font = DIA_FONT(object);
    
    if (font->pfd) pango_font_description_free(font->pfd);
    G_OBJECT_CLASS(parent_class)->finalize(object);
}

DiaFont* dia_font_ref(DiaFont* font)
{
    g_object_ref(G_OBJECT(font));
    return font;
}

void dia_font_unref(DiaFont* font)
{ 
    g_object_unref(G_OBJECT(font));
}

DiaFontStyle 
dia_font_get_style(const DiaFont* font)
{
  guint style;

  static int weight_map[] = {
    DIA_FONT_ULTRALIGHT, DIA_FONT_LIGHT,
    DIA_FONT_WEIGHT_NORMAL, /* intentionaly ==0 */
    DIA_FONT_MEDIUM, DIA_FONT_DEMIBOLD, /* not yet in Pango */
    DIA_FONT_BOLD, DIA_FONT_ULTRABOLD, DIA_FONT_HEAVY
  };

  PangoStyle pango_style = pango_font_description_get_style(font->pfd);
  PangoWeight pango_weight = pango_font_description_get_weight(font->pfd);

  g_assert(PANGO_WEIGHT_ULTRALIGHT <= pango_weight && pango_weight <= PANGO_WEIGHT_HEAVY); 
  g_assert(PANGO_WEIGHT_ULTRALIGHT == 200);
  g_assert(PANGO_WEIGHT_NORMAL == 400);
  g_assert(PANGO_WEIGHT_BOLD == 700);

  style  = weight_map[(pango_weight - PANGO_WEIGHT_ULTRALIGHT) / 100];
  style |= (pango_style << 2);

  return style;
}

G_CONST_RETURN char*
dia_font_get_family(const DiaFont* font)
{
  return pango_font_description_get_family(font->pfd);
}

real
dia_font_get_height(const DiaFont* font)
{
  return pdu_to_dcm(pango_font_description_get_size(font->pfd));
}

void
dia_font_set_height(DiaFont* font, real height)
{
  pango_font_description_set_size(font->pfd, dcm_to_pdu(height));    
}


G_CONST_RETURN char*
dia_font_get_psfontname(const DiaFont *font)
{
    /* FIXME: this will very likely not work ! */
  return dia_font_get_legacy_name(font);
}

void dia_font_set_any_family(DiaFont* font, const char* family)
{
  g_assert(font != NULL);
  pango_font_description_set_family(font->pfd, family);
  if (font->legacy_name) {
      g_free(font->legacy_name);
      font->legacy_name = NULL;
  }
}

void dia_font_set_family(DiaFont* font, DiaFontFamily family)
{
  g_assert(font != NULL);
  dia_pfd_set_family(font->pfd,family);  
  if (font->legacy_name) {
      g_free(font->legacy_name);
      font->legacy_name = NULL;
  }
}

void dia_font_set_weight(DiaFont* font, DiaFontWeight weight)
{
  g_assert(font != NULL);    
  dia_pfd_set_weight(font->pfd,weight);
}

void dia_font_set_slant(DiaFont* font, DiaFontSlant slant)
{
  g_assert(font != NULL);    
  dia_pfd_set_slant(font->pfd,slant);
}


struct weight_name { DiaFontWeight fw; const char *name; };    
static const struct weight_name weight_names[] = {
    {DIA_FONT_ULTRALIGHT, "200"},
    {DIA_FONT_LIGHT,"300"},
    {DIA_FONT_WEIGHT_NORMAL,"normal"},
    {DIA_FONT_WEIGHT_NORMAL,"400"},
    {DIA_FONT_MEDIUM, "500"},
    {DIA_FONT_DEMIBOLD, "600"},
    {DIA_FONT_BOLD, "700"},
    {DIA_FONT_ULTRABOLD, "800"},
    {DIA_FONT_HEAVY, "900"},
    {0,NULL}};

G_CONST_RETURN char *dia_font_get_weight_string(const DiaFont* font)
{
    const struct weight_name* p;
    DiaFontWeight fw = DIA_FONT_STYLE_GET_WEIGHT(dia_font_get_style(font));
    
    for (p = weight_names; p->name != NULL; ++p) {
        if (p->fw == fw) return p->name;
    }
    return "normal";
}

void dia_font_set_weight_from_string(DiaFont* font, const char* weight) {
    DiaFontWeight fw = DIA_FONT_WEIGHT_NORMAL;
    const struct weight_name* p;

    for (p = weight_names; p->name != NULL; ++p) {
        if (0 == strncmp(weight,p->name,8)) {
            fw = p->fw;
            break;
        }
    }

    dia_font_set_weight(font,fw);
}


struct slant_name { DiaFontSlant fo; const char *name; };    
static const struct slant_name slant_names[] = {
    { DIA_FONT_NORMAL, "normal"},
    { DIA_FONT_OBLIQUE, "oblique"},
    { DIA_FONT_ITALIC, "italic"},
    { 0, NULL} };

G_CONST_RETURN char *
dia_font_get_slant_string(const DiaFont* font)
{
    const struct slant_name* p;
    DiaFontSlant fo =
    DIA_FONT_STYLE_GET_SLANT(dia_font_get_style(font));
    
    for (p = slant_names; p->name != NULL; ++p) {
        if (p->fo == fo) return p->name;
    }
    return "normal";
}

void dia_font_set_slant_from_string(DiaFont* font, const char* obli) {
    DiaFontSlant fo = DIA_FONT_NORMAL;
    const struct slant_name* p;

    DiaFontStyle old_style;
    DiaFontSlant old_fo;
    old_style = dia_font_get_style(font);
    old_fo = DIA_FONT_STYLE_GET_SLANT(old_style);
    
    for (p = slant_names; p->name != NULL; ++p) {
        if (0 == strncmp(obli,p->name,8)) {
            fo = p->fo;
            break;
        }
    }
    dia_font_set_slant(font,fo);
}


/* ************************************************************************ */
/* Non-scaled versions of the utility routines                              */
/* ************************************************************************ */

real
dia_font_string_width(const char* string, DiaFont *font, real height)
{
    return dia_font_scaled_string_width(string,font,height,global_zoom_factor);
}

real
dia_font_ascent(const char* string, DiaFont* font, real height)
{
    return dia_font_scaled_ascent(string,font,height,global_zoom_factor);
}

real dia_font_descent(const char* string, DiaFont* font, real height)
{
    return dia_font_scaled_descent(string,font,height,global_zoom_factor);
}

typedef struct {
  gchar *string;
  DiaFont *font;
  real height;
  PangoLayout *layout;
  int usecount;
} LayoutCacheItem;

static GHashTable *layoutcache;

static gboolean
layout_cache_equals(gconstpointer e1, gconstpointer e2) 
{
  LayoutCacheItem *i1 = (LayoutCacheItem*)e1,
    *i2 = (LayoutCacheItem*)e2;

  return strcmp(i1->string, i2->string) == 0 &&
    fabs(i1->height - i2->height) < 0.00001 &&
    i1->font == i2->font;
}

static guint
layout_cache_hash(gconstpointer el) 
{
  LayoutCacheItem *item = (LayoutCacheItem*)el;

  return g_str_hash(item->string) ^
    (int)(item->height*1000) ^
    (int)(item->font);
}

static long layout_cache_last_use;

static gboolean
layout_cache_cleanup_entry(gpointer key, gpointer value, gpointer data)
{
  LayoutCacheItem *item = (LayoutCacheItem*)value;
  /** Remove unused items */
  if (item->usecount == 0) return TRUE;
  item->usecount = 0;
  return FALSE;
}

/** The actual hash cleanup, called when idle. */
static gboolean
layout_cache_cleanup_idle(gpointer data)
{
  GHashTable *table = (GHashTable*)(data);

  g_hash_table_foreach_remove(table, layout_cache_cleanup_entry, NULL);

  return FALSE;
}

/** Every ten minutes, clean up those strings that haven't seen use since
 * last cleanup.
 */
static gboolean
layout_cache_cleanup(gpointer data)
{
  /* Only cleanup if there has been font activity since last cleanup */
  if (time(0) - layout_cache_last_use < 60*10) {
    /* Don't go directly to cleanup, wait till there's a pause. */
    g_idle_add(layout_cache_cleanup_idle, data);
  }
  /* Keep doing this */
  return TRUE;
}

static void
layout_cache_free_key(gpointer data)
{
    LayoutCacheItem *item = (LayoutCacheItem*)data;

    if (item->string != NULL) {
      g_free(item->string);
      item->string = NULL;
    }

    if (item->font != NULL) {
      g_object_unref(item->font);
      item->font = NULL;
    }

    if (item->layout != NULL) {
      g_object_unref(item->layout);
      item->layout = NULL;
    }
    g_free(item);
}


PangoLayout*
dia_font_build_layout(const char* string, DiaFont* font, real height)
{
    PangoLayout* layout;
    PangoAttrList* list;
    PangoAttribute* attr;
    guint length;
    gchar *desc = NULL;

    LayoutCacheItem *cached;

    layout_cache_last_use = time(0);
    if (layoutcache == NULL) {
      /** Note that key and value are the same -- it's a HashSet */
      layoutcache = g_hash_table_new_full(layout_cache_hash,
					  layout_cache_equals,
					  layout_cache_free_key,
					  NULL);
      g_timeout_add(10*60*1000, layout_cache_cleanup, (gpointer)layoutcache);
    } else {
      LayoutCacheItem item;
      item.string = string;
      item.font = font;
      item.height = height;
      cached = g_hash_table_lookup(layoutcache, &item);
      if (cached != NULL) {
	g_object_ref(cached->layout);
	cached->usecount ++;
	return cached->layout;
      }
    }

    cached = g_new0(LayoutCacheItem,1);
    cached->string = g_strdup(string);
    cached->font = font;
    g_object_ref(font);
    cached->height = height;

    height *= 0.7;

    dia_font_set_height(font,height);
    layout = pango_layout_new(dia_font_get_context());

    length = string ? strlen(string) : 0;
    pango_layout_set_text(layout,string,length);
        
    list = pango_attr_list_new();
    desc = g_utf8_strdown(pango_font_description_get_family(font->pfd), -1);
    pango_font_description_set_family(font->pfd, desc);
    g_free(desc);
    attr = pango_attr_font_desc_new(font->pfd);
    attr->start_index = 0;
    attr->end_index = length;
    pango_attr_list_insert(list,attr); /* eats attr */
    
    pango_layout_set_attributes(layout,list);
    pango_attr_list_unref(list);

    pango_layout_set_indent(layout,0);
    pango_layout_set_justify(layout,FALSE);
    pango_layout_set_alignment(layout,PANGO_ALIGN_LEFT);
  
    cached->layout = layout;
    g_object_ref(layout);
    cached->usecount = 1;
    g_hash_table_insert(layoutcache, cached, cached);

    return layout;
}

/* ************************************************************************ */
/* scaled versions of the utility routines                                  */
/* ************************************************************************ */

void
dia_font_set_nominal_zoom_factor(real size_one)
{ global_zoom_factor = size_one; }



real
dia_font_scaled_string_width(const char* string, DiaFont *font, real height,
                            real zoom_factor)
{
    int lw,lh;
    real result;
    PangoLayout* layout = dia_font_scaled_build_layout(string, font,
						       height, zoom_factor);
    pango_layout_get_size(layout,&lw,&lh);
    g_object_unref(G_OBJECT(layout));
    
    result = pdu_to_dcm(lw);
    /* Scale the result back for the zoom factor */
    result /= (zoom_factor/global_zoom_factor);
    return result;
}

static gboolean
dia_font_vertical_extents(const char* string, DiaFont* font,
                          real height, real zoom_factor,
                          guint line_no,
                          real* top, real* baseline, real* bottom)
{
    PangoRectangle ink_rect,logical_rect;
    PangoLayout* layout;
    PangoLayoutIter* iter;
    guint i;

    layout = dia_font_scaled_build_layout(string, font,
                                          height, zoom_factor);
    iter = pango_layout_get_iter(layout);
    for (i = 0; i < line_no; ++i) {
       if (!pango_layout_iter_next_line(iter)) {
           pango_layout_iter_free(iter);
           g_object_unref(G_OBJECT(layout));
           return FALSE;
       }
    }
    
    pango_layout_iter_get_line_extents(iter,&ink_rect,&logical_rect);

    *top = pdu_to_dcm(logical_rect.y);
    *bottom = pdu_to_dcm(logical_rect.y + logical_rect.height);
    *baseline = pdu_to_dcm(pango_layout_iter_get_baseline(iter));

    pango_layout_iter_free(iter);
    g_object_unref(G_OBJECT(layout));

    return TRUE;
}
    

real
dia_font_scaled_ascent(const char* string, DiaFont* font, real height,
                      real zoom_factor)
{
  real top,bline,bottom;
  if (string[0] == '\0') {
    /* This hack won't work for fonts that don't cover ASCII */
    dia_font_vertical_extents("XjgM149",font,height,zoom_factor,
			      0,&top,&bline,&bottom);
  } else {
    dia_font_vertical_extents(string,font,height,zoom_factor,
			      0,&top,&bline,&bottom);
  }
  return (bline-top)/(zoom_factor/global_zoom_factor);
}

real dia_font_scaled_descent(const char* string, DiaFont* font,
                            real height, real zoom_factor)
{
  real top,bline,bottom;

  if (!string || string[0] == '\0') {
    /* This hack won't work for fonts that don't cover ASCII */
    dia_font_vertical_extents("XjgM149",font,height,zoom_factor,
			      0,&top,&bline,&bottom);
  } else {
    dia_font_vertical_extents(string,font,height,zoom_factor,
                              0,&top,&bline,&bottom);
  }
  return (bottom-bline)/(zoom_factor/global_zoom_factor);
}

PangoLayout*
dia_font_scaled_build_layout(const char* string, DiaFont* font,
                            real height, real zoom_factor)
{
    DiaFont* altered_font;
    real scaling;
    real nozoom_width;
    real target_zoomed_width;
    PangoLayout* layout;
    real altered_scaling;
    real real_width;

    scaling = zoom_factor / global_zoom_factor;
    if (fabs(1.0 - scaling) < 1E-7) {
        return dia_font_build_layout(string,font,height);
    }

    nozoom_width = dia_font_string_width(string,font,height);
    target_zoomed_width = nozoom_width * scaling;

        /* First try: no tweaks. */
    real_width = dia_font_string_width(string,font, height * scaling);
    if (real_width <= target_zoomed_width) {
        return dia_font_build_layout(string,font,height*scaling);
    }

    altered_font = dia_font_copy(font);

        /* Last try. Using the "reduce overall size" strategy. */
    for (altered_scaling = scaling;
         altered_scaling > (scaling / 2);
         altered_scaling *= (target_zoomed_width/real_width>0.98?0.98:
			     target_zoomed_width/real_width) ) {
      real_width = dia_font_string_width(string,font,
					 height * altered_scaling);

        if (real_width <= target_zoomed_width) {
            layout = dia_font_build_layout(string,altered_font,
                                          height*altered_scaling);
            dia_font_unref(altered_font);
            return layout;
        }
    }

    /* Everything has failed. Returning non-tweaked variant. */
    g_warning("Failed to appropriately tweak zoomed font for zoom factor %f.", zoom_factor);
    dia_font_unref(altered_font);
    return dia_font_build_layout(string,font,height*scaling);    
}

/**
 * Compatibility with older files out of pre Pango Time. 
 * Make old files look as similar as possible
 *
 * FIXME: DIA_FONT_FAMILY_ANY in the list below does mean noone knows better
 */
static struct _legacy_font {
  gchar*       oldname;
  gchar*       newname;
  DiaFontStyle style;   /* the DIA_FONT_FAMILY() is used as falback only */
} legacy_fonts[] = {
  /* these _MUST_ be sorted alphabetical */
  { "AvantGarde-Book",        "AvantGarde", DIA_FONT_SERIF },
  { "AvantGarde-BookOblique", "AvantGarde", DIA_FONT_SERIF | DIA_FONT_OBLIQUE },
  { "AvantGarde-Demi",        "AvantGarde", DIA_FONT_SERIF | DIA_FONT_DEMIBOLD },
  { "AvantGarde-DemiOblique", "AvantGarde", DIA_FONT_SERIF | DIA_FONT_OBLIQUE | DIA_FONT_DEMIBOLD },
  { "Batang", "Batang", DIA_FONT_FAMILY_ANY },
  { "Bookman-Demi",        "Bookman Old Style", DIA_FONT_SERIF | DIA_FONT_DEMIBOLD },
  { "Bookman-DemiItalic",  "Bookman Old Style", DIA_FONT_SERIF | DIA_FONT_DEMIBOLD | DIA_FONT_ITALIC },
  { "Bookman-Light",       "Bookman Old Style", DIA_FONT_SERIF | DIA_FONT_LIGHT },
  { "Bookman-LightItalic", "Bookman Old Style", DIA_FONT_SERIF | DIA_FONT_LIGHT | DIA_FONT_ITALIC },
  { "BousungEG-Light-GB", "BousungEG-Light-GB", DIA_FONT_FAMILY_ANY },
  { "Courier",             "monospace", DIA_FONT_MONOSPACE },
  { "Courier",             "Courier New", DIA_FONT_MONOSPACE },
  { "Courier-Bold",        "Courier New", DIA_FONT_MONOSPACE | DIA_FONT_BOLD },
  { "Courier-BoldOblique", "Courier New", DIA_FONT_MONOSPACE | DIA_FONT_OBLIQUE | DIA_FONT_BOLD },
  { "Courier-Oblique",     "Courier New", DIA_FONT_MONOSPACE | DIA_FONT_OBLIQUE },
  { "Dotum", "Dotum", DIA_FONT_FAMILY_ANY },
  { "GBZenKai-Medium", "GBZenKai-Medium", DIA_FONT_FAMILY_ANY }, 
  { "GothicBBB-Medium", "GothicBBB-Medium", DIA_FONT_FAMILY_ANY },
  { "Gulim", "Gulim", DIA_FONT_FAMILY_ANY }, 
  { "Headline", "Headline", DIA_FONT_FAMILY_ANY },
  { "Helvetica",             "sans", DIA_FONT_SANS },
  { "Helvetica",             "Arial", DIA_FONT_SANS },
  { "Helvetica-Bold",        "Arial", DIA_FONT_SANS | DIA_FONT_BOLD },
  { "Helvetica-BoldOblique", "Arial", DIA_FONT_SANS | DIA_FONT_BOLD | DIA_FONT_OBLIQUE },
  { "Helvetica-Narrow",             "Arial Narrow", DIA_FONT_SANS | DIA_FONT_MEDIUM },
  { "Helvetica-Narrow-Bold",        "Arial Narrow", DIA_FONT_SANS | DIA_FONT_DEMIBOLD },
  { "Helvetica-Narrow-BoldOblique", "Arial Narrow", DIA_FONT_SANS | DIA_FONT_MEDIUM | DIA_FONT_OBLIQUE },
  { "Helvetica-Narrow-Oblique",     "Arial Narrow", DIA_FONT_SANS | DIA_FONT_MEDIUM | DIA_FONT_OBLIQUE },
  { "Helvetica-Oblique",     "Arial", DIA_FONT_SANS | DIA_FONT_OBLIQUE },
  { "MOESung-Medium", "MOESung-Medium", DIA_FONT_FAMILY_ANY },
  { "NewCenturySchoolbook-Bold",       "Century Schoolbook SWA", DIA_FONT_SERIF | DIA_FONT_BOLD },
  { "NewCenturySchoolbook-BoldItalic", "Century Schoolbook SWA", DIA_FONT_SERIF | DIA_FONT_BOLD | DIA_FONT_ITALIC },
  { "NewCenturySchoolbook-Italic",     "Century Schoolbook SWA", DIA_FONT_SERIF | DIA_FONT_ITALIC },
  { "NewCenturySchoolbook-Roman",      "Century Schoolbook SWA", DIA_FONT_SERIF },
  { "Palatino-Bold",       "Palatino", DIA_FONT_FAMILY_ANY | DIA_FONT_BOLD }, 
  { "Palatino-BoldItalic", "Palatino", DIA_FONT_FAMILY_ANY | DIA_FONT_BOLD | DIA_FONT_ITALIC }, 
  { "Palatino-Italic",     "Palatino", DIA_FONT_FAMILY_ANY | DIA_FONT_ITALIC }, 
  { "Palatino-Roman",      "Palatino", DIA_FONT_FAMILY_ANY },
  { "Ryumin-Light", "Ryumin", DIA_FONT_FAMILY_ANY | DIA_FONT_LIGHT },
  { "ShanHeiSun-Light", "ShanHeiSun", DIA_FONT_FAMILY_ANY | DIA_FONT_LIGHT },
  { "Song-Medium", "Song-Medium", DIA_FONT_FAMILY_ANY | DIA_FONT_MEDIUM },
  { "Symbol", "Symbol", DIA_FONT_SANS | DIA_FONT_MEDIUM },
  { "Times-Bold",       "Times New Roman", DIA_FONT_SERIF | DIA_FONT_BOLD },
  { "Times-BoldItalic", "Times New Roman", DIA_FONT_SERIF | DIA_FONT_ITALIC | DIA_FONT_BOLD },
  { "Times-Italic",     "Times New Roman", DIA_FONT_SERIF | DIA_FONT_ITALIC },
  { "Times-Roman",      "serif", DIA_FONT_SERIF }, 
  { "Times-Roman",      "Times New Roman", DIA_FONT_SERIF }, 
  { "ZapfChancery-MediumItalic", "Zapf Calligraphic 801 SWA", DIA_FONT_SERIF | DIA_FONT_MEDIUM },
  { "ZapfDingbats", "Zapf Calligraphic 801 SWA", DIA_FONT_SERIF },
  { "ZenKai-Medium", "ZenKai", DIA_FONT_FAMILY_ANY | DIA_FONT_MEDIUM },
};


static int
fonts_compare (const void *key, const void *elem)
{
  char* a = (char*)key;
  char* b = ((struct _legacy_font*)elem)->oldname;
  return strcmp (a, b);
}

/**
 * Given a legacy name as stored until Dia-0.90 construct
 * a new DiaFont which is as similar as possible
 */
DiaFont*
dia_font_new_from_legacy_name(const char* name)
{
  /* do NOT translate anything here !!! */
  DiaFont* retval;
  struct _legacy_font* found;
  real height = 1.0;

  found = bsearch (name, legacy_fonts,
		   G_N_ELEMENTS(legacy_fonts), sizeof (struct _legacy_font),
		   fonts_compare);
  if (found) {
    retval = dia_font_new (found->newname, found->style, height);
    retval->legacy_name = found->oldname;
  } else {      
    /* We tried our best, let Pango complain */
    retval = dia_font_new (name, DIA_FONT_WEIGHT_NORMAL, height);
    retval->legacy_name = NULL;
  }
  
  return retval;
}

G_CONST_RETURN char*
dia_font_get_legacy_name(const DiaFont *font)
{
  const char* matched_name = NULL;
  const char* family;
  DiaFontStyle style;
  int i;

  /* if we have loaded it from an old file, use the old name */    
  if (font->legacy_name)
    return font->legacy_name;

  family = dia_font_get_family (font);
  style = dia_font_get_style (font);
  for (i = 0; i < G_N_ELEMENTS(legacy_fonts); i++) {
    if (0 == g_strcasecmp (legacy_fonts[i].newname, family)) {
      /* match weight and slant */
      DiaFontStyle st = legacy_fonts[i].style;
      if (   (DIA_FONT_STYLE_GET_SLANT(style) || DIA_FONT_STYLE_GET_WEIGHT(style))
          == (DIA_FONT_STYLE_GET_SLANT(st) || DIA_FONT_STYLE_GET_WEIGHT(st))) {
        return legacy_fonts[i].oldname; /* exact match */
      } else if (0 == (DIA_FONT_STYLE_GET_SLANT(st) || DIA_FONT_STYLE_GET_WEIGHT(st))) {
        matched_name = legacy_fonts[i].oldname;
        /* 'unmodified' font, continue matching */
      }
    }
  }
  return matched_name ? matched_name : "Courier";
}