示例#1
0
文件: ftdump.c 项目: xahgo/tama
  void
  Print_Type( FT_Face  face )
  {
    FT_Module  module;


    printf( "font type entries\n" );

    module = &face->driver->root;
    printf( "   FreeType driver: %s\n", module->clazz->module_name );

    /* Is it better to dump all sfnt tag names? */
    printf( "   sfnt wrapped:    %s\n",
            FT_IS_SFNT( face ) ? (char *)"yes" : (char *)"no" );

    /* isScalable? */
    comma_flag = 0;
    printf( "   type:            " );
    if ( FT_IS_SCALABLE( face ) )
    {
      Print_Comma( "scalable" );
      if ( FT_HAS_MULTIPLE_MASTERS( face ) )
        Print_Comma( "multiple masters" );
    }
    if ( FT_HAS_FIXED_SIZES( face ) )
      Print_Comma( "fixed size" );
    printf( "\n" );

    /* Direction */
    comma_flag = 0;
    printf( "   direction:       " );
    if ( FT_HAS_HORIZONTAL( face ) )
      Print_Comma( "horizontal" );

    if ( FT_HAS_VERTICAL( face ) )
      Print_Comma( "vertical" );

    printf( "\n" );

    printf( "   fixed width:     %s\n",
            FT_IS_FIXED_WIDTH( face ) ? (char *)"yes" : (char *)"no" );

    printf( "   glyph names:     %s\n",
            FT_HAS_GLYPH_NAMES( face ) ? (char *)"yes" : (char *)"no" );

    if ( FT_IS_SCALABLE( face ) )
    {
      printf( "   EM size:         %d\n", face->units_per_EM );
      printf( "   global BBox:     (%ld,%ld):(%ld,%ld)\n",
              face->bbox.xMin, face->bbox.yMin,
              face->bbox.xMax, face->bbox.yMax );
      printf( "   ascent:          %d\n", face->ascender );
      printf( "   descent:         %d\n", face->descender );
      printf( "   text height:     %d\n", face->height );
    }
  }
示例#2
0
bool FreeTypeFont::hasVertical() const
{
    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(FreeTypeLibrary::instance()->getMutex());
    return FT_HAS_VERTICAL(_face)!=0;
}
示例#3
0
//
// Constructor:
//
FontFace::FontFace( FontLibrary &library, const std::string &fileName ){
	
	_fileName=fileName;
	
	//
	// By default report on fragmentary and partial orthographic
	// support in addition to fully supported orthographies:
	//
	_reportMissing     = true;
	_reportFragmentary = true;
	_reportPartial     = true;
	_reportFull        = true;

	_reportConscript   = false;
	
	FT_Error err;
	
	err = FT_New_Face(library.get(),_fileName.c_str(),0, &_face ); 
	if(err==FT_Err_Unknown_File_Format) throw Exception("FontFace()","Unknown file format.");
	else if(err) throw Exception("FontFace()","Unable to open or process font file.");
	//
	//
	//
	_commonName = _face->family_name;
	_subFamily  = _face->style_name;
	_glyphCount = _face->num_glyphs;
	
	if(FT_IS_SFNT(_face)){
		
		FT_UInt count=FT_Get_Sfnt_Name_Count(_face);
		
		FT_SfntName fontName;
		
		for(unsigned j=0;j<count;j++){
			
			FT_Get_Sfnt_Name(_face,j,&fontName);
			
			if(fontName.platform_id==3 && fontName.encoding_id==1){
				//
				// Microsoft 3:1 Platform:
				//
				if( fontName.language_id==0x0409 ){
					//
					// This is the de-facto
					// default AMERICAN ENGLISH
					// entry:
					//
					switch(fontName.name_id){
					case NID_FONT_FAMILY:
						if(_commonName.empty()) _commonName = _getPlatform3Encoding1String(fontName.string_len,fontName.string);
						break;
					case NID_FONT_SUBFAM:
						if(_subFamily.empty()) _subFamily   = _getPlatform3Encoding1String(fontName.string_len,fontName.string);
						break;
					case NID_VERSION:
						if(_version.empty()) _version       = _getPlatform3Encoding1String(fontName.string_len,fontName.string);
						break;
					case NID_VENDOR:
						if(_vendor.empty()) _vendor         = _getPlatform3Encoding1String(fontName.string_len,fontName.string);
						break;
					case NID_DESIGNER:
						if(_designer.empty()) _designer     = _getPlatform3Encoding1String(fontName.string_len,fontName.string);
						break;
					case NID_URL_VENDOR:
						if(_vendorURL.empty()) _vendorURL   = _getPlatform3Encoding1String(fontName.string_len,fontName.string);
						break;
					case NID_URL_DESIGNER:
						if(_designerURL.empty()) _designerURL = _getPlatform3Encoding1String(fontName.string_len,fontName.string);
						break;
					default:
						break;
					}
				}else{
					//
					// Some other language:
					// We take whatever the very first
					// other language is to be
					// our "nativeName" string:
					//
					switch(fontName.name_id){
					case NID_FONT_FAMILY:
						if(_nativeName.empty()) _nativeName = _getPlatform3Encoding1String(fontName.string_len,fontName.string);
						break;
					default:
						break;
					}
				}
				
				//
				// DEBUG
				//
				//if(fontName.name_id==NID_COPYRIGHT){
				//	// DEBUG:
				//	std::cout << ">>> COPYRIGHT: " << _getPlatform3Encoding1String(fontName.string_len,fontName.string) << std::endl;
				//}
				//if(fontName.name_id==NID_VERSION){
				//	// DEBUG:
				//	std::cout << ">>> VERSION     : " << _getPlatform3Encoding1String(fontName.string_len,fontName.string) << std::endl;
				//}
				
			}else if(fontName.platform_id==1 && fontName.encoding_id==0){
				//
				// Macintosh 1:0 platform: This is going to 
				// be English in the MacRoman encoding:
				//
				// NOTA BENE: We currently do not deal with
				// non-English Mac strings.  They seem to be 
				// very rare in real fonts out there in the world.
				//
				switch(fontName.name_id){
				case NID_FONT_FAMILY:
					if(_commonName.empty()) _commonName = _getPlatform1Encoding0String(fontName.string_len,fontName.string);
					break;
				case NID_FONT_SUBFAM:
					if(_subFamily.empty()) _subFamily   = _getPlatform1Encoding0String(fontName.string_len,fontName.string);
					break;
				case NID_VERSION:
					if(_version.empty()) _version       = _getPlatform1Encoding0String(fontName.string_len,fontName.string);
					break;
				case NID_VENDOR:
					if(_vendor.empty()) _vendor         = _getPlatform1Encoding0String(fontName.string_len,fontName.string);
					break;
				case NID_DESIGNER:
					if(_designer.empty()) _designer     = _getPlatform1Encoding0String(fontName.string_len,fontName.string);
					break;
				case NID_URL_VENDOR:
					if(_vendorURL.empty()) _vendorURL   = _getPlatform1Encoding0String(fontName.string_len,fontName.string);
					break;
				case NID_URL_DESIGNER:
					if(_designerURL.empty()) _designerURL = _getPlatform1Encoding0String(fontName.string_len,fontName.string);
					break;
				default:
					break;
				}
			}
			
			
		}
	}
	
	//
	// If native name is missing, fill it in:
	//
	//if(_nativeName.empty()) _nativeName = _commonName;
	
	_style=NORMAL;
	if( _face->style_flags & FT_STYLE_FLAG_ITALIC ) _style  = ITALIC;
	_weight=NORMAL_WEIGHT;
	if( _face->style_flags & FT_STYLE_FLAG_BOLD   ) _weight = BOLD;
	_isFixedWidth=FT_IS_FIXED_WIDTH(_face);
	
	
	
	//
	// Vertical metrics for Japanese, Chinese, Mongolian:
	//
	_hasVerticalMetrics = FT_HAS_VERTICAL(_face);
	//
	// Check for embedded bitmaps:
	//
	_hasFixedSizes = FT_HAS_FIXED_SIZES(_face);
	
	//
	// Get the set of unicode values this font covers
	//
	_getUnicodeValues();
	
	//
	// Check orthographic coverage:
	//
	//_checkOrthographies();
	
	//
	// Check license:
	//
	_checkLicenses();
	
}
示例#4
0
文件: Font.cpp 项目: mtwilliams/mojo
    bool Font::CreateFromFile( const char* path, const uint32_t font_size, const bool smooth, const uint32_t start_char, const size_t num_chars )
    {
        if( path == NULL || font_size == 0 || num_chars == 0 || _num_glyphs > 0 ) return false;

        Mojo::Services::Filesystem* filesystem = MOJO_GET_SERVICE(Filesystem);
        Mojo::Filesystem::File* file = filesystem->Open(path, Mojo::Filesystem::FILE_READ);
        if( !file ) return false;

        size_t file_len = filesystem->Length(file);
        if( file_len == 0 ) {
            filesystem->Close(file);
            return false;
        }

        // todo: Use FT_Open_Face to read the file instead?

        uint8_t* buffer = new uint8_t[file_len]; {
            uint32_t num_bytes_read = 0;
            while( num_bytes_read < file_len ) {
                size_t read = filesystem->Read(file, file_len - num_bytes_read, (void*)&buffer[num_bytes_read]);
                mojo_assertf(read > 0, "Font::CreateFromFile\n -> Services/Filesystem error?\n");
                num_bytes_read += read;
            }
        }

        filesystem->Close(file);

        FT_Face ft_face;
        if( FT_New_Memory_Face(Mojo::GetFreeTypeLibrary(), (const FT_Byte*)buffer, file_len, 0, &ft_face) ) {
            delete[] buffer;
            return false;
        }

        FT_Set_Char_Size(ft_face, font_size * 64, font_size * 64, 72, 72);

        const float line_height = ft_face->size->metrics.height >> 6;

        // Load the glyphs
        Font::Glyph*    glyphs       = new Font::Glyph[num_chars];
        FT_Glyph*       ft_glyphs    = new FT_Glyph[num_chars];
        FT_BitmapGlyph* bm_glyphs    = (FT_BitmapGlyph*)ft_glyphs;

        float blo = 0.0f;
        uint32_t bm_max_width = 0, bm_max_height = 0;
        for( uint32_t i = 0; i < num_chars; ++i ) {
            FT_Load_Char(ft_face, start_char + i, FT_LOAD_DEFAULT);
            FT_Get_Glyph(ft_face->glyph, &ft_glyphs[i]);

            glyphs[i].x_advance = ft_face->glyph->advance.x >> 6;
            glyphs[i].y_advance = ft_face->glyph->advance.y >> 6;
            glyphs[i].x_bearing = (FT_HAS_VERTICAL(ft_face) ? ft_face->glyph->metrics.vertBearingX : ft_face->glyph->metrics.horiBearingX) >> 6;
            glyphs[i].y_bearing = (FT_HAS_VERTICAL(ft_face) ? ft_face->glyph->metrics.vertBearingY : ft_face->glyph->metrics.horiBearingY) >> 6;
            
            FT_Glyph_To_Bitmap(&ft_glyphs[i], smooth ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1);

            const FT_Bitmap bitmap = bm_glyphs[i]->bitmap;
            glyphs[i].width  = bitmap.width;
            glyphs[i].height = bitmap.rows;

            bm_max_width  = bm_max_width < bitmap.width ? bitmap.width : bm_max_width;
            bm_max_height = bm_max_height < bitmap.rows ? bitmap.rows : bm_max_height;

            const float gbl = -glyphs[i].y_bearing + glyphs[i].height;
            blo = (blo < gbl) ? gbl : blo;
        }

        // Determine the texture atlas size
        uint32_t atlas_width = 0, atlas_height = 0; {
            static const struct { uint32_t width, height, area; } atlas_sizes[] = {
                {  64,  64,  64 *  64 }, { 128, 128, 128 * 128 },
                { 256, 256, 256 * 256 }, { 512, 512, 512 * 512 }
            };

            uint32_t min_area = 0;
            for( uint32_t i = 0; i < num_chars; ++i ) min_area += uint32_t((glyphs[i].width + 2) * (bm_max_height + 2));

            for( uint32_t i = 0; i < 4; ++i ) {
                if( atlas_sizes[i].area < min_area ) continue;

                const uint32_t index = (i > 3) ? 3 : i;
                atlas_width  = atlas_sizes[index].width;
                atlas_height = atlas_sizes[index].height;
                break;
            }

            if( atlas_width == 0 || atlas_height == 0 ) {
                for( uint32_t i = 0; i < num_chars; ++i ) FT_Done_Glyph(ft_glyphs[i]);
                delete[] ft_glyphs;
                delete[] glyphs;

                FT_Done_Face(ft_face);
                delete[] buffer;

                return false;
            }
        }

        Mojo::TextureAtlas tex_atlas = Mojo::TextureAtlas(atlas_width, atlas_height, 32);
        Mojo::BookshelfTexturePacker tex_packer = Mojo::BookshelfTexturePacker(&tex_atlas);

        uint8_t* bm_buffer = new uint8_t[bm_max_width * bm_max_height * 4];
        for( uint32_t i = 0; i < num_chars; ++i ) {
            const FT_Bitmap bitmap = bm_glyphs[i]->bitmap;
            if( bitmap.width == 0 || bitmap.rows == 0 ) continue;

            memset((void*)bm_buffer, 255, bm_max_width * bm_max_height * 4);

            switch( bitmap.pixel_mode ) {
                default: {
                    mojo_assertf(0, "Font::CreateFromFile()\n -> Pixel mode not supported.\n"); 
                } break;

                case FT_PIXEL_MODE_MONO: {
                    const uint8_t* bm_pixels = (const uint8_t*)bitmap.buffer;
                    const uint32_t y_offset = 0;

                    for( uint32_t y = 0; y < bitmap.rows; ++y ) {
                        for( uint32_t x = 0; x < bitmap.width; ++x ) bm_buffer[(x + y * bitmap.width) * 4 + 3] = ((bm_pixels[x / 8]) & (1 << (7 - (x % 8)))) ? 0xFF : 0x00;
                        bm_pixels += bitmap.pitch;
                    }
                } break;
                
                case FT_PIXEL_MODE_GRAY: {
                    const uint8_t* bm_pixels = (const uint8_t*)bitmap.buffer;

                    for( uint32_t y = 0; y < bitmap.rows; ++y ) {
                        for( uint32_t x = 0; x < bitmap.width; ++x ) bm_buffer[(x + y * bitmap.width) * 4 + 3] = bm_pixels[x];
                        bm_pixels += bitmap.pitch;
                    }
                } break;
            }

            Mojo::Recti packed_rect;
            if( !tex_packer.Pack(bitmap.width, bitmap.rows, 1, bm_buffer, packed_rect) ) {
                Mojo::DebugPrintf(DBG_WARNING, "Font::CreateFromFile()\n -> unable to pack character '%c'\n", i + start_char);              
            }

            glyphs[i].tex_coords[0] = (float)packed_rect.x / atlas_width;
            glyphs[i].tex_coords[1] = (float)packed_rect.y / atlas_height;
            glyphs[i].tex_coords[2] = (float)(packed_rect.x + packed_rect.width) / atlas_width;
            glyphs[i].tex_coords[3] = (float)(packed_rect.y + packed_rect.height) / atlas_height;
        }
        delete[] bm_buffer;

        // Unload the glyphs
        for( uint32_t i = 0; i < num_chars; ++i ) FT_Done_Glyph(ft_glyphs[i]);
        delete[] ft_glyphs;

        FT_Done_Face(ft_face);
        delete[] buffer;

        // Update
        _font_atlas  = tex_atlas.Compile();
        _start_glyph = start_char;
        _num_glyphs  = num_chars;
        _glyphs      = glyphs;
        _base_line   = bm_max_height - blo;
        _line_height = line_height;

        return true;
    }
示例#5
0
void font_instance::LoadGlyph(int glyph_id)
{
    if ( pFont == NULL ) {
        return;
    }
    InitTheFace();
#ifndef USE_PANGO_WIN32
    if ( !FT_IS_SCALABLE(theFace) ) {
        return; // bitmap font
    }
#endif

    if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
        Geom::PathBuilder path_builder;

        if ( nbGlyph >= maxGlyph ) {
            maxGlyph=2*nbGlyph+1;
            glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph));
        }
        font_glyph  n_g;
        n_g.pathvector=NULL;
        n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0;
        n_g.h_advance = 0;
        n_g.v_advance = 0;
        n_g.h_width = 0;
        n_g.v_width = 0;
        bool   doAdd=false;

#ifdef USE_PANGO_WIN32

#ifndef GGO_UNHINTED         // For compatibility with old SDKs.
#define GGO_UNHINTED 0x0100
#endif

        MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
        OUTLINETEXTMETRIC otm;
        GetOutlineTextMetrics(daddy->hScreenDC, sizeof(otm), &otm);
        GLYPHMETRICS metrics;
        DWORD bufferSize=GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity);
        double scale=1.0/daddy->fontSize;
        n_g.h_advance=metrics.gmCellIncX*scale;
        n_g.v_advance=otm.otmTextMetrics.tmHeight*scale;
        n_g.h_width=metrics.gmBlackBoxX*scale;
        n_g.v_width=metrics.gmBlackBoxY*scale;
        if ( bufferSize == GDI_ERROR) {
            // shit happened
        } else if ( bufferSize == 0) {
            // character has no visual representation, but is valid (eg whitespace)
            doAdd=true;
        } else {
            char *buffer = new char[bufferSize];
            if ( GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, bufferSize, buffer, &identity) <= 0 ) {
                // shit happened
            } else {
                // Platform SDK is rubbish, read KB87115 instead
                DWORD polyOffset=0;
                while ( polyOffset < bufferSize ) {
                    TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer+polyOffset);
                    if (polyOffset+polyHeader->cb > bufferSize) break;

                    if (polyHeader->dwType == TT_POLYGON_TYPE) {
                        path_builder.moveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale));
                        DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER);

                        while ( curveOffset < polyOffset+polyHeader->cb ) {
                            TTPOLYCURVE const *polyCurve=(TTPOLYCURVE const *)(buffer+curveOffset);
                            POINTFX const *p=polyCurve->apfx;
                            POINTFX const *endp=p+polyCurve->cpfx;

                            switch (polyCurve->wType) {
                            case TT_PRIM_LINE:
                                while ( p != endp )
                                    path_builder.lineTo(pointfx_to_nrpoint(*p++, scale));
                                break;

                            case TT_PRIM_QSPLINE:
                                {
                                    g_assert(polyCurve->cpfx >= 2);

                                    // The list of points specifies one or more control points and ends with the end point.
                                    // The intermediate points (on the curve) are the points between the control points.
                                    Geom::Point this_control = pointfx_to_nrpoint(*p++, scale);
                                    while ( p+1 != endp ) { // Process all "midpoints" (all points except the last)
                                        Geom::Point new_control = pointfx_to_nrpoint(*p++, scale);
                                        path_builder.quadTo(this_control, (new_control+this_control)/2);
                                        this_control = new_control;
                                    }
                                    Geom::Point end = pointfx_to_nrpoint(*p++, scale);
                                    path_builder.quadTo(this_control, end);
                                }
                                break;

                            case 3:  // TT_PRIM_CSPLINE
                                g_assert(polyCurve->cpfx % 3 == 0);
                                while ( p != endp ) {
                                    path_builder.curveTo(pointfx_to_nrpoint(p[0], scale),
                                                         pointfx_to_nrpoint(p[1], scale),
                                                         pointfx_to_nrpoint(p[2], scale));
                                    p += 3;
                                }
                                break;
                            }
                            curveOffset += sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(polyCurve->cpfx-1);
                        }
                    }
                    polyOffset += polyHeader->cb;
                }
                doAdd=true;
            }
            delete [] buffer;
        }
#else
        if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) {
            // shit happened
        } else {
            if ( FT_HAS_HORIZONTAL(theFace) ) {
                n_g.h_advance=((double)theFace->glyph->metrics.horiAdvance)/((double)theFace->units_per_EM);
                n_g.h_width=((double)theFace->glyph->metrics.width)/((double)theFace->units_per_EM);
            } else {
                n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM);
            }
            if ( FT_HAS_VERTICAL(theFace) ) {
                n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM);
                n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM);
            } else {
                n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM);
            }
            if ( theFace->glyph->format == ft_glyph_format_outline ) {
                FT_Outline_Funcs ft2_outline_funcs = {
                    ft2_move_to,
                    ft2_line_to,
                    ft2_conic_to,
                    ft2_cubic_to,
                    0, 0
                };
                FT2GeomData user(path_builder, 1.0/((double)theFace->units_per_EM));
                FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &user);
            }
            doAdd=true;
        }
#endif
        path_builder.finish();

        if ( doAdd ) {
            Geom::PathVector pv = path_builder.peek();
            // close all paths
            for (Geom::PathVector::iterator i = pv.begin(); i != pv.end(); ++i) {
                i->close();
            }
            if ( !pv.empty() ) {
                n_g.pathvector = new Geom::PathVector(pv);
                Geom::OptRect bounds = bounds_exact(*n_g.pathvector);
                if (bounds) {
                    n_g.bbox[0] = bounds->left();
                    n_g.bbox[1] = bounds->top();
                    n_g.bbox[2] = bounds->right();
                    n_g.bbox[3] = bounds->bottom();
                }
            }
            glyphs[nbGlyph]=n_g;
            id_to_no[glyph_id]=nbGlyph;
            nbGlyph++;
        }
    } else {
    }
}