Example #1
0
PdfFont* PdfFontCache::GetFont( FT_Face face, bool bEmbedd, const PdfEncoding * const pEncoding )
{
    PdfFont*          pFont;
    PdfFontMetrics*   pMetrics;
    std::pair<TISortedFontList,TCISortedFontList> it;

    std::string sName = FT_Get_Postscript_Name( face );
    if( sName.empty() )
    {
        PdfError::LogMessage( eLogSeverity_Critical, "Could not retrieve fontname for font!\n" );
        return NULL;
    }

    bool bBold   = ((face->style_flags & FT_STYLE_FLAG_BOLD)   != 0);
    bool bItalic = ((face->style_flags & FT_STYLE_FLAG_ITALIC) != 0);

    it = std::equal_range( m_vecFonts.begin(), m_vecFonts.end(), 
			   TFontCacheElement( sName.c_str(), bBold, bItalic, pEncoding ) );
    if( it.first == it.second )
    {
        pMetrics = new PdfFontMetrics( &m_ftLibrary, face );
        pFont    = this->CreateFontObject( it.first, m_vecFonts, pMetrics, 
					   bEmbedd, bBold, bItalic, sName.c_str(), pEncoding );
    }
    else
        pFont = (*it.first).m_pFont;

    return pFont;
}
Example #2
0
CAMLprim value Wrapper_FT_Get_Postscript_Name(value face)
{
  CAMLparam1(face);
  FT_Face f;

  f = *(FT_Face *)Data_custom_val(face);

  CAMLreturn(copy_string(FT_Get_Postscript_Name(f)));
};
Example #3
0
File: ftdump.c Project: xahgo/tama
  void
  Print_Name( FT_Face  face )
  {
    const char*  ps_name;


    printf( "font name entries\n" );

    /* XXX: Foundry?  Copyright?  Version? ... */

    printf( "   family:     %s\n", face->family_name );
    printf( "   style:      %s\n", face->style_name );

    ps_name = FT_Get_Postscript_Name( face );
    if ( ps_name == NULL )
      ps_name = "UNAVAILABLE";

    printf( "   postscript: %s\n", ps_name );
  }
Example #4
0
FT_Error
get_file_info(FontManagerFontInfo *fileinfo, const gchar * filepath, gint index)
{
    FT_Face         face;
    FT_Library      library;
    FT_Error        error;
    PS_FontInfoRec  ps_info;
    BDF_PropertyRec prop;

    gsize   filesize = 0;
    gchar   * font = NULL;

    if (G_UNLIKELY(!g_file_get_contents(filepath, &font, &filesize, NULL))) {
        g_warning("Failed to load file : %s", filepath);
        return FT_Err_Cannot_Open_Resource;
    }

    error = FT_Init_FreeType(&library);
    if (G_UNLIKELY(error))
        return error;

    error = FT_New_Memory_Face(library, (const FT_Byte *) font, (FT_Long) filesize, index, &face);
    if (G_UNLIKELY(error)) {
        g_warning("Failed to create FT_Face for file : %s", filepath);
        return error;
    }

    font_manager_font_info_set_owner(fileinfo, get_file_owner(filepath));
    font_manager_font_info_set_filetype(fileinfo, FT_Get_X11_Font_Format(face));

    gchar * _size = g_format_size(filesize);
    font_manager_font_info_set_filesize(fileinfo, _size);
    g_free0(_size);

    gchar * _md5 = g_compute_checksum_for_data(G_CHECKSUM_MD5, (const guchar *) font, filesize);
    font_manager_font_info_set_checksum(fileinfo, _md5);
    g_free0(_md5);

    font_manager_font_info_set_psname(fileinfo, FT_Get_Postscript_Name(face));

    TT_OS2 * os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
    if (G_LIKELY(os2 && os2->version >= 0x0001 && os2->version != 0xffff)) {
        gchar * _vendor = get_vendor_from_vendor_id((gchar *) os2->achVendID);
        font_manager_font_info_set_vendor(fileinfo, _vendor);
        g_free0(_vendor);
        gchar * panose = g_strdup_printf("%i:%i:%i:%i:%i:%i:%i:%i:%i:%i", os2->panose[0],
                                          os2->panose[1], os2->panose[2], os2->panose[3],
                                          os2->panose[4], os2->panose[5], os2->panose[6],
                                          os2->panose[7], os2->panose[8], os2->panose[9]);
        font_manager_font_info_set_panose(fileinfo, panose);
        g_free0(panose);
    }

    if (G_LIKELY(FT_IS_SFNT(face)))
        get_sfnt_info(fileinfo, face);
    if (FT_Get_PS_Font_Info(face, &ps_info) == 0)
        get_ps_info(fileinfo, ps_info, face);

    gint lic_type = get_license_type(font_manager_font_info_get_license_data(fileinfo),
                                     font_manager_font_info_get_copyright(fileinfo),
                                     font_manager_font_info_get_license_url(fileinfo));
    gchar * _name = get_license_name(lic_type);
    font_manager_font_info_set_license_type(fileinfo, _name);
    g_free0(_name);

    if (!font_manager_font_info_get_license_url(fileinfo)) {
        gchar * _url = get_license_url(lic_type);
        if (_url)
            font_manager_font_info_set_license_url(fileinfo, _url);
        g_free0(_url);
    }

    if (!font_manager_font_info_get_version(fileinfo)) {
        TT_Header * head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
        if (head)
            if (head->Font_Revision) {
                gchar * rev = g_strdup_printf("%f", (float) head->Font_Revision);
                font_manager_font_info_set_version(fileinfo, rev);
                g_free0(rev);
            }
    }

    if (!font_manager_font_info_get_vendor(fileinfo)) {
        int result = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
        if(result == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
            font_manager_font_info_set_vendor(fileinfo, prop.u.atom);
        else
            font_manager_font_info_set_vendor(fileinfo, "Unknown Vendor");
    }

    FT_Done_Face(face);
    error = FT_Done_FreeType(library);
    g_free0(font);
    return error;
}
Example #5
0
bool CFontEngine::openFontFt(const QString &file)
{
    enum ETtfWeight
    {
        TTF_WEIGHT_UNKNOWN = 0,
        TTF_WEIGHT_THIN = 100 + 50,
        TTF_WEIGHT_EXTRALIGHT = 200 + 50,
        TTF_WEIGHT_LIGHT = 300 + 50,
        TTF_WEIGHT_NORMAL = 400 + 50,
        TTF_WEIGHT_MEDIUM = 500 + 50,
        TTF_WEIGHT_SEMIBOLD = 600 + 50,
        TTF_WEIGHT_BOLD = 700 + 50,
        TTF_WEIGHT_EXTRABOLD = 800 + 50,
        TTF_WEIGHT_BLACK = 900 + 50
    };

    bool status = FT_New_Face(itsFt.library, QFile::encodeName(file), 0, &itsFt.face) ? false : true;

    if(status)
        itsFt.open = true;

    PS_FontInfoRec t1info;

    if(0 == FT_Get_PS_Font_Info(itsFt.face, &t1info))
    {
        itsFamily = t1info.family_name;
        itsType = TYPE_1;
    }
    else
    {
        itsFamily = getName(itsFt.face, TT_NAME_ID_FONT_FAMILY);
        itsType = TRUE_TYPE;
    }

    if(itsFamily.isEmpty())
        itsFamily = FT_Get_Postscript_Name(itsFt.face);

    if(itsFamily.isEmpty())
        status = false; // Hmm... couldn't find any of the names!

    if(status)
    {
        removeSymbols(itsFamily);
        itsPsName = (FT_Get_Postscript_Name(itsFt.face));

        if(TYPE_1 == itsType)
        {
            itsWeight = strToWeight(t1info.weight);
            itsItalic = t1info.italic_angle <= -4 || t1info.italic_angle >= 4 ? ITALIC_ITALIC : ITALIC_NONE;
        }
        else // TrueType...
        {
            TT_Postscript *post = NULL;
            TT_OS2 *os2 = NULL;
            TT_Header *head = NULL;
            bool gotItalic = false;

            if(NULL == (os2 = (TT_OS2 *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_os2)) || 0xFFFF == os2->version)
                itsWeight = WEIGHT_UNKNOWN;
            else
            {
                FT_UShort weight = (os2->usWeightClass > 0 && os2->usWeightClass < 100) ? os2->usWeightClass * 100 : os2->usWeightClass;

                if(weight < TTF_WEIGHT_THIN)
                    itsWeight = WEIGHT_THIN;
                else if(weight < TTF_WEIGHT_EXTRALIGHT)
                    itsWeight = WEIGHT_EXTRA_LIGHT;
                else if(weight < TTF_WEIGHT_LIGHT)
                    itsWeight = WEIGHT_LIGHT;
                else if(/*weight<TTF_WEIGHT_NORMAL || */ weight < TTF_WEIGHT_MEDIUM)
                    itsWeight = WEIGHT_MEDIUM;
                else if(weight < TTF_WEIGHT_SEMIBOLD)
                    itsWeight = WEIGHT_SEMI_BOLD;
                else if(weight < TTF_WEIGHT_BOLD)
                    itsWeight = WEIGHT_BOLD;
                else if(weight < TTF_WEIGHT_EXTRABOLD)
                    itsWeight = WEIGHT_EXTRA_BOLD;
                else if(weight < TTF_WEIGHT_BLACK)
                    itsWeight = WEIGHT_BLACK;
                else if(os2->fsSelection & (1 << 5))
                    itsWeight = WEIGHT_BOLD;
                else
                    itsWeight = WEIGHT_UNKNOWN;

                itsItalic = os2->fsSelection & (1 << 0) ? ITALIC_ITALIC : ITALIC_NONE;
                gotItalic = true;
            }

            if(WEIGHT_UNKNOWN == itsWeight)
                itsWeight =
                    NULL != (head = (TT_Header *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_head)) && head->Mac_Style & 1 ? WEIGHT_BOLD : WEIGHT_MEDIUM;

            if(!gotItalic && (head != NULL || NULL != (head = (TT_Header *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_head))))
            {
                gotItalic = true;
                itsItalic = head->Mac_Style & 2 ? ITALIC_ITALIC : ITALIC_NONE;
            }

            if(!gotItalic && NULL != (post = (TT_Postscript *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_post)))
            {
                struct TFixed
                {
                    TFixed(unsigned long v) : upper(v >> 16), lower(v & 0xFFFF)
                    {
                    }

                    short upper, lower;

                    float value()
                    {
                        return upper + (lower / 65536.0);
                    }
                };

                gotItalic = true;
                itsItalic = 0.0f == ((TFixed)post->italicAngle).value() ? ITALIC_NONE : ITALIC_ITALIC;
            }
        }
    }
Example #6
0
/**
 * \brief Select a face with the given charcode and add it to ASS_Font
 * \return index of the new face in font->faces, -1 if failed
 */
static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch)
{
    char *path;
    char *postscript_name = NULL;
    int i, index, uid, error;
    ASS_FontStream stream = { NULL, NULL };
    FT_Face face;

    if (font->n_faces == ASS_FONT_MAX_FACES)
        return -1;

    path = ass_font_select(fontsel, font->library, font , &index,
            &postscript_name, &uid, &stream, ch);

    if (!path)
        return -1;

    for (i = 0; i < font->n_faces; i++) {
        if (font->faces_uid[i] == uid) {
            ass_msg(font->library, MSGL_INFO,
                    "Got a font face that already is available! Skipping.");
            return i;
        }
    }

    if (stream.func) {
        FT_Open_Args args;
        FT_Stream ftstream = calloc(1, sizeof(FT_StreamRec));
        ASS_FontStream *fs  = calloc(1, sizeof(ASS_FontStream));

        *fs = stream;
        ftstream->size  = stream.func(stream.priv, NULL, 0, 0);
        ftstream->read  = read_stream_font;
        ftstream->close = close_stream_font;
        ftstream->descriptor.pointer = (void *)fs;

        memset(&args, 0, sizeof(FT_Open_Args));
        args.flags  = FT_OPEN_STREAM;
        args.stream = ftstream;

        error = FT_Open_Face(font->ftlibrary, &args, index, &face);

        if (error) {
            ass_msg(font->library, MSGL_WARN,
                    "Error opening memory font: '%s'", path);
            return -1;
        }

    } else {
        error = FT_New_Face(font->ftlibrary, path, index, &face);
        if (error) {
            ass_msg(font->library, MSGL_WARN,
                    "Error opening font: '%s', %d", path, index);
            return -1;
        }

        if (postscript_name && index < 0 && face->num_faces > 0) {
            // The font provider gave us a post_script name and is not sure
            // about the face index.. so use the postscript name to find the
            // correct face_index in the collection!
            for (int i = 0; i < face->num_faces; i++) {
                FT_Done_Face(face);
                error = FT_New_Face(font->ftlibrary, path, i, &face);
                if (error) {
                    ass_msg(font->library, MSGL_WARN,
                            "Error opening font: '%s', %d", path, i);
                    return -1;
                }

                const char *face_psname = FT_Get_Postscript_Name(face);
                if (face_psname != NULL &&
                    strcmp(face_psname, postscript_name) == 0)
                    break;
            }
        }
    }

    charmap_magic(font->library, face);
    buggy_font_workaround(face);

    font->faces[font->n_faces] = face;
    font->faces_uid[font->n_faces++] = uid;
    ass_face_set_size(face, font->size);
    return font->n_faces - 1;
}
Example #7
0
FT2Font::FT2Font(std::string facefile) 
{
  _VERBOSE("FT2Font::FT2Font");
  clear(Py::Tuple(0));
  
  int error = FT_New_Face( _ft2Library, facefile.c_str(), 0, &face );
  
  if (error == FT_Err_Unknown_File_Format ) {
    std::ostringstream s;
    s << "Could not load facefile " << facefile << "; Unknown_File_Format" << std::endl;
    throw Py::RuntimeError(s.str());
  }
  else if (error == FT_Err_Cannot_Open_Resource) {
    std::ostringstream s;
    s << "Could not open facefile " << facefile << "; Cannot_Open_Resource" << std::endl;
    throw Py::RuntimeError(s.str());
  }
  else if (error == FT_Err_Invalid_File_Format) {
    std::ostringstream s;
    s << "Could not open facefile " << facefile << "; Invalid_File_Format" << std::endl;
    throw Py::RuntimeError(s.str());
  }
  else if (error) {
    std::ostringstream s;
    s << "Could not open facefile " << facefile << "; freetype error code " << error<< std::endl;
    throw Py::RuntimeError(s.str());
  }
  
  // set a default fontsize 12 pt at 72dpi
  error = FT_Set_Char_Size( face, 12 * 64, 0, 72, 72 );
  //error = FT_Set_Char_Size( face, 20 * 64, 0, 80, 80 );
  if (error) {
    std::ostringstream s;
    s << "Could not set the fontsize for facefile  " << facefile << std::endl;
    throw Py::RuntimeError(s.str());
  }
  
  // set some face props as attributes
  //small memory leak fixed after 2.1.8 
  const char* ps_name = FT_Get_Postscript_Name( face );
  //const char* ps_name = "jdh";
  if ( ps_name == NULL )
    ps_name = "UNAVAILABLE";
  
  setattr("postscript_name", Py::String(ps_name));
  setattr("num_faces",       Py::Int(face->num_faces));
  setattr("family_name",     Py::String(face->family_name));
  setattr("style_name",      Py::String(face->style_name));
  setattr("face_flags",      Py::Int(face->face_flags));
  setattr("style_flags",     Py::Int(face->style_flags));
  setattr("num_glyphs",      Py::Int(face->num_glyphs));
  setattr("num_fixed_sizes", Py::Int(face->num_fixed_sizes));
  setattr("num_charmaps",    Py::Int(face->num_charmaps));
   
  int scalable = FT_IS_SCALABLE( face );

  setattr("scalable", Py::Int(scalable));
  
  if (scalable) {
    setattr("units_per_EM", Py::Int(face->units_per_EM));
    
    Py::Tuple bbox(4);
    bbox[0] = Py::Int(face->bbox.xMin);
    bbox[1] = Py::Int(face->bbox.yMin);
    bbox[2] = Py::Int(face->bbox.xMax);
    bbox[3] = Py::Int(face->bbox.yMax);
    setattr("bbox",  bbox);
    setattr("ascender",            Py::Int(face->ascender));
    setattr("descender",           Py::Int(face->descender));
    setattr("height",              Py::Int(face->height));
    setattr("max_advance_width",   Py::Int(face->max_advance_width));
    setattr("max_advance_height",  Py::Int(face->max_advance_height));
    setattr("underline_position",  Py::Int(face->underline_position));
    setattr("underline_thickness", Py::Int(face->underline_thickness));
  }
}
Example #8
0
/**
 * \brief Read basic metadata (names, weight, slant) from a FreeType face,
 * as required for the FontSelector for matching and sorting.
 * \param lib FreeType library
 * \param face FreeType face
 * \param info metadata, returned here
 * \return success
 */
static bool
get_font_info(FT_Library lib, FT_Face face, ASS_FontProviderMetaData *info)
{
    int i;
    int num_fullname = 0;
    int num_family   = 0;
    int num_names = FT_Get_Sfnt_Name_Count(face);
    int slant, weight;
    char *fullnames[MAX_FULLNAME];
    char *families[MAX_FULLNAME];

    // we're only interested in outlines
    if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
        return false;

    for (i = 0; i < num_names; i++) {
        FT_SfntName name;

        if (FT_Get_Sfnt_Name(face, i, &name))
            continue;

        if (name.platform_id == TT_PLATFORM_MICROSOFT &&
                (name.name_id == TT_NAME_ID_FULL_NAME ||
                 name.name_id == TT_NAME_ID_FONT_FAMILY)) {
            char buf[1024];
            ass_utf16be_to_utf8(buf, sizeof(buf), (uint8_t *)name.string,
                                name.string_len);

            if (name.name_id == TT_NAME_ID_FULL_NAME) {
                fullnames[num_fullname] = strdup(buf);
                if (fullnames[num_fullname] == NULL)
                    goto error;
                num_fullname++;
            }

            if (name.name_id == TT_NAME_ID_FONT_FAMILY) {
                families[num_family] = strdup(buf);
                if (families[num_family] == NULL)
                    goto error;
                num_family++;
            }
        }

    }

    // check if we got a valid family - if not use whatever FreeType gives us
    if (num_family == 0 && face->family_name) {
        families[0] = strdup(face->family_name);
        if (families[0] == NULL)
            goto error;
        num_family++;
    }

    // we absolutely need a name
    if (num_family == 0)
        goto error;

    // calculate sensible slant and weight from style attributes
    slant  = 110 * !!(face->style_flags & FT_STYLE_FLAG_ITALIC);
    weight = 300 * !!(face->style_flags & FT_STYLE_FLAG_BOLD) + 400;

    // fill our struct
    info->slant  = slant;
    info->weight = weight;
    info->width  = 100;     // FIXME, should probably query the OS/2 table

    info->postscript_name = (char *)FT_Get_Postscript_Name(face);

    info->families = calloc(sizeof(char *), num_family);
    if (info->families == NULL)
        goto error;
    memcpy(info->families, &families, sizeof(char *) * num_family);
    info->n_family = num_family;

    if (num_fullname) {
        info->fullnames = calloc(sizeof(char *), num_fullname);
        if (info->fullnames == NULL)
            goto error;
        memcpy(info->fullnames, &fullnames, sizeof(char *) * num_fullname);
        info->n_fullname = num_fullname;
    }

    return false;

error:
    for (i = 0; i < num_family; i++)
        free(families[i]);

    for (i = 0; i < num_fullname; i++)
        free(fullnames[i]);

    free(info->families);
    free(info->fullnames);

    return true;
}
Example #9
0
static VFontData *objfnt_to_ftvfontdata(PackedFile *pf)
{
	/* Variables */
	FT_Face face;
	const FT_ULong charcode_reserve = 256;
	FT_ULong charcode = 0, lcode;
	FT_UInt glyph_index;
	const char *fontname;
	VFontData *vfd;

#if 0
	FT_CharMap found = 0;
	FT_CharMap charmap;
	FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
	FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
	int n;
#endif

	/* load the freetype font */
	err = FT_New_Memory_Face(library,
	                         pf->data,
	                         pf->size,
	                         0,
	                         &face);

	if (err) return NULL;

#if 0
	for (n = 0; n < face->num_charmaps; n++)
	{
		charmap = face->charmaps[n];
		if (charmap->platform_id == my_platform_id &&
		    charmap->encoding_id == my_encoding_id)
		{
			found = charmap;
			break;
		}
	}

	if (!found) { return NULL; }

	/* now, select the charmap for the face object */
	err = FT_Set_Charmap(face, found);
	if (err) { return NULL; }
#endif

	/* allocate blender font */
	vfd = MEM_callocN(sizeof(*vfd), "FTVFontData");

	/* get the name */
	fontname = FT_Get_Postscript_Name(face);
	BLI_strncpy(vfd->name, (fontname == NULL) ? "" : fontname, sizeof(vfd->name));

	/* Extract the first 256 character from TTF */
	lcode = charcode = FT_Get_First_Char(face, &glyph_index);

	/* No charmap found from the ttf so we need to figure it out */
	if (glyph_index == 0) {
		FT_CharMap found = NULL;
		FT_CharMap charmap;
		int n;

		for (n = 0; n < face->num_charmaps; n++) {
			charmap = face->charmaps[n];
			if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) {
				found = charmap;
				break;
			}
		}

		err = FT_Set_Charmap(face, found);

		if (err)
			return NULL;

		lcode = charcode = FT_Get_First_Char(face, &glyph_index);
	}


	/* Adjust font size */
	if (face->bbox.yMax != face->bbox.yMin) {
		vfd->scale = (float)(1.0 / (double)(face->bbox.yMax - face->bbox.yMin));
	}
	else {
		vfd->scale = 1.0f / 1000.0f;
	}

	/* Load characters */
	vfd->characters = BLI_ghash_int_new_ex(__func__, charcode_reserve);

	while (charcode < charcode_reserve) {
		/* Generate the font data */
		freetypechar_to_vchar(face, charcode, vfd);

		/* Next glyph */
		charcode = FT_Get_Next_Char(face, charcode, &glyph_index);

		/* Check that we won't start infinite loop */
		if (charcode <= lcode)
			break;
		lcode = charcode;
	}

	return vfd;
}
Example #10
0
XeTeXFontMgr::NameCollection*
XeTeXFontMgr_FC::readNames(FcPattern* pat)
{
	NameCollection*	names = new NameCollection;

	char*	pathname;
	if (FcPatternGetString(pat, FC_FILE, 0, (FcChar8**)&pathname) != FcResultMatch)
		return names;
	int index;
	if (FcPatternGetInteger(pat, FC_INDEX, 0, &index) != FcResultMatch)
		return names;

	FT_Face face;
	if (FT_New_Face(gFreeTypeLibrary, pathname, index, &face) != 0)
		return names;

	const char* name = FT_Get_Postscript_Name(face);
	if (name == NULL)
		return names;
	names->psName = name;

	// for sfnt containers, we'll read the name table ourselves, not rely on Fontconfig
	if (FT_IS_SFNT(face)) {
		std::list<std::string>	familyNames;
		std::list<std::string>	subFamilyNames;
		FT_SfntName	nameRec;
		for (index = 0; index < FT_Get_Sfnt_Name_Count(face); ++index) {
			char*	utf8name = NULL;
			if (FT_Get_Sfnt_Name(face, index, &nameRec) != 0)
				continue;
			switch (nameRec.name_id) {
				case kFontFullName:
				case kFontFamilyName:
				case kFontStyleName:
				case kPreferredFamilyName:
				case kPreferredSubfamilyName:
					{
						bool	preferredName = false;
						if (nameRec.platform_id == TT_PLATFORM_MACINTOSH
								&& nameRec.encoding_id == TT_MAC_ID_ROMAN && nameRec.language_id == 0) {
							utf8name = convertToUtf8(macRomanConv, nameRec.string, nameRec.string_len);
							preferredName = true;
						}
						else if ((nameRec.platform_id == TT_PLATFORM_APPLE_UNICODE)
								|| (nameRec.platform_id == TT_PLATFORM_MICROSOFT))
							utf8name = convertToUtf8(utf16beConv, nameRec.string, nameRec.string_len);

						if (utf8name != NULL) {
							std::list<std::string>*	nameList = NULL;
							switch (nameRec.name_id) {
								case kFontFullName:
									nameList = &names->fullNames;
									break;
								case kFontFamilyName:
									nameList = &names->familyNames;
									break;
								case kFontStyleName:
									nameList = &names->styleNames;
									break;
								case kPreferredFamilyName:
									nameList = &familyNames;
									break;
								case kPreferredSubfamilyName:
									nameList = &subFamilyNames;
									break;
							}
							if (preferredName)
								prependToList(nameList, utf8name);
							else
								appendToList(nameList, utf8name);
						}
					}
					break;
			}
		}
		if (familyNames.size() > 0)
			names->familyNames = familyNames;
		if (subFamilyNames.size() > 0)
			names->styleNames = subFamilyNames;
	}
	else {
		index = 0;
		while (FcPatternGetString(pat, FC_FULLNAME, index++, (FcChar8**)&name) == FcResultMatch)
			appendToList(&names->fullNames, name);
		index = 0;
		while (FcPatternGetString(pat, FC_FAMILY, index++, (FcChar8**)&name) == FcResultMatch)
			appendToList(&names->familyNames, name);
		index = 0;
		while (FcPatternGetString(pat, FC_STYLE, index++, (FcChar8**)&name) == FcResultMatch)
			appendToList(&names->styleNames, name);

		if (names->fullNames.size() == 0) {
			std::string fullName(names->familyNames.front());
			if (names->styleNames.size() > 0) {
				fullName += " ";
				fullName += names->styleNames.front();
			}
			names->fullNames.push_back(fullName);
		}
	}

	FT_Done_Face(face);

	return names;
}
Example #11
0
static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
{
	// Variables
	FT_Face face;
	FT_ULong charcode = 0, lcode;
	FT_UInt glyph_index;
	const char *fontname;
	VFontData *vfd;

/*
	FT_CharMap  found = 0;
	FT_CharMap  charmap;
	FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
	FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
	int         n;
*/

	// load the freetype font
	err = FT_New_Memory_Face( library,
						pf->data,
						pf->size,
						0,
						&face );

	if(err) return NULL;
/*
	for ( n = 0; n < face->num_charmaps; n++ )
	{
		charmap = face->charmaps[n];
		if ( charmap->platform_id == my_platform_id &&
			charmap->encoding_id == my_encoding_id )
		{
			found = charmap;
			break;
		}
	}

	if ( !found ) { return NULL; }

	// now, select the charmap for the face object
	err = FT_Set_Charmap( face, found );
	if ( err ) { return NULL; }
*/

	// allocate blender font
	vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");

	// get the name
	fontname = FT_Get_Postscript_Name(face);
	strcpy(vfd->name, (fontname == NULL) ? "" : fontname);

	// Extract the first 256 character from TTF
	lcode= charcode= FT_Get_First_Char(face, &glyph_index);

	// No charmap found from the ttf so we need to figure it out
	if(glyph_index == 0)
	{
		FT_CharMap  found = NULL;
		FT_CharMap  charmap;
		int n;

		for ( n = 0; n < face->num_charmaps; n++ )
		{
			charmap = face->charmaps[n];
			if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
			{
				found = charmap;
				break;
			}
		}

		err = FT_Set_Charmap( face, found );

		if( err ) 
			return NULL;

		lcode= charcode= FT_Get_First_Char(face, &glyph_index);
	}

	// Load characters
	while(charcode < 256)
	{
		// Generate the font data
		freetypechar_to_vchar(face, charcode, vfd);

		// Next glyph
		charcode = FT_Get_Next_Char(face, charcode, &glyph_index);

		// Check that we won't start infinite loop
		if(charcode <= lcode)
			break;
		lcode = charcode;
	}

	return vfd;	
}
Example #12
0
int main(int argc, char **argv)
{
	char *fn;
	int  begin=0;
	int  end=255;
	int  size=10;
	int  cpl=0;
	int  cell=0;
	char autohinter=0;
	char seq=0;
	char alpha=0;
	char pack=0;

	FT_Library freetype;
	FT_Face    face;

	int  err;
	int  i;

	char *out_fn="font.png";

	char *def_fn=NULL;

	Font font;

	if(argc<2)
	{
		usage();
		return 1;
	}

	while((i=getopt(argc, argv, "r:s:l:c:o:atvh?ed:p"))!=-1)
	{
		char *ptr;
		int  temp;
		switch(i)
		{
		case 'r':
			if(!strcmp(optarg, "all"))
			{
				begin=0;
				end=0x110000;
			}
			else
			{
				if(!isdigit(optarg[0]))
					temp=-1;
				else
				{
					temp=strtol(optarg, &ptr, 0);
					if(ptr[0]!=',' || !isdigit(ptr[1]))
						temp=-1;
				}
				if(temp<0)
				{
					printf("Not a valid range: %s\n", optarg);
					exit(1);
				}
				else
				{
					begin=temp;
					end=strtol(ptr+1, NULL, 0);
				}
			}
			break;
		case 's':
			size=strtol(optarg, NULL, 0);
			break;
		case 'l':
			cpl=strtol(optarg, NULL, 0);
			break;
		case 'c':
			cell=strtol(optarg, NULL, 0);
			break;
		case 'o':
			out_fn=optarg;
			break;
		case 'a':
			autohinter=1;
			break;
		case 't':
			alpha=1;
			break;
		case 'v':
			++verbose;
			break;
		case 'h':
		case '?':
			usage();
			return 0;
		case 'e':
			seq=1;
			break;
		case 'd':
			def_fn=optarg;
			break;
		case 'p':
			pack=1;
			break;
		}
	}
	if(!strcmp(out_fn, "-"))
		verbose=0;

	if(optind!=argc-1)
	{
		usage();
		return 1;
	}
	
	fn=argv[optind];

	err=FT_Init_FreeType(&freetype);
	if(err)
	{
		fprintf(stderr, "Couldn't initialize FreeType library\n");
		return 1;
	}

	err=FT_New_Face(freetype, fn, 0, &face);
	if(err)
	{
		fprintf(stderr, "Couldn't load font file\n");
		if(err==FT_Err_Unknown_File_Format)
			fprintf(stderr, "Unknown file format\n");
		return 1;
	}

	if(verbose)
	{
		const char *name=FT_Get_Postscript_Name(face);
		printf("Font name: %s\n", name);
		printf("Glyphs:    %ld\n", face->num_glyphs);
	}

	err=FT_Set_Pixel_Sizes(face, 0, size);
	if(err)
	{
		fprintf(stderr, "Couldn't set size\n");
		return 1;
	}

	font.size=size;
	init_font(&font, face, begin, end, autohinter);
	if(pack)
		render_packed(&font);
	else
		render_grid(&font, cell, cpl, seq);
	save_png(out_fn, &font.image, alpha);
	if(def_fn)
		save_defs(def_fn, &font);

	for(i=0; i<font.n_glyphs; ++i)
		free(font.glyphs[i].image.data);
	free(font.glyphs);
	free(font.image.data);

	FT_Done_Face(face);
	FT_Done_FreeType(freetype);

	return 0;
}
Example #13
0
gfxfont_t* gfxfont_load(const char*id, const char*filename, unsigned int flags, double quality)
{
    FT_Face face;
    FT_Error error;
    const char* fontname = 0;
    FT_ULong charcode;
    FT_UInt gindex;
    gfxfont_t* font;
    int t;
    int*glyph2glyph = 0;
    int*glyph2unicode = 0;
    int max_unicode = 0;
    int charmap = -1;
    int isunicode = 1;
    int has_had_errors = 0;
    int num_names = 0;

    if(ftlibrary == 0) {
	if(FT_Init_FreeType(&ftlibrary)) {
	    fprintf(stderr, "Couldn't init freetype library!\n");
	    exit(1);
	}
    }
    error = FT_New_Face(ftlibrary, filename, 0, &face);
    FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
#ifdef DEBUG
    printf("gfxfont_load(%s, %s, %f)\n", id, filename, quality);
#endif

    if(error) {
	fprintf(stderr, "Couldn't load file %s- not a TTF file? (error=%02x)\n", filename, error);
	return 0;
    }
    if(face->num_glyphs <= 0) {
	fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs);
	return 0;
    }

    font = (gfxfont_t*)rfx_calloc(sizeof(gfxfont_t));
    //font->style =  ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
    //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
    //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
    //font->leading = font->layout->ascent + font->layout->descent;
    //font->encoding = FONT_ENCODING_UNICODE;
    font->max_unicode = 0;
    font->id = strdup(id);
    
    font->glyphs = (gfxglyph_t*)rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
    glyph2unicode = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
    glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));

    if(FT_HAS_GLYPH_NAMES(face)) {
	//font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
    }

    fontname = FT_Get_Postscript_Name(face);

#ifdef DEBUG
    for(t=0;t<face->num_charmaps;t++) {
        printf("possible encoding: %c%c%c%c (%d of %d)\n", 
                (face->charmaps[t]->encoding >> 24)&255,
                (face->charmaps[t]->encoding >> 16)&255,
                (face->charmaps[t]->encoding >> 8)&255,
                (face->charmaps[t]->encoding >> 0)&255,
                t+1, face->num_charmaps
                );
    }
#endif

    while(1) 
    {
	charcode = FT_Get_First_Char(face, &gindex);

	while(gindex != 0)
	{
	    if(gindex >= 0 && gindex<face->num_glyphs) {
		if(!glyph2unicode[gindex]) {
		    glyph2unicode[gindex] = charcode;
		    if(charcode + 1 > font->max_unicode) {
			font->max_unicode = charcode + 1;
		    }
		}
	    }
	    charcode = FT_Get_Next_Char(face, charcode, &gindex);
	}

#ifdef DEBUG
        if(face->charmap) {
            printf("ENCODING: %c%c%c%c (%d of %d) max_unicode=%d\n", 
                    (face->charmap->encoding >> 24)&255,
                    (face->charmap->encoding >> 16)&255,
                    (face->charmap->encoding >> 8)&255,
                    (face->charmap->encoding >> 0)&255,
                    charmap, face->num_charmaps, font->max_unicode
                    );
        } else {
const char* PdfFontMetricsFreetype::GetFontname() const
{
    const char*	s = FT_Get_Postscript_Name( m_pFace );
    return s ? s : "";
}
Example #15
0
SWFFONT* swf_LoadTrueTypeFont(const char*filename, char flashtype)
{
    FT_Face face;
    FT_Error error;
    const char* name = 0;
    FT_ULong charcode;
    FT_UInt gindex;
    SWFFONT* font;
    int t;
    int*glyph2glyph;
    int max_unicode = 0;
    int charmap = -1;

    if(ftlibrary == 0) {
	if(FT_Init_FreeType(&ftlibrary)) {
	    fprintf(stderr, "Couldn't init freetype library!\n");
	    exit(1);
	}
    }
    error = FT_New_Face(ftlibrary, filename, 0, &face);

    if(error || !face) {
	fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
	return 0;
    }
   
    int scale = flashtype?20:1;
    FT_Set_Pixel_Sizes (face, 16*loadfont_scale*scale, 16*loadfont_scale*scale);

    if(face->num_glyphs <= 0) {
	fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs);
	return 0;
    }

    font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
    font->id = -1;
    font->version = flashtype?3:2;

    font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
    font->layout->bounds = (SRECT*)rfx_calloc(face->num_glyphs*sizeof(SRECT));
    font->style =  ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0)
	          |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
    font->encoding = FONT_ENCODING_UNICODE;
    font->glyph2ascii = (U16*)rfx_calloc(face->num_glyphs*sizeof(U16));
    font->maxascii = 0;
    font->glyph = (SWFGLYPH*)rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH));
    if(FT_HAS_GLYPH_NAMES(face)) {
	font->glyphnames = (char**)rfx_calloc(face->num_glyphs*sizeof(char*));
    }
    
    font->layout->kerningcount = 0;
    
    name = face->family_name;
    if(!(name && *name))
        name = FT_Get_Postscript_Name(face);
    if(name && *name)
	font->name = (U8*)strdup(name);

    while(1) 
    {
    /*    // Map Glyphs to Unicode, version 1 (quick and dirty):
	int t;
	for(t=0;t<65536;t++) {
	    int index = FT_Get_Char_Index(face, t);
	    if(index>=0 && index<face->num_glyphs) {
		if(font->glyph2ascii[index]<0)
		    font->glyph2ascii[index] = t;
	    }
	}*/
	
	// Map Glyphs to Unicode, version 2 (much nicer):
	// (The third way would be the AGL algorithm, as proposed
	//  by Werner Lemberg on [email protected])

	charcode = FT_Get_First_Char(face, &gindex);
	while(gindex != 0)
	{
	    if(gindex >= 0 && gindex<face->num_glyphs) {
		if(!font->glyph2ascii[gindex]) {
		    font->glyph2ascii[gindex] = charcode;
		    if(charcode + 1 > font->maxascii) {
			font->maxascii = charcode + 1;
		    }
		}
	    }
	    charcode = FT_Get_Next_Char(face, charcode, &gindex);
	}

	/* if we didn't find a single encoding character, try
	   the font's charmaps instead. That usually means that
	   the encoding is no longer unicode. 
	   TODO: find a way to convert the encoding to unicode
	 */
	if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
	    charmap++;
	    FT_Set_Charmap(face, face->charmaps[charmap]);
	    font->encoding = 0;//anything but unicode FIXME
	} else 
	    break;
    }

    if(full_unicode)
	font->maxascii = 65535;
    
    font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
    
    for(t=0;t<font->maxascii;t++) {
	int g = FT_Get_Char_Index(face, t);
	if(!g || g>=face->num_glyphs)
	    g = -1;
	font->ascii2glyph[t] = g;
	if(g>=0) {
	    max_unicode = t+1;
	    if(!font->glyph2ascii[g]) {
		font->glyph2ascii[g] = t;
	    }
	}
    }
    font->maxascii = max_unicode;

    font->numchars = 0;

    glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));

    SRECT fontbbox = {0,0,0,0};

    for(t=0; t < face->num_glyphs; t++) {
	FT_Glyph glyph;
	FT_BBox bbox;
	char name[128];
	drawer_t draw;
	char hasname = 0;
	name[0]=0;
	if(FT_HAS_GLYPH_NAMES(face)) {
	    error = FT_Get_Glyph_Name(face, t, name, 127);
	    if(!error && name[0] && !strstr(name, "notdef")) {
		font->glyphnames[font->numchars] = strdup(name);
		hasname = 1;
	    }
	}
	if(!font->glyph2ascii[t] && !hasname && skip_unused) {
	    continue;
	}
	error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
	if(error) {
	    //tends to happen with some pdfs
	    fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error);
	    glyph=0;
	    if(skip_unused) 
		continue;
	} else {
	    error = FT_Get_Glyph(face->glyph, &glyph);
	    if(error) {
		fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
		glyph=0;
		if(skip_unused) 
		    continue;
	    }
	}

	if(glyph)
	    FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
	else
	    memset(&bbox, 0, sizeof(bbox));

	bbox.yMin = -bbox.yMin;
	bbox.yMax = -bbox.yMax;
	if(bbox.xMax < bbox.xMin) {
	    // swap
	    bbox.xMax ^= bbox.xMin;
	    bbox.xMin ^= bbox.xMax;
	    bbox.xMax ^= bbox.xMin;
	}
	if(bbox.yMax < bbox.yMin) {
	    // swap
	    bbox.yMax ^= bbox.yMin;
	    bbox.yMin ^= bbox.yMax;
	    bbox.yMax ^= bbox.yMin;
	}

	swf_Shape01DrawerInit(&draw, 0);

	//error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
	if(glyph)
	    error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
	else
	    error = 0;
	draw.finish(&draw);
	
	if(error) {
	    fprintf(stderr, "Couldn't decompose glyph %d\n", t);
	    draw.dealloc(&draw);
	    continue;
	}

#if 0
	if(bbox.xMin > 0) {
	    font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
	} else {
	    font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
	}
#else
	if(glyph)
	    font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
	else
	    font->glyph[font->numchars].advance = 0;
#endif
	
	SRECT b = swf_ShapeDrawerGetBBox(&draw);

	//font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
	//font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
	//font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
	//font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;

	font->layout->bounds[font->numchars] = b;
	font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);

	swf_ExpandRect2(&fontbbox, &font->layout->bounds[font->numchars]);

	draw.dealloc(&draw);

	if(glyph)
	    FT_Done_Glyph(glyph);
	font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
	glyph2glyph[t] = font->numchars;
	font->numchars++;
    }
    
    //font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
    //font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
    //font->layout->leading = font->layout->ascent + font->layout->descent;

    if(-fontbbox.ymin < 0)
        font->layout->ascent = 0;
    else
	font->layout->ascent = -fontbbox.ymin;

    if(fontbbox.ymax < 0)
        font->layout->descent = 0;
    else
	font->layout->descent = fontbbox.ymax;

    int leading = fontbbox.ymax - fontbbox.ymin;
    font->layout->leading = leading>0x7fff?0x7fff:leading;

    /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will 
	       have more memory allocated than just font->numchars, but only the first font->numchars 
	       are used/valid */

    for(t=0;t<font->maxascii;t++) {
	if(font->ascii2glyph[t]>=0) {
	    font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
	}
    }
    rfx_free(glyph2glyph);

    FT_Done_Face(face);
    FT_Done_FreeType(ftlibrary);ftlibrary=0;

    return font;
}
Example #16
0
unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int size)
{
    if ( descr == NULL ) {
        if ( size > 0 ) {
            str[0]=0;
        }
        return 0;
    }
    char*   res=NULL;
    bool    free_res=false;

    if ( strcmp(key,"name") == 0 ) {
        PangoFontDescription* td=pango_font_description_copy(descr);
        pango_font_description_unset_fields (td, PANGO_FONT_MASK_SIZE);
        res=pango_font_description_to_string (td);
        pango_font_description_free(td);
        free_res=true;
    } else if ( strcmp(key,"psname") == 0 ) {
#ifndef USE_PANGO_WIN32
         res = (char *) FT_Get_Postscript_Name (theFace); // that's the main method, seems to always work
#endif
         free_res=false;
         if (res == NULL) { // a very limited workaround, only bold, italic, and oblique will work
             PangoStyle style=pango_font_description_get_style(descr);
             bool i = (style == PANGO_STYLE_ITALIC);
             bool o = (style == PANGO_STYLE_OBLIQUE);
             PangoWeight weight=pango_font_description_get_weight(descr);
             bool b = (weight >= PANGO_WEIGHT_BOLD);

             res = g_strdup_printf ("%s%s%s%s",
                                    pango_font_description_get_family(descr),
                                    (b || i || o) ? "-" : "",
                                    (b) ? "Bold" : "",
                                    (i) ? "Italic" : ((o) ? "Oblique" : "")  );
             free_res = true;
         }
    } else if ( strcmp(key,"family") == 0 ) {
        res=(char*)pango_font_description_get_family(descr);
        free_res=false;
    } else if ( strcmp(key,"style") == 0 ) {
        PangoStyle v=pango_font_description_get_style(descr);
        if ( v == PANGO_STYLE_ITALIC ) {
            res=(char*)"italic";
        } else if ( v == PANGO_STYLE_OBLIQUE ) {
            res=(char*)"oblique";
        } else {
            res=(char*)"normal";
        }
        free_res=false;
    } else if ( strcmp(key,"weight") == 0 ) {
        PangoWeight v=pango_font_description_get_weight(descr);
        if ( v <= PANGO_WEIGHT_THIN ) {
            res=(char*)"100";
        } else if ( v <= PANGO_WEIGHT_ULTRALIGHT ) {
            res=(char*)"200";
        } else if ( v <= PANGO_WEIGHT_LIGHT ) {
            res=(char*)"300";
        } else if ( v <= PANGO_WEIGHT_BOOK ) {
            res=(char*)"380";
        } else if ( v <= PANGO_WEIGHT_NORMAL ) {
            res=(char*)"normal";
        } else if ( v <= PANGO_WEIGHT_MEDIUM ) {
            res=(char*)"500";
        } else if ( v <= PANGO_WEIGHT_SEMIBOLD ) {
            res=(char*)"600";
        } else if ( v <= PANGO_WEIGHT_BOLD ) {
            res=(char*)"bold";
        } else if ( v <= PANGO_WEIGHT_ULTRABOLD ) {
            res=(char*)"800";
        } else { // HEAVY   NB: Pango defines ULTRAHEAVY = 1000 but not CSS2
            res=(char*)"900";
        }
        free_res=false;
    } else if ( strcmp(key,"stretch") == 0 ) {
        PangoStretch v=pango_font_description_get_stretch(descr);
        if ( v <= PANGO_STRETCH_EXTRA_CONDENSED ) {
            res=(char*)"extra-condensed";
        } else if ( v <= PANGO_STRETCH_CONDENSED ) {
            res=(char*)"condensed";
        } else if ( v <= PANGO_STRETCH_SEMI_CONDENSED ) {
            res=(char*)"semi-condensed";
        } else if ( v <= PANGO_STRETCH_NORMAL ) {
            res=(char*)"normal";
        } else if ( v <= PANGO_STRETCH_SEMI_EXPANDED ) {
            res=(char*)"semi-expanded";
        } else if ( v <= PANGO_STRETCH_EXPANDED ) {
            res=(char*)"expanded";
        } else {
            res=(char*)"extra-expanded";
        }
        free_res=false;
    } else if ( strcmp(key,"variant") == 0 ) {
        PangoVariant v=pango_font_description_get_variant(descr);
        if ( v == PANGO_VARIANT_SMALL_CAPS ) {
            res=(char*)"small-caps";
        } else {
            res=(char*)"normal";
        }
        free_res=false;
    } else {
        res = NULL;
        free_res=false;
    }
    if ( res == NULL ) {
        if ( size > 0 ) {
            str[0] = 0;
        }
        return 0;
    }

    if (res) {
        unsigned int len=strlen(res);
        unsigned int rlen=(size-1<len)?size-1:len;
        if ( str ) {
            if ( rlen > 0 ) {
                memcpy(str, res, rlen);
            }
            if ( size > 0 ) {
                str[rlen] = 0;
            }
        }
        if (free_res) {
            g_free(res);
            res = 0;
        }
        return len;
    }
    return 0;
}