//------------------------------------------------------------------------ bool font_engine_freetype_base::load_font(const char* font_name, unsigned face_index, glyph_rendering ren_type, const char* font_mem, const long font_mem_size) { bool ret = false; if(m_library_initialized) { m_last_error = 0; int idx = find_face(font_name); if(idx >= 0) { m_cur_face = m_faces[idx]; m_name = m_face_names[idx]; } else { if(m_num_faces >= m_max_faces) { delete [] m_face_names[0]; FT_Done_Face(m_faces[0]); memcpy(m_faces, m_faces + 1, (m_max_faces - 1) * sizeof(FT_Face)); memcpy(m_face_names, m_face_names + 1, (m_max_faces - 1) * sizeof(char*)); m_num_faces = m_max_faces - 1; } if (font_mem && font_mem_size) { m_last_error = FT_New_Memory_Face(m_library, (const FT_Byte*)font_mem, font_mem_size, face_index, &m_faces[m_num_faces]); } else { m_last_error = FT_New_Face(m_library, font_name, face_index, &m_faces[m_num_faces]); } if(m_last_error == 0) { m_face_names[m_num_faces] = new char [strlen(font_name) + 1]; strcpy(m_face_names[m_num_faces], font_name); m_cur_face = m_faces[m_num_faces]; m_name = m_face_names[m_num_faces]; ++m_num_faces; } else { m_face_names[m_num_faces] = 0; m_cur_face = 0; m_name = 0; } } if(m_last_error == 0) { ret = true; switch(ren_type) { case glyph_ren_native_mono: m_glyph_rendering = glyph_ren_native_mono; break; case glyph_ren_native_gray8: m_glyph_rendering = glyph_ren_native_gray8; break; case glyph_ren_outline: if(FT_IS_SCALABLE(m_cur_face)) { m_glyph_rendering = glyph_ren_outline; } else { m_glyph_rendering = glyph_ren_native_gray8; } break; case glyph_ren_agg_mono: if(FT_IS_SCALABLE(m_cur_face)) { m_glyph_rendering = glyph_ren_agg_mono; } else { m_glyph_rendering = glyph_ren_native_mono; } break; case glyph_ren_agg_gray8: if(FT_IS_SCALABLE(m_cur_face)) { m_glyph_rendering = glyph_ren_agg_gray8; } else { m_glyph_rendering = glyph_ren_native_gray8; } break; } update_signature(); } } return ret; }
EFontFT2::EFontFT2(const EEntry *entry, eint32 faceIndex) : EFontEngine(), fFilename(NULL), fFaceIndex(-1), nFaces(-1), fFace(NULL), fScalable(false), fForceFontAliasing(false) { EPath aPath; if(entry == NULL || entry->Exists() == false || entry->GetPath(&aPath) != E_OK) return; EString filename = aPath.Path(); #ifdef _WIN32 filename.ReplaceAll("/", "\\"); #endif SetRenderMode(E_FONT_RENDER_PIXMAP); EAutolock <ELocker> autolock(&etk_ft2_font_locker); if(!_etk_ft2_initialized_) return; FT_Error error = FT_New_Face(_etk_ft2_library_, filename.String(), faceIndex, &fFace); if(error || !fFace) { ETK_DEBUG("[FONT]: %s --- CAN NOT load face[%s:%d].", __PRETTY_FUNCTION__, aPath.Path(), faceIndex); return; } if(FT_Select_Charmap(fFace, FT_ENCODING_UNICODE)) { // ETK_DEBUG("[FONT]: %s --- font[%s] don't support ENCODING_UNICODE.", __PRETTY_FUNCTION__, aPath.Path()); if(FT_Select_Charmap(fFace, FT_ENCODING_NONE)) { // ETK_WARNING("[FONT]: %s --- font[%s] don't support unicode at all.", __PRETTY_FUNCTION__, aPath.Path()); FT_Done_Face(fFace); fFace = NULL; return; } } fFilename = EStrdup(filename.String()); fFaceIndex = faceIndex; nFaces = fFace->num_faces; EString family = fFace->family_name; if(family.Length() <= 0) { family = aPath.Leaf(); eint32 cFound; if((cFound = family.FindFirst('.')) >= 0) family.Remove(cFound, -1); if(family.Length() < 0) family = "Unknown"; } SetFamily(family.String()); EString style = fFace->style_name; if(style.Length() <= 0) { if((fFace->style_flags & FT_STYLE_FLAG_BOLD) && (fFace->style_flags & FT_STYLE_FLAG_ITALIC)) style = "Bold Italic"; else if(fFace->style_flags & FT_STYLE_FLAG_BOLD) style = "Bold"; else if(fFace->style_flags & FT_STYLE_FLAG_ITALIC) style = "Italic"; else style = "Regular"; } SetStyle(style.String()); if(FT_IS_SCALABLE(fFace)) fScalable = true; if(fFace->num_fixed_sizes > 0) { float *sizes = new float[(int)fFace->num_fixed_sizes]; for(int i = 0; i < fFace->num_fixed_sizes; i++) sizes[i] = (float)(fFace->available_sizes[i].height); SetFixedSize(sizes, (eint32)fFace->num_fixed_sizes); delete[] sizes; } FT_Done_Face(fFace); fFace = NULL; }
// ----------------------------------------------- texture_font_load_glyphs --- size_t texture_font_load_glyphs( texture_font_t * self, const wchar_t * charcodes ) { assert( self ); assert( charcodes ); size_t i, x, y, width, height, depth, w, h; FT_Library library; FT_Error error; FT_Face face; FT_Glyph ft_glyph; FT_GlyphSlot slot; FT_Bitmap ft_bitmap; FT_UInt glyph_index; texture_glyph_t *glyph; ivec4 region; size_t missed = 0; width = self->atlas->width; height = self->atlas->height; depth = self->atlas->depth; if( !texture_font_load_face( &library, self->filename, self->size, &face ) ) { return wcslen(charcodes); } /* Load each glyph */ for( i=0; i<wcslen(charcodes); ++i ) { glyph_index = FT_Get_Char_Index( face, charcodes[i] ); // WARNING: We use texture-atlas depth to guess if user wants // LCD subpixel rendering FT_Int32 flags = 0; if( self->outline_type > 0 ) { flags |= FT_LOAD_NO_BITMAP; } else { flags |= FT_LOAD_RENDER; } if( !self->hinting ) { flags |= FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT; } else { flags |= FT_LOAD_FORCE_AUTOHINT; } if( depth == 3 ) { FT_Library_SetLcdFilter( library, FT_LCD_FILTER_LIGHT ); flags |= FT_LOAD_TARGET_LCD; if( self->filtering ) { FT_Library_SetLcdFilterWeights( library, self->lcd_weights ); } } error = FT_Load_Glyph( face, glyph_index, flags ); if( error ) { fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_FreeType( library ); return wcslen(charcodes)-i; } int ft_bitmap_width = 0; int ft_bitmap_rows = 0; int ft_bitmap_pitch = 0; int ft_glyph_top = 0; int ft_glyph_left = 0; if( self->outline_type == 0 ) { slot = face->glyph; ft_bitmap = slot->bitmap; ft_bitmap_width = slot->bitmap.width; ft_bitmap_rows = slot->bitmap.rows; ft_bitmap_pitch = slot->bitmap.pitch; ft_glyph_top = slot->bitmap_top; ft_glyph_left = slot->bitmap_left; } else { FT_Stroker stroker; error = FT_Stroker_New( library, &stroker ); if( error ) { fprintf(stderr, "FT_Error (0x%02x) : %s\n", FT_Errors[error].code, FT_Errors[error].message); return 0; } FT_Stroker_Set( stroker, (int)(self->outline_thickness *64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); error = FT_Get_Glyph( face->glyph, &ft_glyph); if( error ) { fprintf(stderr, "FT_Error (0x%02x) : %s\n", FT_Errors[error].code, FT_Errors[error].message); return 0; } if( self->outline_type == 1 ) { error = FT_Glyph_Stroke( &ft_glyph, stroker, 1 ); } else if ( self->outline_type == 2 ) { error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 0, 1 ); } else if ( self->outline_type == 3 ) { error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 1, 1 ); } if( error ) { fprintf(stderr, "FT_Error (0x%02x) : %s\n", FT_Errors[error].code, FT_Errors[error].message); return 0; } if( depth == 1) { error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_NORMAL, 0, 1); if( error ) { fprintf(stderr, "FT_Error (0x%02x) : %s\n", FT_Errors[error].code, FT_Errors[error].message); return 0; } } else { error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_LCD, 0, 1); if( error ) { fprintf(stderr, "FT_Error (0x%02x) : %s\n", FT_Errors[error].code, FT_Errors[error].message); return 0; } } FT_BitmapGlyph ft_bitmap_glyph = (FT_BitmapGlyph) ft_glyph; ft_bitmap = ft_bitmap_glyph->bitmap; ft_bitmap_width = ft_bitmap.width; ft_bitmap_rows = ft_bitmap.rows; ft_bitmap_pitch = ft_bitmap.pitch; ft_glyph_top = ft_bitmap_glyph->top; ft_glyph_left = ft_bitmap_glyph->left; FT_Stroker_Done(stroker); } // We want each glyph to be separated by at least one black pixel // (for example for shader used in demo-subpixel.c) w = ft_bitmap_width/depth + 1; h = ft_bitmap_rows + 1; region = texture_atlas_get_region( self->atlas, w, h ); if ( region.x < 0 ) { missed++; fprintf( stderr, "Texture atlas is full (line %d)\n", __LINE__ ); continue; } w = w - 1; h = h - 1; x = region.x; y = region.y; texture_atlas_set_region( self->atlas, x, y, w, h, ft_bitmap.buffer, ft_bitmap.pitch ); glyph = texture_glyph_new( ); glyph->charcode = charcodes[i]; glyph->width = w; glyph->height = h; glyph->outline_type = self->outline_type; glyph->outline_thickness = self->outline_thickness; glyph->offset_x = ft_glyph_left; glyph->offset_y = ft_glyph_top; glyph->s0 = x/(float)width; glyph->t0 = y/(float)height; glyph->s1 = (x + glyph->width)/(float)width; glyph->t1 = (y + glyph->height)/(float)height; // Discard hinting to get advance FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING); slot = face->glyph; glyph->advance_x = slot->advance.x/64.0; glyph->advance_y = slot->advance.y/64.0; vector_push_back( self->glyphs, &glyph ); if( self->outline_type > 0 ) { FT_Done_Glyph( ft_glyph ); } } FT_Done_Face( face ); FT_Done_FreeType( library ); texture_atlas_upload( self->atlas ); texture_font_generate_kerning( self ); return missed; }
void tst_QScriptEngine::malayalam() { { FT_Face face = loadFace("AkrutiMal2Normal.ttf"); if (face) { const ShapeTable shape_table [] = { { { 0x0d15, 0x0d46, 0x0 }, { 0x005e, 0x0034, 0x0 } }, { { 0x0d15, 0x0d47, 0x0 }, { 0x005f, 0x0034, 0x0 } }, { { 0x0d15, 0x0d4b, 0x0 }, { 0x005f, 0x0034, 0x0058, 0x0 } }, { { 0x0d15, 0x0d48, 0x0 }, { 0x0060, 0x0034, 0x0 } }, { { 0x0d15, 0x0d4a, 0x0 }, { 0x005e, 0x0034, 0x0058, 0x0 } }, { { 0x0d30, 0x0d4d, 0x0d15, 0x0 }, { 0x009e, 0x0034, 0x0 } }, { { 0x0d15, 0x0d4d, 0x0d35, 0x0 }, { 0x0034, 0x007a, 0x0 } }, { { 0x0d15, 0x0d4d, 0x0d2f, 0x0 }, { 0x0034, 0x00a2, 0x0 } }, { { 0x0d1f, 0x0d4d, 0x0d1f, 0x0 }, { 0x0069, 0x0 } }, { { 0x0d26, 0x0d4d, 0x0d26, 0x0 }, { 0x0074, 0x0 } }, { { 0x0d30, 0x0d4d, 0x0 }, { 0x009e, 0x0 } }, { { 0x0d30, 0x0d4d, 0x200c, 0x0 }, { 0x009e, 0x0 } }, { { 0x0d30, 0x0d4d, 0x200d, 0x0 }, { 0x009e, 0x0 } }, { { 0xd15, 0xd46, 0xd3e, 0x0 }, { 0x5e, 0x34, 0x58, 0x0 } }, { { 0xd15, 0xd47, 0xd3e, 0x0 }, { 0x5f, 0x34, 0x58, 0x0 } }, { { 0xd15, 0xd46, 0xd57, 0x0 }, { 0x5e, 0x34, 0x65, 0x0 } }, { { 0xd15, 0xd57, 0x0 }, { 0x34, 0x65, 0x0 } }, { { 0xd1f, 0xd4d, 0xd1f, 0xd41, 0xd4d, 0x0 }, { 0x69, 0x5b, 0x64, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Malayalam) ); ++s; } FT_Done_Face(face); } else { QSKIP("couln't find AkrutiMal2Normal.ttf"); } } { FT_Face face = loadFace("Rachana.ttf"); if (face) { const ShapeTable shape_table [] = { { { 0xd37, 0xd4d, 0xd1f, 0xd4d, 0xd30, 0xd40, 0x0 }, { 0x385, 0xa3, 0x0 } }, { { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 }, { 0x2ff, 0x0 } }, { { 0xd33, 0xd4d, 0xd33, 0x0 }, { 0x3f8, 0x0 } }, { { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 }, { 0x2ff, 0x0 } }, { { 0xd30, 0xd4d, 0x200d, 0xd35, 0xd4d, 0xd35, 0x0 }, { 0xf3, 0x350, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Malayalam) ); ++s; } FT_Done_Face(face); } else { QSKIP("couln't find Rachana.ttf"); } } }
void tst_QScriptEngine::bengali() { { FT_Face face = loadFace("AkaashNormal.ttf"); if (face) { const ShapeTable shape_table [] = { // Ka { { 0x0995, 0x0 }, { 0x0151, 0x0 } }, // Ka Halant { { 0x0995, 0x09cd, 0x0 }, { 0x0151, 0x017d, 0x0 } }, // Ka Halant Ka { { 0x0995, 0x09cd, 0x0995, 0x0 }, { 0x019b, 0x0 } }, // Ka MatraI { { 0x0995, 0x09bf, 0x0 }, { 0x0173, 0x0151, 0x0 } }, // Ra Halant Ka { { 0x09b0, 0x09cd, 0x0995, 0x0 }, { 0x0151, 0x0276, 0x0 } }, // Ra Halant Ka MatraI { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 }, { 0x0173, 0x0151, 0x0276, 0x0 } }, // Ka Nukta { { 0x0995, 0x09bc, 0x0 }, { 0x0151, 0x0171, 0x0 } }, // Ka Halant Ra { { 0x0995, 0x09cd, 0x09b0, 0x0 }, { 0x01f4, 0x0 } }, // Ka Halant Ra Halant Ka { { 0x0995, 0x09cd, 0x09b0, 0x09cd, 0x0995, 0x0 }, { 0x025c, 0x0276, 0x0151, 0x0 } }, // Ya + Halant { { 0x09af, 0x09cd, 0x0 }, { 0x016a, 0x017d, 0x0 } }, // Da Halant Ya -> Da Ya-Phala { { 0x09a6, 0x09cd, 0x09af, 0x0 }, { 0x01e5, 0x0 } }, // A Halant Ya -> A Ya-phala { { 0x0985, 0x09cd, 0x09af, 0x0 }, { 0x0145, 0x01cf, 0x0 } }, // Na Halant Ka { { 0x09a8, 0x09cd, 0x0995, 0x0 }, { 0x026f, 0x0151, 0x0 } }, // Na Halant ZWNJ Ka { { 0x09a8, 0x09cd, 0x200c, 0x0995, 0x0 }, { 0x0164, 0x017d, 0x0151, 0x0 } }, // Na Halant ZWJ Ka { { 0x09a8, 0x09cd, 0x200d, 0x0995, 0x0 }, { 0x026f, 0x0151, 0x0 } }, // Ka Halant ZWNJ Ka { { 0x0995, 0x09cd, 0x200c, 0x0995, 0x0 }, { 0x0151, 0x017d, 0x0151, 0x0 } }, // Ka Halant ZWJ Ka { { 0x0995, 0x09cd, 0x200d, 0x0995, 0x0 }, { 0x025c, 0x0151, 0x0 } }, // Na Halant Ra { { 0x09a8, 0x09cd, 0x09b0, 0x0 }, { 0x0207, 0x0 } }, // Na Halant ZWNJ Ra { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 }, { 0x0164, 0x017d, 0x016b, 0x0 } }, // Na Halant ZWJ Ra { { 0x09a8, 0x09cd, 0x200d, 0x09b0, 0x0 }, { 0x026f, 0x016b, 0x0 } }, // Na Halant Ba { { 0x09a8, 0x09cd, 0x09ac, 0x0 }, { 0x022f, 0x0 } }, // Na Halant ZWNJ Ba { { 0x09a8, 0x09cd, 0x200c, 0x09ac, 0x0 }, { 0x0164, 0x017d, 0x0167, 0x0 } }, // Na Halant ZWJ Ba { { 0x09a8, 0x09cd, 0x200d, 0x09ac, 0x0 }, { 0x026f, 0x0167, 0x0 } }, // Na Halant Dha { { 0x09a8, 0x09cd, 0x09a7, 0x0 }, { 0x01d3, 0x0 } }, // Na Halant ZWNJ Dha { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 }, { 0x0164, 0x017d, 0x0163, 0x0 } }, // Na Halant ZWJ Dha { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 }, { 0x026f, 0x0163, 0x0 } }, // Ra Halant Ka MatraAU { { 0x09b0, 0x09cd, 0x0995, 0x09cc, 0x0 }, { 0x0179, 0x0151, 0x0276, 0x017e, 0x0 } }, // Ra Halant Ba Halant Ba { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 }, { 0x0232, 0x0276, 0x0 } }, { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x982, 0x0 }, { 0x151, 0x276, 0x172, 0x143, 0x0 } }, { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x983, 0x0 }, { 0x151, 0x276, 0x172, 0x144, 0x0 } }, // test decomposed two parts matras { { 0x995, 0x9c7, 0x9be, 0x0 }, { 0x179, 0x151, 0x172, 0x0 } }, { { 0x995, 0x9c7, 0x9d7, 0x0 }, { 0x179, 0x151, 0x17e, 0x0 } }, { { 0x9b0, 0x9cd, 0x9ad, 0x0 }, { 0x168, 0x276, 0x0 } }, { { 0x9f0, 0x9cd, 0x9ad, 0x0 }, { 0x168, 0x276, 0x0 } }, { { 0x9f1, 0x9cd, 0x9ad, 0x0 }, { 0x191, 0x17d, 0x168, 0x0 } }, // Ra ZWJ Halant Ya { { 0x09b0, 0x200d, 0x09cd, 0x09af, 0x0 }, { 0x016b, 0x01cf, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Bengali) ); ++s; } FT_Done_Face(face); } else { QSKIP("couln't find AkaashNormal.ttf"); } } { FT_Face face = loadFace("MuktiNarrow.ttf"); if (face) { const ShapeTable shape_table [] = { // Ka { { 0x0995, 0x0 }, { 0x0073, 0x0 } }, // Ka Halant { { 0x0995, 0x09cd, 0x0 }, { 0x00b9, 0x0 } }, // Ka Halant Ka { { 0x0995, 0x09cd, 0x0995, 0x0 }, { 0x0109, 0x0 } }, // Ka MatraI { { 0x0995, 0x09bf, 0x0 }, { 0x0095, 0x0073, 0x0 } }, // Ra Halant Ka { { 0x09b0, 0x09cd, 0x0995, 0x0 }, { 0x0073, 0x00e1, 0x0 } }, // Ra Halant Ka MatraI { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 }, { 0x0095, 0x0073, 0x00e1, 0x0 } }, // MatraI { { 0x09bf, 0x0 }, { 0x0095, 0x01c8, 0x0 } }, // Ka Nukta { { 0x0995, 0x09bc, 0x0 }, { 0x0073, 0x0093, 0x0 } }, // Ka Halant Ra { { 0x0995, 0x09cd, 0x09b0, 0x0 }, { 0x00e5, 0x0 } }, // Ka Halant Ra Halant Ka { { 0x995, 0x9cd, 0x9b0, 0x9cd, 0x995, 0x0 }, { 0x234, 0x24e, 0x73, 0x0 } }, // Ya + Halant { { 0x09af, 0x09cd, 0x0 }, { 0x00d2, 0x0 } }, // Da Halant Ya -> Da Ya-Phala { { 0x09a6, 0x09cd, 0x09af, 0x0 }, { 0x0084, 0x00e2, 0x0 } }, // A Halant Ya -> A Ya-phala { { 0x0985, 0x09cd, 0x09af, 0x0 }, { 0x0067, 0x00e2, 0x0 } }, // Na Halant Ka { { 0x09a8, 0x09cd, 0x0995, 0x0 }, { 0x0188, 0x0 } }, // Na Halant ZWNJ Ka { { 0x9a8, 0x9cd, 0x200c, 0x995, 0x0 }, { 0xcc, 0x73, 0x0 } }, // Na Halant ZWJ Ka { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 }, { 0x247, 0x73, 0x0 } }, // Ka Halant ZWNJ Ka { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 }, { 0x247, 0x73, 0x0 } }, // Ka Halant ZWJ Ka { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 }, { 0x247, 0x73, 0x0 } }, // Na Halant Ra { { 0x09a8, 0x09cd, 0x09b0, 0x0 }, { 0x00f8, 0x0 } }, // Na Halant ZWNJ Ra { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 }, { 0xcc, 0x8d, 0x0 } }, // Na Halant ZWJ Ra { { 0x9a8, 0x9cd, 0x200d, 0x9b0, 0x0 }, { 0x247, 0x8d, 0x0 } }, // Na Halant Ba { { 0x09a8, 0x09cd, 0x09ac, 0x0 }, { 0x0139, 0x0 } }, // Na Halant ZWNJ Ba { { 0x9a8, 0x9cd, 0x200c, 0x9ac, 0x0 }, { 0xcc, 0x89, 0x0 } }, // Na Halant ZWJ Ba { { 0x9a8, 0x9cd, 0x200d, 0x9ac, 0x0 }, { 0x247, 0x89, 0x0 } }, // Na Halant Dha { { 0x09a8, 0x09cd, 0x09a7, 0x0 }, { 0x0145, 0x0 } }, // Na Halant ZWNJ Dha { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 }, { 0xcc, 0x85, 0x0 } }, // Na Halant ZWJ Dha { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 }, { 0x247, 0x85, 0x0 } }, // Ra Halant Ka MatraAU { { 0x9b0, 0x9cd, 0x995, 0x9cc, 0x0 }, { 0x232, 0x73, 0xe1, 0xa0, 0x0 } }, // Ra Halant Ba Halant Ba { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 }, { 0x013b, 0x00e1, 0x0 } }, // Init feature for vowel sign E should only be // applied when it's initial character (QTBUG-13620) { { 0x09a8, 0x09c7, 0x0 }, { 0x0232, 0x0086, 0x0 } }, { { 0x09a8, 0x09a8, 0x09c7, 0x0 }, { 0x0086, 0x009b, 0x0086, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Bengali) ); ++s; } FT_Done_Face(face); } else { QSKIP("couln't find MuktiNarrow.ttf"); } } { FT_Face face = loadFace("LikhanNormal.ttf"); if (face) { const ShapeTable shape_table [] = { { { 0x09a8, 0x09cd, 0x09af, 0x0 }, { 0x01ca, 0x0 } }, { { 0x09b8, 0x09cd, 0x09af, 0x0 }, { 0x020e, 0x0 } }, { { 0x09b6, 0x09cd, 0x09af, 0x0 }, { 0x01f4, 0x0 } }, { { 0x09b7, 0x09cd, 0x09af, 0x0 }, { 0x01fe, 0x0 } }, { { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0x0 }, { 0x10b, 0x167, 0x0 } }, { { 0x9b0, 0x9cd, 0x9ad, 0x0 }, { 0xa1, 0x167, 0x0 } }, { { 0x9f0, 0x9cd, 0x9ad, 0x0 }, { 0xa1, 0x167, 0x0 } }, { { 0x9f1, 0x9cd, 0x9ad, 0x0 }, { 0x11c, 0xa1, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Bengali) ); ++s; } FT_Done_Face(face); } else { QSKIP("couln't find LikhanNormal.ttf"); } } }
Font::~Font() { FT_Done_Face(face); glDeleteTextures(1, &textureID); }
static inline void closeFont (void) { hb_font_destroy (hb_font); FT_Done_Face (ft_face); }
/* ------------------------------------------------------------------------- */ void texture_font_generate_kerning( TextureFont *self ) { size_t i, j, k, count; FT_Library library; FT_Face face; FT_UInt glyph_index, prev_index; TextureGlyph *glyph, *prev_glyph; FT_Vector kerning; /* Load font */ if( !texture_font_load_face( &library, self->filename, self->size, &face ) ) { return; } /* For each glyph couple combination, check if kerning is necessary */ for( i=0; i<self->glyphs->size; ++i ) { glyph = (TextureGlyph *) vector_get( self->glyphs, i ); /* Remove any old kerning information */ if( glyph->kerning ) { free( glyph->kerning ); glyph->kerning = 0; glyph->kerning_count = 0; } /* Count how many kerning pairs we need */ count = 0; glyph_index = FT_Get_Char_Index( face, glyph->charcode ); for( j=0; j<self->glyphs->size; ++j ) { prev_glyph = (TextureGlyph *) vector_get( self->glyphs, j ); prev_index = FT_Get_Char_Index( face, prev_glyph->charcode ); FT_Get_Kerning( face, prev_index, glyph_index, FT_KERNING_UNFITTED, &kerning ); if( kerning.x != 0.0 ) { count++; } } /* No kerning at all */ if( !count ) { continue; } /* Store kerning pairs */ glyph->kerning = (KerningPair *) malloc( count * sizeof(KerningPair) ); glyph->kerning_count = count; k = 0; for( j=0; j<self->glyphs->size; ++j ) { prev_glyph = (TextureGlyph *) vector_get( self->glyphs, j ); prev_index = FT_Get_Char_Index( face, prev_glyph->charcode ); FT_Get_Kerning( face, prev_index, glyph_index, FT_KERNING_UNFITTED, &kerning ); if( kerning.x != 0.0 ) { glyph->kerning[k].charcode = prev_glyph->charcode; // 64 * 64 because of 26.6 encoding AND the transform matrix used // in texture_font_load_face (hres = 64) glyph->kerning[k].kerning = kerning.x/ (float)(64.0f*64.0f); ++k; } } } FT_Done_Face( face ); FT_Done_FreeType( library ); }
/* ------------------------------------------------------------------------- */ size_t texture_font_cache_glyphs( TextureFont *self, wchar_t * charcodes ) { size_t i, x, y, width, height, depth, w, h; FT_Library library; FT_Error error; FT_Face face; FT_GlyphSlot slot; FT_UInt glyph_index; TextureGlyph *glyph; Region region; unsigned char c; size_t missed = 0; width = self->atlas->width; height = self->atlas->height; depth = self->atlas->depth; if( !texture_font_load_face( &library, self->filename, self->size, &face ) ) { return wcslen(charcodes); } /* Load each glyph */ for( i=0; i<wcslen(charcodes); ++i ) { glyph_index = FT_Get_Char_Index( face, charcodes[i] ); // WARNING: We use texture-atlas depth to guess if user wants // LCD subpixel rendering FT_Int32 flags = FT_LOAD_RENDER; if( !self->hinting ) { flags |= FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT; } else { flags |= FT_LOAD_FORCE_AUTOHINT; } if( depth == 3 ) { FT_Library_SetLcdFilter( library, FT_LCD_FILTER_LIGHT ); flags |= FT_LOAD_TARGET_LCD; if( self->lcd_filter ) { FT_Library_SetLcdFilterWeights( library, self->lcd_weights ); } } error = FT_Load_Glyph( face, glyph_index, flags ); if( error ) { fprintf(stderr, "FT_Error (line %d, code 0x%02x) : %s\n", __LINE__, FT_Errors[error].code, FT_Errors[error].message); FT_Done_FreeType( library ); return wcslen(charcodes)-i; } slot = face->glyph; /* Gamma correction (sort of) */ for( x=0; x<slot->bitmap.width; ++x ) { for( y=0; y<slot->bitmap.rows; ++y ) { c = *(unsigned char *)(slot->bitmap.buffer + y*slot->bitmap.pitch + x ); c = (unsigned char) ( pow(c/255.0, self->gamma) * 255); *(unsigned char *)(slot->bitmap.buffer + y*slot->bitmap.pitch + x ) = c; } } // We want each glyph to be separated by at least one black pixel // (for example for shader used in demo-subpixel.c) w = slot->bitmap.width/depth + 1; h = slot->bitmap.rows + 1; region = texture_atlas_get_region( self->atlas, w, h ); if ( region.x < 0 ) { missed++; continue; } w = w - 1; h = h - 1; x = region.x; y = region.y; texture_atlas_set_region( self->atlas, x, y, w, h, slot->bitmap.buffer, slot->bitmap.pitch ); glyph = texture_glyph_new( ); glyph->font = self; glyph->charcode = charcodes[i]; glyph->kerning = 0; glyph->width = w; glyph->height = h; glyph->offset_x = slot->bitmap_left; glyph->offset_y = slot->bitmap_top; glyph->u0 = x/(float)width; glyph->v0 = y/(float)height; glyph->u1 = (x + glyph->width)/(float)width; glyph->v1 = (y + glyph->height)/(float)height; /* Discard hinting to get advance */ FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING); slot = face->glyph; glyph->advance_x = slot->advance.x/64.0; glyph->advance_y = slot->advance.y/64.0; vector_push_back( self->glyphs, glyph ); texture_glyph_delete( glyph ); } FT_Done_Face( face ); FT_Done_FreeType( library ); texture_atlas_upload( self->atlas ); texture_font_generate_kerning( self ); return missed; }
//------------------------------------------------------------------ void ofTrueTypeFont::loadFont(string filename, int fontsize, bool _bAntiAliased, bool _bFullCharacterSet, bool makeContours, float simplifyAmt){ bMakeContours = makeContours; //------------------------------------------------ if (bLoadedOk == true){ // we've already been loaded, try to clean up : unloadTextures(); } //------------------------------------------------ filename = ofToDataPath(filename); bLoadedOk = false; bAntiAlised = _bAntiAliased; bFullCharacterSet = _bFullCharacterSet; fontSize = fontsize; //--------------- load the library and typeface FT_Library library; if (FT_Init_FreeType( &library )){ ofLog(OF_LOG_ERROR," PROBLEM WITH FT lib"); return; } FT_Face face; if (FT_New_Face( library, filename.c_str(), 0, &face )) { return; } FT_Set_Char_Size( face, fontsize << 6, fontsize << 6, 96, 96); lineHeight = fontsize * 1.43f; //------------------------------------------------------ //kerning would be great to support: //ofLog(OF_LOG_NOTICE,"FT_HAS_KERNING ? %i", FT_HAS_KERNING(face)); //------------------------------------------------------ nCharacters = bFullCharacterSet ? 256 : 128 - NUM_CHARACTER_TO_START; //--------------- initialize character info and textures cps.resize(nCharacters); if(bMakeContours){ charOutlines.clear(); charOutlines.assign(nCharacters, ofTTFCharacter()); } vector<ofPixels> expanded_data(nCharacters); long areaSum=0; //--------------------- load each char ----------------------- for (int i = 0 ; i < nCharacters; i++){ //------------------------------------------ anti aliased or not: if(FT_Load_Glyph( face, FT_Get_Char_Index( face, (unsigned char)(i+NUM_CHARACTER_TO_START) ), FT_LOAD_DEFAULT )){ ofLog(OF_LOG_ERROR,"error with FT_Load_Glyph %i", i); } if (bAntiAlised == true) FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); else FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); //------------------------------------------ FT_Bitmap& bitmap= face->glyph->bitmap; // prepare the texture: /*int width = ofNextPow2( bitmap.width + border*2 ); int height = ofNextPow2( bitmap.rows + border*2 ); // ------------------------- this is fixing a bug with small type // ------------------------- appearantly, opengl has trouble with // ------------------------- width or height textures of 1, so we // ------------------------- we just set it to 2... if (width == 1) width = 2; if (height == 1) height = 2;*/ if(bMakeContours){ if( printVectorInfo )printf("\n\ncharacter %c: \n", char( i+NUM_CHARACTER_TO_START ) ); //int character = i + NUM_CHARACTER_TO_START; charOutlines[i] = makeContoursForCharacter( face ); if(simplifyAmt>0) charOutlines[i].simplify(simplifyAmt); charOutlines[i].getTessellation(); } // ------------------------- // info about the character: cps[i].character = i; cps[i].height = face->glyph->bitmap_top; cps[i].width = face->glyph->bitmap.width; cps[i].setWidth = face->glyph->advance.x >> 6; cps[i].topExtent = face->glyph->bitmap.rows; cps[i].leftExtent = face->glyph->bitmap_left; int width = cps[i].width; int height = bitmap.rows; cps[i].tW = width; cps[i].tH = height; GLint fheight = cps[i].height; GLint bwidth = cps[i].width; GLint top = cps[i].topExtent - cps[i].height; GLint lextent = cps[i].leftExtent; GLfloat corr, stretch; //this accounts for the fact that we are showing 2*visibleBorder extra pixels //so we make the size of each char that many pixels bigger stretch = 0;//(float)(visibleBorder * 2); corr = (float)(( (fontSize - fheight) + top) - fontSize); cps[i].x1 = lextent + bwidth + stretch; cps[i].y1 = fheight + corr + stretch; cps[i].x2 = (float) lextent; cps[i].y2 = -top + corr; // Allocate Memory For The Texture Data. expanded_data[i].allocate(width, height, 2); //-------------------------------- clear data: expanded_data[i].set(0,255); // every luminance pixel = 255 expanded_data[i].set(1,0); if (bAntiAlised == true){ ofPixels bitmapPixels; bitmapPixels.setFromExternalPixels(bitmap.buffer,bitmap.width,bitmap.rows,1); expanded_data[i].setChannel(1,bitmapPixels); } else { //----------------------------------- // true type packs monochrome info in a // 1-bit format, hella funky // here we unpack it: unsigned char *src = bitmap.buffer; for(int j=0; j <bitmap.rows;j++) { unsigned char b=0; unsigned char *bptr = src; for(int k=0; k < bitmap.width ; k++){ expanded_data[i][2*(k+j*width)] = 255; if (k%8==0){ b = (*bptr++); } expanded_data[i][2*(k+j*width) + 1] = b&0x80 ? 255 : 0; b <<= 1; } src += bitmap.pitch; } //----------------------------------- } areaSum += (cps[i].width+border*2)*(cps[i].height+border*2); } vector<charProps> sortedCopy = cps; sort(sortedCopy.begin(),sortedCopy.end(),&compare_cps); // pack in a texture, algorithm to calculate min w/h from // http://upcommons.upc.edu/pfc/bitstream/2099.1/7720/1/TesiMasterJonas.pdf //cout << areaSum << endl; bool packed = false; float alpha = logf(areaSum)*1.44269; int w; int h; while(!packed){ w = pow(2,floor((alpha/2.f) + 0.5)); // there doesn't seem to be a round in cmath for windows. //w = pow(2,round(alpha/2.f)); h = w;//pow(2,round(alpha - round(alpha/2.f))); int x=0; int y=0; int maxRowHeight = sortedCopy[0].tH + border*2; for(int i=0;i<(int)cps.size();i++){ if(x+sortedCopy[i].tW + border*2>w){ x = 0; y += maxRowHeight; maxRowHeight = sortedCopy[i].tH + border*2; if(y + maxRowHeight > h){ alpha++; break; } } x+= sortedCopy[i].tW + border*2; if(i==(int)cps.size()-1) packed = true; } } ofPixels atlasPixels; atlasPixels.allocate(w,h,2); atlasPixels.set(0,255); atlasPixels.set(1,0); int x=0; int y=0; int maxRowHeight = sortedCopy[0].tH + border*2; for(int i=0;i<(int)cps.size();i++){ ofPixels & charPixels = expanded_data[sortedCopy[i].character]; if(x+sortedCopy[i].tW + border*2>w){ x = 0; y += maxRowHeight; maxRowHeight = sortedCopy[i].tH + border*2; } cps[sortedCopy[i].character].t2 = float(x + border)/float(w); cps[sortedCopy[i].character].v2 = float(y + border)/float(h); cps[sortedCopy[i].character].t1 = float(cps[sortedCopy[i].character].tW + x + border)/float(w); cps[sortedCopy[i].character].v1 = float(cps[sortedCopy[i].character].tH + y + border)/float(h); charPixels.pasteInto(atlasPixels,x+border,y+border); x+= sortedCopy[i].tW + border*2; } texAtlas.allocate(atlasPixels.getWidth(),atlasPixels.getHeight(),GL_LUMINANCE_ALPHA,false); if(bAntiAlised && fontsize>14){ texAtlas.setTextureMinMagFilter(GL_LINEAR,GL_LINEAR); }else{ texAtlas.setTextureMinMagFilter(GL_NEAREST,GL_NEAREST); } texAtlas.loadData(atlasPixels.getPixels(),atlasPixels.getWidth(),atlasPixels.getHeight(),GL_LUMINANCE_ALPHA); // ------------- close the library and typeface FT_Done_Face(face); FT_Done_FreeType(library); bLoadedOk = true; }
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; }
int main( int argc, char** argv ) { FT_Library library; FT_Face face; FT_GlyphSlot slot; FT_Matrix matrix; /* transformation matrix */ FT_Vector pen; /* untransformed origin */ FT_Error error; char* filename; // char* text; double angle; int target_height; int n, num_chars; wchar_t *chinese_str = L"ол╣Щ1g"; unsigned int *p = (unsigned int *)chinese_str; int i; printf("Uniocde: \n"); for (i = 0; i < wcslen(chinese_str); i++) { printf("0x%x ", p[i]); } printf("\n"); // return 0; if ( argc != 2 ) { fprintf ( stderr, "usage: %s font\n", argv[0] ); exit( 1 ); } filename = argv[1]; /* first argument */ // text = argv[2]; /* second argument */ num_chars = wcslen(chinese_str); angle = ( 0.0 / 360 ) * 3.14159 * 2; /* use 0 degrees */ target_height = HEIGHT; error = FT_Init_FreeType( &library ); /* initialize library */ /* error handling omitted */ error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */ /* error handling omitted */ /* use 20pt at 100dpi */ error = FT_Set_Char_Size( face, 20 * 64, 0, 100, 0 ); /* set character size */ /* error handling omitted */ slot = face->glyph; /* set up matrix */ matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L ); matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L ); matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); /* the pen position in 26.6 cartesian space coordinates; */ /* start at (0,40) relative to the upper left corner */ pen.x = 0 * 64; pen.y = ( target_height - 40 ) * 64; for ( n = 0; n < num_chars; n++ ) { /* set transformation */ FT_Set_Transform( face, &matrix, &pen ); /* load glyph image into the slot (erase previous one) */ error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER ); if ( error ) continue; /* ignore errors */ /* now, draw to our target surface (convert position) */ draw_bitmap( &slot->bitmap, slot->bitmap_left, target_height - slot->bitmap_top ); /* increment pen position */ pen.x += slot->advance.x; pen.y += slot->advance.y; } show_image(); FT_Done_Face ( face ); FT_Done_FreeType( library ); return 0; }
void FreeTypeLib::freeFace(FT_Face* face) { FT_Done_Face(*face); delete face; }
//-----------------------------------------------------------------// ~ftimg() { for(face_map_it it = face_map_.begin(); it != face_map_.end(); ++it) { FT_Done_Face(it->second.face_); } FT_Done_FreeType(library_); }
SFMLGfx::~SFMLGfx() { FT_Done_Face(font); FT_Done_FreeType(freetypeHandle); }
void TTFLibrary::closeFont(FT_Face &face) { assert(_initialized); FT_Done_Face(face); }
static FT_Face LoadFace( filter_t *p_filter, const char *psz_fontfile, int i_idx, const text_style_t *p_style ) { filter_sys_t *p_sys = p_filter->p_sys; char *psz_key = NULL; int i_font_size = ConvertToLiveSize( p_filter, p_style ); int i_font_width = p_style->i_style_flags & STYLE_HALFWIDTH ? i_font_size / 2 : i_font_size; if( asprintf( &psz_key, "%s - %d - %d - %d", psz_fontfile, i_idx, i_font_size, i_font_width ) < 0 ) return NULL; FT_Face p_face = vlc_dictionary_value_for_key( &p_sys->face_map, psz_key ); if( p_face != kVLCDictionaryNotFound ) goto done; if( psz_fontfile[0] == ':' && psz_fontfile[1] == '/' ) { int i_attach = atoi( psz_fontfile + 2 ); if( i_attach < 0 || i_attach >= p_sys->i_font_attachments ) { msg_Err( p_filter, "LoadFace: Invalid font attachment index" ); p_face = NULL; } else { input_attachment_t *p_attach = p_sys->pp_font_attachments[ i_attach ]; if( FT_New_Memory_Face( p_sys->p_library, p_attach->p_data, p_attach->i_data, i_idx, &p_face ) ) p_face = NULL; } } else if( FT_New_Face( p_sys->p_library, psz_fontfile, i_idx, &p_face ) ) { msg_Err( p_filter, "LoadFace: Error creating face for %s", psz_key ); p_face = NULL; } if( !p_face ) goto done; if( FT_Select_Charmap( p_face, ft_encoding_unicode ) ) { /* We've loaded a font face which is unhelpful for actually * rendering text - fallback to the default one. */ msg_Err( p_filter, "LoadFace: Error selecting charmap for %s", psz_key ); FT_Done_Face( p_face ); p_face = NULL; goto done; } if( FT_Set_Pixel_Sizes( p_face, i_font_width, i_font_size ) ) { msg_Err( p_filter, "LoadFace: Failed to set font size for %s", psz_key ); FT_Done_Face( p_face ); p_face = NULL; goto done; } vlc_dictionary_insert( &p_sys->face_map, psz_key, p_face ); done: free( psz_key ); return p_face; }
void DemoEntityManager::CreateOpenGlFont() { FT_Library library; FT_Error error = FT_Init_FreeType (&library); if ( !error ) { char fileName[2048]; //GetWorkingFileName ("arial.ttf", fileName); //GetWorkingFileName ("calibri.ttf", fileName); GetWorkingFileName ("courbd.ttf", fileName); FT_Face face[96]; int withInPixels = 12; int heightInPixels = 16; int width = 0; int height = 0; for (int ch = 0; ch < 96; ch ++) { // Load The Glyph For Our Character. error = FT_New_Face( library, fileName, 0, &face[ch] ); dAssert (!error); FT_Face bitmap = face[ch]; error = FT_Set_Char_Size(bitmap, withInPixels * 64, heightInPixels * 64, 96, 96); dAssert (!error); FT_UInt index = FT_Get_Char_Index( face[ch], ch + ' '); //FT_UInt index = FT_Get_Char_Index (bitmap, 'A'); error = FT_Load_Glyph (bitmap, index, FT_LOAD_DEFAULT ); dAssert (!error); error = FT_Render_Glyph (bitmap->glyph, FT_RENDER_MODE_NORMAL); dAssert (!error); const FT_Glyph_Metrics& metrics = bitmap->glyph->metrics; int w = metrics.width / 64; int h = metrics.height / 64; width += w; height = (height > h) ? height : h; } int imageWidth = TwosPower (width); int imageHeight = TwosPower (height); char* const image = new char[2 * imageWidth * imageHeight]; memset (image, 0, 2 * imageWidth * imageHeight); int maxWidth = 0; int imageBase = 0; for (int ch = 0; ch < 96; ch ++) { FT_Face bitmap = face[ch]; FT_GlyphSlot slot = bitmap->glyph; const FT_Glyph_Metrics& metrics = slot->metrics; int w = metrics.width / 64; int h = metrics.height / 64; maxWidth = (w > maxWidth) ? w : maxWidth; if (w) { const unsigned char* const buffer = slot->bitmap.buffer; int pitch = slot->bitmap.pitch; int posit = imageBase; for (int j = 0; j < h; j ++) { for (int i = 0; i < w; i ++) { int color = buffer[j * pitch + i]; image[posit + i * 2 + 0] = color; image[posit + i * 2 + 1] = color; } posit += imageWidth * 2; } imageBase += w * 2; } } // make th open gl display list here m_fontImage = LoadImage("fontTexture", image, imageWidth, imageHeight, m_luminace); m_font = glGenLists(96); glBindTexture(GL_TEXTURE_2D, m_fontImage); imageBase = 0; for (int ch = 0; ch < 96; ch ++) { FT_Face bitmap = face[ch]; FT_GlyphSlot slot = bitmap->glyph; const FT_Glyph_Metrics& metrics = slot->metrics; glNewList(m_font + ch, GL_COMPILE); glPushMatrix(); // glTranslatef(slot->bitmap_left, 64 - slot->bitmap_top, 0); glTranslatef(slot->bitmap_left, - slot->bitmap_top, 0); dFloat w = dFloat (metrics.width / 64); dFloat h = dFloat (metrics.height / 64); if (w) { dFloat u0 = dFloat (imageBase) / imageWidth; dFloat u1 = dFloat (imageBase + w - 1.0f) / imageWidth; dFloat v0 = 0.0f; dFloat v1 = (h - 1.0f) / imageHeight; glBegin(GL_QUADS); glTexCoord2d (u0, v0); glVertex2i(0, 0); glTexCoord2d (u0, v1); glVertex2i(0, h - 1); glTexCoord2d (u1, v1); glVertex2i (w - 1, h - 1); glTexCoord2d (u1, v0); glVertex2i (w - 1, 0); glEnd(); imageBase += w; } glPopMatrix(); //glTranslatef(maxWidth, 0, 0); glTranslatef(metrics.horiAdvance / 64, 0, 0); glEndList(); FT_Done_Face(bitmap); } delete[] image; // destroy the free type library FT_Done_FreeType (library); } }
void FreeTypeFont::doClose() { CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Done_Face(ftFont) == 0); _data = nullptr; ftFont = nullptr; }
static void ReleaseFont(FT_Face face) { assert(face); FT_Done_Face(face); };
void tst_QScriptEngine::kannada() { { FT_Face face = loadFace("Sampige.ttf"); if (face) { const ShapeTable shape_table [] = { { { 0x0ca8, 0x0ccd, 0x0ca8, 0x0 }, { 0x0049, 0x00ba, 0x0 } }, { { 0x0ca8, 0x0ccd, 0x0ca1, 0x0 }, { 0x0049, 0x00b3, 0x0 } }, { { 0x0caf, 0x0cc2, 0x0 }, { 0x004f, 0x005d, 0x0 } }, { { 0x0ce0, 0x0 }, { 0x006a, 0x0 } }, { { 0x0ce6, 0x0ce7, 0x0ce8, 0x0 }, { 0x006b, 0x006c, 0x006d, 0x0 } }, { { 0x0cb5, 0x0ccb, 0x0 }, { 0x015f, 0x0067, 0x0 } }, { { 0x0cb0, 0x0ccd, 0x0cae, 0x0 }, { 0x004e, 0x0082, 0x0 } }, { { 0x0cb0, 0x0ccd, 0x0c95, 0x0 }, { 0x0036, 0x0082, 0x0 } }, { { 0x0c95, 0x0ccd, 0x0cb0, 0x0 }, { 0x0036, 0x00c1, 0x0 } }, { { 0x0cb0, 0x0ccd, 0x200d, 0x0c95, 0x0 }, { 0x0050, 0x00a7, 0x0 } }, // Kaphala { { 0x0cb0, 0x200d, 0x0ccd, 0x0c95, 0x0 }, { 0x0050, 0x00a7, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Kannada) ); ++s; } FT_Done_Face(face); } else { QSKIP("couln't find Sampige.ttf"); } } { FT_Face face = loadFace("tunga.ttf"); if (face) { const ShapeTable shape_table [] = { { { 0x0cb7, 0x0cc6, 0x0 }, { 0x00b0, 0x006c, 0x0 } }, { { 0x0cb7, 0x0ccd, 0x0 }, { 0x0163, 0x0 } }, { { 0xc95, 0xcbf, 0xcd5, 0x0 }, { 0x114, 0x73, 0x0 } }, { { 0xc95, 0xcc6, 0xcd5, 0x0 }, { 0x90, 0x6c, 0x73, 0x0 } }, { { 0xc95, 0xcc6, 0xcd6, 0x0 }, { 0x90, 0x6c, 0x74, 0x0 } }, { { 0xc95, 0xcc6, 0xcc2, 0x0 }, { 0x90, 0x6c, 0x69, 0x0 } }, { { 0xc95, 0xcca, 0xcd5, 0x0 }, { 0x90, 0x6c, 0x69, 0x73, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Kannada) ); ++s; } FT_Done_Face(face); } else { QSKIP("couln't find tunga.ttf"); } } }
triebWerk::CFontFace::~CFontFace() { FT_Done_Face(m_Face); }
void tst_QScriptEngine::devanagari() { { FT_Face face = loadFace("raghu.ttf"); if (face) { const ShapeTable shape_table [] = { // Ka { { 0x0915, 0x0 }, { 0x0080, 0x0 } }, // Ka Halant { { 0x0915, 0x094d, 0x0 }, { 0x0080, 0x0051, 0x0 } }, // Ka Halant Ka { { 0x0915, 0x094d, 0x0915, 0x0 }, { 0x00c8, 0x0080, 0x0 } }, // Ka MatraI { { 0x0915, 0x093f, 0x0 }, { 0x01d1, 0x0080, 0x0 } }, // Ra Halant Ka { { 0x0930, 0x094d, 0x0915, 0x0 }, { 0x0080, 0x005b, 0x0 } }, // Ra Halant Ka MatraI { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 }, { 0x01d1, 0x0080, 0x005b, 0x0 } }, // MatraI { { 0x093f, 0x0 }, { 0x01d4, 0x029c, 0x0 } }, // Ka Nukta { { 0x0915, 0x093c, 0x0 }, { 0x00a4, 0x0 } }, // Ka Halant Ra { { 0x0915, 0x094d, 0x0930, 0x0 }, { 0x0110, 0x0 } }, // Ka Halant Ra Halant Ka { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 }, { 0x0158, 0x0080, 0x0 } }, { { 0x0930, 0x094d, 0x200d, 0x0 }, { 0x00e2, 0x0 } }, { { 0x0915, 0x094d, 0x0930, 0x094d, 0x200d, 0x0 }, { 0x0158, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Devanagari) ); ++s; } FT_Done_Face(face); } else { QSKIP("couln't find raghu.ttf"); } } { FT_Face face = loadFace("mangal.ttf"); if (face) { const ShapeTable shape_table [] = { // Ka { { 0x0915, 0x0 }, { 0x0080, 0x0 } }, // Ka Halant { { 0x0915, 0x094d, 0x0 }, { 0x0080, 0x0051, 0x0 } }, // Ka Halant Ka { { 0x0915, 0x094d, 0x0915, 0x0 }, { 0x00c8, 0x0080, 0x0 } }, // Ka MatraI { { 0x0915, 0x093f, 0x0 }, { 0x01d1, 0x0080, 0x0 } }, // Ra Halant Ka { { 0x0930, 0x094d, 0x0915, 0x0 }, { 0x0080, 0x005b, 0x0 } }, // Ra Halant Ka MatraI { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 }, { 0x01d1, 0x0080, 0x005b, 0x0 } }, // MatraI { { 0x093f, 0x0 }, { 0x01d4, 0x029c, 0x0 } }, // Ka Nukta { { 0x0915, 0x093c, 0x0 }, { 0x00a4, 0x0 } }, // Ka Halant Ra { { 0x0915, 0x094d, 0x0930, 0x0 }, { 0x0110, 0x0 } }, // Ka Halant Ra Halant Ka { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 }, { 0x0158, 0x0080, 0x0 } }, { { 0x92b, 0x94d, 0x930, 0x0 }, { 0x125, 0x0 } }, { { 0x92b, 0x93c, 0x94d, 0x930, 0x0 }, { 0x149, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Devanagari) ); ++s; } FT_Done_Face(face); } else { QSKIP("couldn't find mangal.ttf"); } } }
void tearDownFreetype() { FT_Done_Face(face); FT_Done_FreeType(library); }
void tst_QScriptEngine::tamil() { { FT_Face face = loadFace("akruti1.ttf"); if (face) { const ShapeTable shape_table [] = { { { 0x0b95, 0x0bc2, 0x0 }, { 0x004e, 0x0 } }, { { 0x0bae, 0x0bc2, 0x0 }, { 0x009e, 0x0 } }, { { 0x0b9a, 0x0bc2, 0x0 }, { 0x0058, 0x0 } }, { { 0x0b99, 0x0bc2, 0x0 }, { 0x0053, 0x0 } }, { { 0x0bb0, 0x0bc2, 0x0 }, { 0x00a8, 0x0 } }, { { 0x0ba4, 0x0bc2, 0x0 }, { 0x008e, 0x0 } }, { { 0x0b9f, 0x0bc2, 0x0 }, { 0x0062, 0x0 } }, { { 0x0b95, 0x0bc6, 0x0 }, { 0x000a, 0x0031, 0x0 } }, { { 0x0b95, 0x0bca, 0x0 }, { 0x000a, 0x0031, 0x0007, 0x0 } }, { { 0x0b95, 0x0bc6, 0x0bbe, 0x0 }, { 0x000a, 0x0031, 0x007, 0x0 } }, { { 0x0b95, 0x0bcd, 0x0bb7, 0x0 }, { 0x0049, 0x0 } }, { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bca, 0x0 }, { 0x000a, 0x0049, 0x007, 0x0 } }, { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bc6, 0x0bbe, 0x0 }, { 0x000a, 0x0049, 0x007, 0x0 } }, { { 0x0b9f, 0x0bbf, 0x0 }, { 0x005f, 0x0 } }, { { 0x0b9f, 0x0bc0, 0x0 }, { 0x0060, 0x0 } }, { { 0x0bb2, 0x0bc0, 0x0 }, { 0x00ab, 0x0 } }, { { 0x0bb2, 0x0bbf, 0x0 }, { 0x00aa, 0x0 } }, { { 0x0bb0, 0x0bcd, 0x0 }, { 0x00a4, 0x0 } }, { { 0x0bb0, 0x0bbf, 0x0 }, { 0x00a5, 0x0 } }, { { 0x0bb0, 0x0bc0, 0x0 }, { 0x00a6, 0x0 } }, { { 0x0b83, 0x0 }, { 0x0025, 0x0 } }, { { 0x0b83, 0x0b95, 0x0 }, { 0x0025, 0x0031, 0x0 } }, { {0}, {0} } }; const ShapeTable *s = shape_table; while (s->unicode[0]) { QVERIFY( shaping(face, s, HB_Script_Tamil) ); ++s; } FT_Done_Face(face); } else { QSKIP("couln't find akruti1.ttf"); } } }
/* ------------------------------------------------------------------------- */ int main ( int argc, char *argv[] ) { FT_Library library; FT_Face face; FT_FaceRec props; FT_Error error = 0; FT_UInt names; FT_CharMap charmap; FX_Kern_0 *kstable; TT_OS2 *pOS2; TT_Postscript *ppost; ULONG rc; BOOL bDumpUCS = FALSE; BOOL bShowKST = FALSE; BOOL bShowOS2 = FALSE; BOOL bShowPS = FALSE; char szPID[10]; char szEID[32]; int i; char *buf; if ( argc < 2 ) { printf("FONTNAME - Show summary of OpenType font names and other optional information.\n"); printf("Syntax: FONTNAME <filename> [ options ]\n\n"); printf(" /D Dump Unicode and DBCS strings as hex values\n"); printf(" /K Show kerning summary (KERN format 0 only)\n"); printf(" /O Show OS/2 table\n"); printf(" /P Show POST table\n\n"); printf("NAME and CMAP table information is always shown.\n\n"); printf("\nNo font file specified.\n"); return 0; } for ( i = 2; i < argc; i++ ) { if ( strlen( argv[i] ) > 1 ) { CHAR cOption = 0; if ( argv[i][0] == '/' || argv[i][0] == '-') cOption = argv[i][1]; switch ( cOption ) { case 'd': case 'D': bDumpUCS = TRUE; break; case 'k': case 'K': bShowKST = TRUE; break; case 'o': case 'O': bShowOS2 = TRUE; break; case 'p': case 'P': bShowPS = TRUE; break; default : break; } } } if (( rc = UniCreateUconvObject( L"@endian=big", &uconv )) != ULS_SUCCESS ) { printf("Failed to create Unicode conversion object (rc=0x%X).\n"); printf("Unicode text values will not be shown.\n"); uconv = NULL; } error = FT_Init_FreeType( &library ); if ( error ) { printf("An error occurred during library initialization.\n"); return (int) error; } printf("FreeType 2 library initialized successfully.\n"); error = FT_New_Face( library, argv[1], 0, &face ); if ( error ) { if ( error == FT_Err_Unknown_File_Format ) printf("The file format is unsupported.\n"); else printf("The file \"%s\" could not be loaded.\n", argv[1]); goto done; } printf("Font %s read successfully.\n", face->family_name ); names = FT_Get_Sfnt_Name_Count( face ); if ( names ) { printf("Names table contains %d entries:\n", names ); for ( i = 0; i < names; i++ ) { FT_SfntName name; error = FT_Get_Sfnt_Name( face, i, &name ); if ( error ) continue; printf("%2d: Plat %d, Enc %d, Lang 0x%X, ID %2d ", i, name.platform_id, name.encoding_id, name.language_id, name.name_id ); if ( name.platform_id == 1 && name.encoding_id == 0 && name.string_len < 100 ) { printf(" \""); PrintNameString( name.string, name.string_len ); printf("\"\n"); } else if ( name.platform_id == 3 && name.encoding_id == 1 && uconv && name.string_len < 200 ) { printf(" (U)\""); if (bDumpUCS) DumpUnicodeString( name.string, name.string_len ); else PrintUnicodeString( name.string, name.string_len ); printf("\"\n"); } else if ( name.string_len < 200 && bDumpUCS ) { printf(" \""); DumpUnicodeString( name.string, name.string_len ); printf("\"\n"); } else printf(" [%d bytes]\n", name.string_len ); } } printf("\nINCLUDED CMAPS"); printf("\n--------------\n"); for ( i = 0; i < face->num_charmaps; i++ ) { charmap = face->charmaps[i]; switch ( charmap->platform_id ) { case 0: strcpy( szPID, "Unicode"); switch ( charmap->encoding_id ) { case 0: strcpy( szEID, "default"); break; case 1: strcpy( szEID, "1.1"); break; case 3: strcpy( szEID, "2+"); break; case 4: strcpy( szEID, "3.1+ UTF-32"); break; default: strcpy( szEID, "unknown"); break; } break; case 1: strcpy( szPID, "Macintosh"); switch ( charmap->encoding_id ) { case 0: strcpy( szEID, "Roman"); break; case 1: strcpy( szEID, "Japanese"); break; case 2: strcpy( szEID, "Chinese-T"); break; case 3: strcpy( szEID, "Korean"); break; case 8: strcpy( szEID, "symbols"); break; case 25: strcpy( szEID, "Chinese-S"); break; default: strcpy( szEID, "other language");break; } break; case 3: strcpy( szPID, "Windows"); switch ( charmap->encoding_id ) { case 0: strcpy( szEID, "symbols"); break; case 1: strcpy( szEID, "Unicode"); break; case 2: strcpy( szEID, "Shift-JIS (Japan)"); break; case 3: strcpy( szEID, "GB2312 (China)"); break; case 4: strcpy( szEID, "Big5 (Taiwan)"); break; case 5: strcpy( szEID, "Wansung (Korea)"); break; case 6: strcpy( szEID, "Johab (Korea)"); break; case 10: strcpy( szEID, "UCS-4"); break; default: strcpy( szEID, "unknown"); break; } break; default: strcpy( szPID, "unknown"); strcpy( szEID, "unknown"); break; } printf("Platform: %d (%s), Encoding: %d (%s)\n", charmap->platform_id, szPID, charmap->encoding_id, szEID ); } #if 0 error = FX_Flush_Stream( face ); if ( error ) { printf("Failed to close stream: 0x%X\n", error ); FT_Done_Face( face ); goto done; } error = FX_Activate_Stream( face ); if ( error ) { printf("Failed to reopen stream: 0x%X\n", error ); FT_Done_Face( face ); goto done; } #endif if ( bShowKST ) { printf("\nKERNING INFORMATION"); printf("\n-------------------\n"); error = FX_Get_Kerning_Pairs( face, &kstable ); switch ( error ) { case 0: printf("%u kerning pairs defined:\n", kstable->nPairs ); if ( kstable->nPairs ) { for ( i = 0; i < kstable->nPairs; i++ ) { printf(" %X / %X (%d)\n", kstable->pairs[i].left, kstable->pairs[i].right, kstable->pairs[i].value ); } } safe_free( kstable ); break; case FT_Err_Table_Missing: printf("No kerning table defined.\n"); break; case FX_Err_Invalid_Kerning_Table: printf("The kerning table is invalid.\n"); break; case FT_Err_Out_Of_Memory: printf("Memory allocation error.\n"); break; case FX_Err_Invalid_Kerning_Table_Format: printf("No supported kerning table format found.\n"); break; default: printf("An unknown error (0x%X) was encountered.\n", error ); break; } } if ( bShowOS2 ) { printf("\nOS/2 TABLE"); printf("\n----------\n"); pOS2 = (TT_OS2 *) FT_Get_Sfnt_Table( face, ft_sfnt_os2 ); if ( pOS2 ) { printf("version: %u\n", pOS2->version ); printf("xAvgCharWidth: %d\n", pOS2->xAvgCharWidth ); printf("usWeightClass: %u\n", pOS2->usWeightClass ); printf("usWidthClass: %u\n", pOS2->usWidthClass ); printf("fsType: 0x%X\n", pOS2->fsType ); printf("ySubscriptXSize: %d\n", pOS2->ySubscriptXSize ); printf("ySubscriptYSize: %d\n", pOS2->ySubscriptYSize ); printf("ySubscriptXOffset: %d\n", pOS2->ySubscriptXOffset ); printf("ySubscriptYOffset: %d\n", pOS2->ySubscriptYOffset ); printf("ySuperscriptXSize: %d\n", pOS2->ySuperscriptXSize ); printf("ySuperscriptYSize: %d\n", pOS2->ySuperscriptYSize ); printf("ySuperscriptXOffset: %d\n", pOS2->ySuperscriptXOffset ); printf("ySuperscriptYOffset: %d\n", pOS2->ySuperscriptYOffset ); printf("yStrikeoutSize: %d\n", pOS2->yStrikeoutSize ); printf("yStrikeoutPosition: %d\n", pOS2->yStrikeoutPosition ); printf("sFamilyClass: %d\n", pOS2->sFamilyClass ); printf("panose: []\n"); printf("ulUnicodeRange1: 0x%X\n", pOS2->ulUnicodeRange1 ); printf("ulUnicodeRange2: 0x%X\n", pOS2->ulUnicodeRange2 ); printf("ulUnicodeRange3: 0x%X\n", pOS2->ulUnicodeRange3 ); printf("ulUnicodeRange4: 0x%X\n", pOS2->ulUnicodeRange4 ); printf("achVendID: %c%c%c%c\n", pOS2->achVendID[0], pOS2->achVendID[1], pOS2->achVendID[2], pOS2->achVendID[3] ); printf("fsSelection: 0x%X\n", pOS2->fsSelection ); printf("usFirstCharIndex: %u\n", pOS2->usFirstCharIndex ); printf("usLastCharIndex: %u\n", pOS2->usLastCharIndex ); printf("sTypoAscender: %d\n", pOS2->sTypoAscender ); printf("sTypoDescender: %d\n", pOS2->sTypoDescender ); printf("sTypoLineGap: %d\n", pOS2->sTypoLineGap ); printf("usWinAscent: %u\n", pOS2->usWinAscent ); printf("usWinDescent: %u\n", pOS2->usWinDescent ); } else printf("OS/2 table could not be located.\n"); } if ( bShowPS) { printf("\nPOST TABLE"); printf("\n----------\n"); ppost = (TT_Postscript *) FT_Get_Sfnt_Table( face, ft_sfnt_post ); if ( ppost ) { printf("FormatType: 0x%X\n", ppost->FormatType ); printf("italicAngle: %d\n", ppost->italicAngle ); printf("underlinePosition: %d\n", ppost->underlinePosition ); printf("underlineThickness: %d\n", ppost->underlineThickness ); printf("isFixedPitch: %u\n", ppost->isFixedPitch ); printf("minMemType42: %u\n", ppost->minMemType42 ); printf("maxMemType42: %u\n", ppost->maxMemType42 ); printf("minMemType1: %u\n", ppost->minMemType1 ); printf("maxMemType1: %u\n", ppost->maxMemType1 ); } else printf("POST table could not be loaded.\n"); } error = FT_Done_Face( face ); done: FT_Done_FreeType( library ); if ( uconv ) UniFreeUconvObject( uconv ); return (int) error; }
// ------------------------------------------------------- texture_font_new --- texture_font_t * texture_font_new( texture_atlas_t * atlas, const char * filename, const float size) { assert( filename ); assert( size ); texture_font_t *self = (texture_font_t *) malloc( sizeof(texture_font_t) ); if( self == NULL) { fprintf( stderr, "line %d: No more memory for allocating data\n", __LINE__ ); exit( EXIT_FAILURE ); } self->glyphs = vector_new( sizeof(texture_glyph_t *) ); self->atlas = atlas; self->height = 0; self->ascender = 0; self->descender = 0; self->filename = strdup( filename ); self->size = size; self->outline_type = 0; self->outline_thickness = 0.0; self->hinting = 1; self->filtering = 1; // FT_LCD_FILTER_LIGHT is (0x00, 0x55, 0x56, 0x55, 0x00) // FT_LCD_FILTER_DEFAULT is (0x10, 0x40, 0x70, 0x40, 0x10) self->lcd_weights[0] = 0x10; self->lcd_weights[1] = 0x40; self->lcd_weights[2] = 0x70; self->lcd_weights[3] = 0x40; self->lcd_weights[4] = 0x10; /* Get font metrics at high resolution */ FT_Library library; FT_Face face; if( !texture_font_load_face( &library, self->filename, self->size*100, &face ) ) { return self; } // 64 * 64 because of 26.6 encoding AND the transform matrix used // in texture_font_load_face (hres = 64) self->underline_position = face->underline_position / (float)(64.0f*64.0f) * self->size; self->underline_position = round( self->underline_position ); if( self->underline_position > -2 ) { self->underline_position = -2.0; } self->underline_thickness = face->underline_thickness / (float)(64.0f*64.0f) * self->size; self->underline_thickness = round( self->underline_thickness ); if( self->underline_thickness < 1 ) { self->underline_thickness = 1.0; } FT_Size_Metrics metrics = face->size->metrics; self->ascender = (metrics.ascender >> 6) / 100.0; self->descender = (metrics.descender >> 6) / 100.0; self->height = (metrics.height >> 6) / 100.0; self->linegap = self->height - self->ascender + self->descender; FT_Done_Face( face ); FT_Done_FreeType( library ); /* -1 is a special glyph */ texture_font_get_glyph( self, -1 ); return self; }
void font_release(struct font_context *ctx) { FT_Done_Face(ctx->font); }
// ------------------------------------------------- texture_font_load_face --- int texture_font_load_face( FT_Library * library, const char * filename, const float size, FT_Face * face ) { assert( library ); assert( filename ); assert( size ); size_t hres = 64; FT_Error error; FT_Matrix matrix = { (int)((1.0/hres) * 0x10000L), (int)((0.0) * 0x10000L), (int)((0.0) * 0x10000L), (int)((1.0) * 0x10000L) }; /* Initialize library */ error = FT_Init_FreeType( library ); if( error ) { fprintf(stderr, "FT_Error (0x%02x) : %s\n", FT_Errors[error].code, FT_Errors[error].message); return 0; } /* Load face */ error = FT_New_Face( *library, filename, 0, face ); if( error ) { fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", __LINE__, FT_Errors[error].code, FT_Errors[error].message); FT_Done_FreeType( *library ); return 0; } /* Select charmap */ error = FT_Select_Charmap( *face, FT_ENCODING_UNICODE ); if( error ) { fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( *face ); FT_Done_FreeType( *library ); return 0; } /* Set char size */ error = FT_Set_Char_Size( *face, (int)(size*64), 0, 72*hres, 72 ); if( error ) { fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( *face ); FT_Done_FreeType( *library ); return 0; } /* Set transform matrix */ FT_Set_Transform( *face, &matrix, NULL ); return 1; }
static Bool ft_enum_fonts(void *cbck, char *file_name, char *file_path, GF_FileEnumInfo *file_info) { char *szfont; FT_Face face; u32 num_faces, i; GF_FontReader *dr = cbck; FTBuilder *ftpriv = dr->udta; GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[FreeType] Enumerating font %s (%s)\n", file_name, file_path)); if (FT_New_Face(ftpriv->library, file_path, 0, & face )) return 0; if (!face || !face->family_name) return 0; num_faces = (u32) face->num_faces; /*locate right font in collection if several*/ for (i=0; i<num_faces; i++) { /*only scan scalable fonts*/ if (face->face_flags & FT_FACE_FLAG_SCALABLE) { Bool bold, italic; szfont = gf_malloc(sizeof(char)* (strlen(face->family_name)+100)); if (!szfont) continue; strcpy(szfont, face->family_name); /*remember first font found which looks like a alphabetical one*/ if (!ftpriv->font_default) { u32 gidx; FT_Select_Charmap(face, FT_ENCODING_UNICODE); gidx = FT_Get_Char_Index(face, (u32) 'a'); if (gidx) gidx = FT_Get_Char_Index(face, (u32) 'z'); if (gidx) gidx = FT_Get_Char_Index(face, (u32) '1'); if (gidx) gidx = FT_Get_Char_Index(face, (u32) '@'); if (gidx) ftpriv->font_default = gf_strdup(szfont); } bold = italic = 0; if (face->style_name) { char *name = gf_strdup(face->style_name); strupr(name); if (strstr(name, "BOLD")) bold = 1; if (strstr(name, "ITALIC")) italic = 1; /*if font is not regular style, append all styles blindly*/ if (!strstr(name, "REGULAR")) { strcat(szfont, " "); strcat(szfont, face->style_name); } gf_free(name); } else { if (face->style_flags & FT_STYLE_FLAG_BOLD) bold = 1; if (face->style_flags & FT_STYLE_FLAG_ITALIC) italic = 1; if (bold) strcat(szfont, " Bold"); if (italic) strcat(szfont, " Italic"); } gf_modules_set_option((GF_BaseInterface *)dr, "FontEngine", szfont, file_path); /*try to assign default fixed fonts*/ if (!bold && !italic) { strcpy(szfont, face->family_name); strlwr(szfont); if (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) { setBestFont(BEST_FIXED_FONTS, &(ftpriv->font_fixed), face->family_name); } setBestFont(BEST_SERIF_FONTS, &(ftpriv->font_serif), face->family_name); setBestFont(BEST_SANS_FONTS, &(ftpriv->font_sans), face->family_name); } gf_free(szfont); } FT_Done_Face(face); if (i+1==num_faces) return 0; /*load next font in collection*/ if (FT_New_Face(ftpriv->library, file_path, i+1, & face )) return 0; if (!face) return 0; } return 0; }