float Font::getKerning(Uint32 first, Uint32 second, unsigned int characterSize) const { // Special case where first or second is 0 (null character) if (first == 0 || second == 0) return 0.f; FT_Face face = static_cast<FT_Face>(m_face); if (face && FT_HAS_KERNING(face) && setCurrentSize(characterSize)) { // Convert the characters to indices FT_UInt index1 = FT_Get_Char_Index(face, first); FT_UInt index2 = FT_Get_Char_Index(face, second); // Get the kerning vector FT_Vector kerning; FT_Get_Kerning(face, index1, index2, FT_KERNING_DEFAULT, &kerning); // X advance is already in pixels for bitmap fonts if (!FT_IS_SCALABLE(face)) return static_cast<float>(kerning.x); // Return the X advance return static_cast<float>(kerning.x) / static_cast<float>(1 << 6); } else { // Invalid font, or no kerning return 0.f; } }
int FontFreeType::getHorizontalKerningForChars(unsigned short firstChar, unsigned short secondChar) { if (!_fontRef) return 0; bool hasKerning = FT_HAS_KERNING( _fontRef ); if (!hasKerning) return 0; // get the ID to the char we need int glyph_index1 = FT_Get_Char_Index(_fontRef, firstChar); if (!glyph_index1) return 0; // get the ID to the char we need int glyph_index2 = FT_Get_Char_Index(_fontRef, secondChar); if (!glyph_index2) return 0; FT_Vector kerning; if (FT_Get_Kerning( _fontRef, glyph_index1, glyph_index2, FT_KERNING_DEFAULT, &kerning )) return 0; return ( kerning.x >> 6 ); }
int RenderChar(FT_ULong currentchar, int sx, int sy, int ex, int color) { int row, pitch, bit, x = 0, y = 0; FT_UInt glyphindex; FT_Vector kerning; FTC_Node anode; //load char if(!(glyphindex = FT_Get_Char_Index(face, currentchar))) { // printf("<FT_Get_Char_Index for Char \"%c\" failed with Errorcode 0x%.2X>\n", (int)currentchar, error); return 0; } if((error = FTC_SBitCache_Lookup(cache, &desc, glyphindex, &sbit, &anode))) { // printf("<FTC_SBitCache_Lookup for Char \"%c\" failed with Errorcode 0x%.2X>\n", (int)currentchar, error); return 0; } if(use_kerning) { FT_Get_Kerning(face, prev_glyphindex, glyphindex, ft_kerning_default, &kerning); prev_glyphindex = glyphindex; kerning.x >>= 6; } else kerning.x = 0;
//------------------------------------------------------------------------ bool font_engine_freetype_base::add_kerning(unsigned first, unsigned second, double* x, double* y) { if(m_cur_face && first && second && FT_HAS_KERNING(m_cur_face)) { FT_Vector delta; FT_Get_Kerning(m_cur_face, first, second, FT_KERNING_DEFAULT, &delta); double dx = int26p6_to_dbl(delta.x); double dy = int26p6_to_dbl(delta.y); if(m_glyph_rendering == glyph_ren_outline || m_glyph_rendering == glyph_ren_agg_mono || m_glyph_rendering == glyph_ren_agg_gray8) { m_affine.transform_2x2(&dx, &dy); } *x += dx; *y += dy; return true; } return false; }
void FTFace::BuildKerningCache() { FT_Vector kernAdvance; kernAdvance.x = 0; kernAdvance.y = 0; kerningCache = new FTGL_DOUBLE[FTFace::MAX_PRECOMPUTED * FTFace::MAX_PRECOMPUTED * 2]; for(unsigned int j = 0; j < FTFace::MAX_PRECOMPUTED; j++) { for(unsigned int i = 0; i < FTFace::MAX_PRECOMPUTED; i++) { err = FT_Get_Kerning(*ftFace, i, j, ft_kerning_unfitted, &kernAdvance); if(err) { delete[] kerningCache; kerningCache = NULL; return; } kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i)] = static_cast<FTGL_DOUBLE>(kernAdvance.x) / 64.0; kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i) + 1] = static_cast<FTGL_DOUBLE>(kernAdvance.y) / 64.0; } } }
float glf_get_string_len(gl_tex_font_p glf, const char *text, int n) { float x = 0.0; if((glf != nullptr) && (glf->ft_face != nullptr)) { uint8_t *nch; uint8_t *nch2; uint8_t *ch = (uint8_t*)text; uint32_t curr_utf32, next_utf32; int i; nch = utf8_to_utf32(ch, &curr_utf32); curr_utf32 = FT_Get_Char_Index(glf->ft_face, curr_utf32); for(i = 0; (*ch != 0) && !((n >= 0) && (i >= n)); i++) { FT_Vector kern; nch2 = utf8_to_utf32(nch, &next_utf32); next_utf32 = FT_Get_Char_Index(glf->ft_face, next_utf32); ch = nch; nch = nch2; FT_Get_Kerning(glf->ft_face, curr_utf32, next_utf32, FT_KERNING_UNSCALED, &kern); // kern in 1/64 pixel curr_utf32 = next_utf32; x += static_cast<GLfloat>(kern.x + glf->glyphs[curr_utf32].advance_x) / 64.0; } } return x; }
FTPoint FTFace::KernAdvance(unsigned int index1, unsigned int index2) { FTGL_DOUBLE x, y; if(!hasKerningTable || !index1 || !index2) { return FTPoint(0.0, 0.0); } if(kerningCache && index1 < FTFace::MAX_PRECOMPUTED && index2 < FTFace::MAX_PRECOMPUTED) { x = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1)]; y = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1) + 1]; return FTPoint(x, y); } FT_Vector kernAdvance; kernAdvance.x = kernAdvance.y = 0; err = FT_Get_Kerning(*ftFace, index1, index2, ft_kerning_unfitted, &kernAdvance); if(err) { return FTPoint(0.0f, 0.0f); } x = static_cast<float>(kernAdvance.x) / 64.0f; y = static_cast<float>(kernAdvance.y) / 64.0f; return FTPoint(x, y); }
//----------------------------------------------------------- int ofTrueTypeFont::getKerning(int c, int prevC) const{ if(useKerning){ FT_Vector kerning; FT_Get_Kerning(face, FT_Get_Char_Index(face, prevC), FT_Get_Char_Index(face, c), FT_KERNING_UNFITTED, &kerning); return kerning.x>>6; }else{ return 0;
static void line_extents(VGFT_FONT_T *font, VGfloat *x, VGfloat *y, const char *text, int chars_count) { int i; int prev_glyph_index = 0; if (chars_count == 0) return; for (i=0; i < chars_count; i++) { int glyph_index = FT_Get_Char_Index(font->ft_face, text[i]); if (!glyph_index) return; if (i != 0) { FT_Vector kern; if (FT_Get_Kerning(font->ft_face, prev_glyph_index, glyph_index, FT_KERNING_DEFAULT, &kern)) { assert(0); } *x += float_from_26_6(kern.x); *y += float_from_26_6(kern.y); } FT_Load_Glyph(font->ft_face, glyph_index, FT_LOAD_DEFAULT); *x += float_from_26_6(font->ft_face->glyph->advance.x); } }
osg::Vec2 FreeTypeFont::getKerning(const osgText::FontResolution& fontRes, unsigned int leftcharcode, unsigned int rightcharcode, osgText::KerningType kerningType) { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(FreeTypeLibrary::instance()->getMutex()); setFontResolution(fontRes); if (!FT_HAS_KERNING(_face) || (kerningType == osgText::KERNING_NONE)) return osg::Vec2(0.0f,0.0f); FT_Kerning_Mode mode = (kerningType==osgText::KERNING_DEFAULT) ? ft_kerning_default : ft_kerning_unfitted; // convert character code to glyph index FT_UInt left = FT_Get_Char_Index( _face, leftcharcode ); FT_UInt right = FT_Get_Char_Index( _face, rightcharcode ); // get the kerning distances. FT_Vector kerning; FT_Error error = FT_Get_Kerning( _face, // handle to face object left, // left glyph index right, // right glyph index mode, // kerning mode &kerning ); // target vector if (error) { OSG_WARN << "FT_Get_Kerning(...) returned error code " <<std::hex<<error<<std::dec<< std::endl; return osg::Vec2(0.0f,0.0f); } float coord_scale = getCoordScale(); return osg::Vec2((float)kerning.x*coord_scale,(float)kerning.y*coord_scale); }
GLubyte *app::font::glyph(FT_Int32 flag, int curr, int prev, int& x, int& y, int& w, int& h, int& a, int& k) { FT_Vector kern; // Look up the current pair of characters. FT_UInt L = FT_Get_Char_Index(face, prev); FT_UInt R = FT_Get_Char_Index(face, curr); // Get the kerning and glyph sizes. FT_Get_Kerning(face, L, R, FT_KERNING_DEFAULT, &kern); FT_Load_Glyph (face, R, flag); // Convert these values to pixels and return the buffer. x = face->glyph->metrics.horiBearingX >> 6; y = face->glyph->metrics.horiBearingY >> 6; w = face->glyph->metrics.width >> 6; h = face->glyph->metrics.height >> 6; a = face->glyph->advance.x >> 6; k = kern.x >> 6; return (GLubyte *) face->glyph->bitmap.buffer; }
void Font::draw(IScene* scene, const char* text, glm::mat4 transform, float font_size, glm::vec3 color) { FT_Set_Pixel_Sizes(m_font_face, font_size, font_size); glUseProgram(TEXT_PROGRAM); checkGLError(); glm::vec3 pen(0, 0, 0); char prev = 0; bool kern = FT_HAS_KERNING(m_font_face); for(const char* i = text; i[0]; ++i) { FT_UInt index = FT_Get_Char_Index(m_font_face, i[0]); Glyph glyph = renderGlyph(i[0], font_size); if(prev && kern && i) { FT_Vector delta; FT_Get_Kerning(m_font_face, prev, index, FT_KERNING_DEFAULT, &delta); pen.x += delta.x * scene->getDPU(); //fprintf(stderr, "%ld\n", delta.x); } if(i[0] == '\n') { pen.x = 0; pen.y += font_size; prev = 0; continue; } else if(i[0] == ' ' || glyph.id == 0) { pen.x += font_size; prev = 0; continue; } glUniform3f(m_color_uniform, color.x, color.y, color.z); glm::vec3 offset(glyph.bearing.x, -glyph.bearing.y, 0.0f); glm::mat4 mvp = scene->getActiveProjectionMatrix() * scene->getActiveViewMatrix() * transform * glm::translate(glm::mat4(1), -(pen + offset) * scene->getDPU()) * glm::scale(glm::mat4(1), glm::vec3(glyph.dimensions.x * scene->getDPU(), glyph.dimensions.y * scene->getDPU(), 1.0f)); //fprintf(stderr, "Result: %f, %f, %f, %f\n", glyph.dimensions.x, glyph.dimensions.y, glyph.dimensions.x * scene->getDPU(), glyph.dimensions.y * scene->getDPU()); glUniformMatrix4fv(m_transform_uniform, 1, GL_FALSE, &mvp[0][0]); glEnableVertexAttribArray(m_vertex_position); glBindBuffer(GL_ARRAY_BUFFER, QUAD_BUFFER); glVertexAttribPointer(m_vertex_position, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, glyph.texture); glUniform1i(m_texture_uniform, 0); checkGLError(); glDrawArrays(GL_TRIANGLES, 0, 6); checkGLError(); glDisableVertexAttribArray(m_vertex_position); pen.x += glyph.advance; //fprintf(stderr, "(%d)\n", (int)glyph.advance); prev = index; } }
//http://www.freetype.org/freetype2/docs/tutorial/step2.html FT_Error measure_string(FT_Face face, std::string text, int size, Vector2i* size_out) { int pos_x = 0; bool use_kerning = FT_HAS_KERNING(face) ? true : false; FT_UInt prev_glyph_index = 0; FT_BBox text_bb; text_bb.xMax = 0; text_bb.xMin = 0; text_bb.yMax = 0; text_bb.yMin = 0; FT_Error error; error = FT_Set_Char_Size(face, 0, size * 64, 72, 72); for(unsigned int i = 0; i < text.length(); i++) { FT_UInt glyph_index = FT_Get_Char_Index(face, text.c_str()[i]); if(use_kerning && prev_glyph_index) { FT_Vector delta; FT_Get_Kerning(face, prev_glyph_index, glyph_index, FT_KERNING_DEFAULT, &delta); pos_x += delta.x >> 6; } prev_glyph_index = glyph_index; if(error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) != FT_Err_Ok) { Log::Error(__FILE__, "Unable to load glyph %d", glyph_index); return error; } FT_Glyph glyph; if(error = FT_Get_Glyph(face->glyph, &glyph) != FT_Err_Ok) { Log::Error(__FILE__, "Unable to get glyph %d", glyph_index); } FT_BBox bb; FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &bb); bb.xMax += pos_x; bb.xMin += pos_x; pos_x += glyph->advance.x >> 16; //Grow overall bounding box if(bb.xMax > text_bb.xMax) text_bb.xMax = bb.xMax; if(bb.yMax > text_bb.yMax) text_bb.yMax = bb.yMax; if(bb.xMin < text_bb.xMin) text_bb.xMin = bb.xMin; if(bb.yMin < text_bb.yMin) text_bb.yMin = bb.yMin; FT_Done_Glyph(glyph); }
static cairo_status_t glyph_array_add_text(glyph_array_t *glyphs, cairo_t *cr, const char *s, double spacing) { cairo_scaled_font_t *scaled_font; cairo_status_t status; FT_Face face; unsigned long charcode; unsigned int index; cairo_text_extents_t extents; const char *p; FT_Vector kerning; double kern_x; int first = TRUE; scaled_font = cairo_get_scaled_font (cr); status = cairo_scaled_font_status (scaled_font); if (status) return status; face = cairo_ft_scaled_font_lock_face (scaled_font); if (face == NULL) return CAIRO_STATUS_FONT_TYPE_MISMATCH; p = s; while (*p) { charcode = *p; index = FT_Get_Char_Index (face, charcode); glyphs->glyph_list[glyphs->num_glyphs].index = index; if (first) { first = FALSE; glyphs->glyph_list[glyphs->num_glyphs].x = glyphs->x; glyphs->glyph_list[glyphs->num_glyphs].y = glyphs->y; } else { cairo_glyph_extents (cr, &glyphs->glyph_list[glyphs->num_glyphs - 1], 1, &extents); FT_Get_Kerning (face, glyphs->glyph_list[glyphs->num_glyphs - 1].index, glyphs->glyph_list[glyphs->num_glyphs].index, FT_KERNING_UNSCALED, &kerning); kern_x = DOUBLE_FROM_26_6(kerning.x); glyphs->glyph_list[glyphs->num_glyphs].x = glyphs->glyph_list[glyphs->num_glyphs - 1].x + extents.x_advance + kern_x + spacing; glyphs->glyph_list[glyphs->num_glyphs].y = glyphs->glyph_list[glyphs->num_glyphs - 1].y + extents.y_advance; } cairo_glyph_extents (cr, &glyphs->glyph_list[glyphs->num_glyphs], 1, &extents); glyphs->x = glyphs->glyph_list[glyphs->num_glyphs].x + extents.x_advance + spacing; glyphs->y = glyphs->glyph_list[glyphs->num_glyphs].y + extents.y_advance; p++; glyphs->num_glyphs++; } cairo_ft_scaled_font_unlock_face (scaled_font); return CAIRO_STATUS_SUCCESS; }
GLvec2 Font::kerning(char prev, char code) const { // Returns kerning in units normalized by font size FT_Vector delta; FT_Face face = (FT_Face)face_; FT_UInt prevIndex = FT_Get_Char_Index(face, prev); FT_UInt curIndex = FT_Get_Char_Index(face, code); FT_Get_Kerning(face, prevIndex, curIndex, FT_KERNING_DEFAULT, &delta); return GLvec2((delta.x >> 6)/(GLfloat)size_, (delta.y >> 6)/(GLfloat)size_); }
//----------------------------------------------------------- int ofTrueTypeFont::getKerning(uint32_t c, uint32_t prevC) const{ if(FT_HAS_KERNING( face )){ FT_Vector kerning; FT_Get_Kerning(face.get(), FT_Get_Char_Index(face.get(), c), FT_Get_Char_Index(face.get(), prevC), FT_KERNING_UNFITTED, &kerning); return kerning.x * fontUnitScale; }else{ return 0; } }
int TextureFont::PickCharacter(const char *str, float mouseX, float mouseY) const { assert(str && mouseX >= 0.0f && mouseY >= 0.0f); // at the point of the mouse in-box test, the vars have the following values: // i1: the index of the character being tested // i2: the index of the next character // charBytes: the number of bytes used to encode the next character // right: the right edge of the box being tested // bottom: the bottom of the box being tested // x: the x-coordinate of the next character // chr1: the Unicode value of the character being tested // chr2: the Unicode value of the next character const float lineSpacing = GetHeight()*PARAGRAPH_SPACING; Uint32 chr2 = '\n'; // pretend we've just had a new line float bottom = GetHeight() - lineSpacing, x = 0.0f; int i2 = 0, charBytes = 0; do { int i1 = i2; Uint32 chr1 = chr2; // read the next character i2 += charBytes; charBytes = conv_mb_to_wc(&chr2, &str[i2]); assert(!str[i2] || charBytes); // assert valid encoding float right; if (chr1 == '\n') { right = std::numeric_limits<float>::max(); x = 0.0f; } else { std::map<Uint32,glfglyph_t>::const_iterator it = m_glyphs.find(chr1); assert(it != m_glyphs.end()); float advance = it->second.advx; if (chr2 != '\n' && chr2 != '\0') { FT_UInt a = FT_Get_Char_Index(m_face, chr1); FT_UInt b = FT_Get_Char_Index(m_face, chr2); FT_Vector kern; FT_Get_Kerning(m_face, a, b, FT_KERNING_UNFITTED, &kern); advance += float(kern.x) / 64.0f; } right = x + (advance / 2.0f); x += advance; } if ((mouseY < bottom) && (mouseX < right)) return i1; if (chr1 == '\n') bottom += lineSpacing; } while (charBytes); return i2; }
bool getKerning(double &output, FontHandle *font, int unicode1, int unicode2) { FT_Vector kerning; if (FT_Get_Kerning(font->face, FT_Get_Char_Index(font->face, unicode1), FT_Get_Char_Index(font->face, unicode2), FT_KERNING_UNSCALED, &kerning)) { output = 0; return false; } output = kerning.x/64.; return true; }
void XeTeXFontInst_FT2::getKernPair(LEGlyphID leftGlyph, LEGlyphID rightGlyph, LEPoint &kern) const { FT_Vector kerning; if (FT_Get_Kerning(face, leftGlyph, rightGlyph, FT_KERNING_UNSCALED, &kerning) == 0) { kern.fX = kerning.x; kern.fY = kerning.y; } else kern.fX = kern.fY = 0; }
double font::kerning( char32_t c1, char32_t c2 ) { FT_Vector kerning; FT_UInt prev_index = FT_Get_Char_Index( _face, c1 ); FT_UInt next_index = FT_Get_Char_Index( _face, c2 ); FT_Get_Kerning( _face, prev_index, next_index, FT_KERNING_UNFITTED, &kerning ); return kerning.x / ( 64.0 * 64.0 ); }
static void draw_chars(VGFT_FONT_T *font, const char *text, int char_count, VGbitfield paint_modes, int peek) { // Put in first character glyph_indices[0] = FT_Get_Char_Index(font->ft_face, text[0]); int prev_glyph_index = glyph_indices[0]; // Calculate glyph_indices and adjustments FT_Vector kern; int i; for (i = 1; i != char_count; ++i) { int glyph_index = FT_Get_Char_Index(font->ft_face, text[i]); if (!glyph_index) return; glyph_indices[i] = glyph_index; if (FT_Get_Kerning(font->ft_face, prev_glyph_index, glyph_index, FT_KERNING_DEFAULT, &kern)) { assert(0); } adjustments_x[i - 1] = float_from_26_6(kern.x); adjustments_y[i - 1] = float_from_26_6(kern.y); prev_glyph_index = glyph_index; } // Get the last adjustment? if (peek) { int peek_glyph_index = FT_Get_Char_Index(font->ft_face, text[i]); if (!peek_glyph_index) return; if (FT_Get_Kerning(font->ft_face, prev_glyph_index, peek_glyph_index, FT_KERNING_DEFAULT, &kern)) { assert(0); } adjustments_x[char_count - 1] = float_from_26_6(kern.x); adjustments_y[char_count - 1] = float_from_26_6(kern.y); } else { adjustments_x[char_count - 1] = 0.0f; adjustments_y[char_count - 1] = 0.0f; } vgDrawGlyphs(font->vg_font, char_count, glyph_indices, adjustments_x, adjustments_y, paint_modes, VG_FALSE); }
JNIEXPORT jint JNICALL Java_com_badlogic_gdx_graphics_g2d_freetype_FreeType_getKerning(JNIEnv* env, jclass clazz, jlong face, jint leftGlyph, jint rightGlyph, jint kernMode) { //@line:664 FT_Vector kerning; FT_Error error = FT_Get_Kerning((FT_Face)face, leftGlyph, rightGlyph, kernMode, &kerning); if(error) return 0; return kerning.x; }
int TextureFont::PickCharacter(const char *str, float mouseX, float mouseY) const { assert(str && mouseX >= 0.0f && mouseY >= 0.0f); // at the point of the mouse in-box test, the vars have the following values: // i1: the index of the character being tested // i2: the index of the next character // charBytes: the number of bytes used to encode the next character // right: the right edge of the box being tested // bottom: the bottom of the box being tested // x: the x-coordinate of the next character // chr1: the Unicode value of the character being tested // chr2: the Unicode value of the next character Uint32 chr2 = '\n'; // pretend we've just had a new line float bottom = 0.0f, x = 0.0f; int i2 = 0, charBytes = 0; do { int i1 = i2; Uint32 chr1 = chr2; // read the next character i2 += charBytes; charBytes = utf8_decode_char(&chr2, &str[i2]); assert(!str[i2] || charBytes); // assert valid encoding float right; if (chr1 == '\n') { right = std::numeric_limits<float>::max(); x = 0.0f; } else { const glfglyph_t &glyph = GetGlyph(chr1); float advance = glyph.advx; if (chr2 != '\n' && chr2 != '\0') { FT_Vector kern; FT_Get_Kerning(m_face, glyph.ftIndex, GetGlyph(chr2).ftIndex, FT_KERNING_UNFITTED, &kern); advance += float(kern.x) / 64.0f; } right = x + (advance / 2.0f); x += advance; } if ((mouseY < bottom) && (mouseX < right)) return i1; if (chr1 == '\n') bottom += GetHeight(); } while (charBytes); return i2; }
/** * @internal * Calculate the kerning between "left" and "right. * * @param fi the font instance to use * @param left the left glyph index * @param right the right glyph index * @param[out] kerning the kerning calculated. * @return FALSE on error, TRUE on success. */ EAPI int evas_common_font_query_kerning(RGBA_Font_Int *fi, FT_UInt left, FT_UInt right, int *kerning) { int *result; FT_Vector delta; int key[2]; int error = 1; key[0] = left; key[1] = right; result = eina_hash_find(fi->kerning, key); if (result) { *kerning = result[2]; goto on_correct; } /* NOTE: ft2 seems to have a bug. and sometimes returns bizarre * values to kern by - given same font, same size and same * prev_index and index. auto/bytecode or none hinting doesn't * matter */ evas_common_font_int_reload(fi); FTLOCK(); if (FT_Get_Kerning(fi->src->ft.face, key[0], key[1], FT_KERNING_DEFAULT, &delta) == 0) { int *push; FTUNLOCK(); *kerning = delta.x; push = malloc(sizeof (int) * 3); if (!push) return 1; push[0] = key[0]; push[1] = key[1]; push[2] = *kerning; eina_hash_direct_add(fi->kerning, push, push); goto on_correct; } FTUNLOCK(); error = 0; on_correct: return error; }
void gfx_font_adapter::add_kerning(unsigned int first, unsigned int second, scalar* x, scalar* y) { if (m_impl->font && first && second && FT_HAS_KERNING(m_impl->font)) { FT_Vector delta; FT_Get_Kerning(m_impl->font, first, second, FT_KERNING_DEFAULT, &delta); scalar dx = int26p6_to_flt(delta.x); scalar dy = int26p6_to_flt(delta.y); if (m_impl->font->glyph->format != FT_GLYPH_FORMAT_BITMAP) m_impl->matrix.transform_2x2(&dx, &dy); *x += dx; *y += dy; } }
static void glyphstring_create(FT_Face face, Text *text, FT_Glyph *glyph_string, FT_Vector *pos) { const uint8_t *string = text->string; FT_Bool has_kerning; FT_UInt glyph_index, previous; FT_Vector pen, delta; uint32_t charcode; int i; has_kerning = FT_HAS_KERNING(face); previous = 0; i = 0; pen.x = pen.y = 0; while (string[0] != '\0') { charcode = utf8_next(&string); glyph_index = FT_Get_Char_Index(face, charcode); if (has_kerning && previous && glyph_index) FT_Get_Kerning(face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); else delta.x = 0; if (glyph_index == 0) log_err("Glyph for character U+%X missing\n", charcode); if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER) != 0) { log_err("Error loading glyph for character U+%X\n", charcode); continue; } if (FT_Get_Glyph(face->glyph, &glyph_string[i]) != 0) { log_err("Error copying glyph for character U+%X\n", charcode); continue; } pen.x += delta.x; pos[i] = pen; pen.x += face->glyph->advance.x; pen.y += face->glyph->advance.y; previous = glyph_index; i++; } text->num_glyphs = i; }
bool Font::drawString(const std::wstring& s, float x, float y) { bool Ret = true; float penX = x, penY = y; uint32_t previousGlyph = 0; FT_Vector Delta; CacheEntry* theGlyph = NULL; std::size_t Length = s.length(); for (std::size_t i = 0; i < Length; ++i) { if (mAutoCache) cacheChar(s[i]); //Special cases switch (s[i]) { case L'\t': penX += spaceAdvance() * TabSize; previousGlyph = 0; continue; case L'\v': penY += mHeight * TabSize; previousGlyph = 0; continue; case L'\n': penY += mHeight; penX = x; previousGlyph = 0; continue; } theGlyph = getCacheEntry(s[i]); if (theGlyph == NULL) { Ret = false; previousGlyph = 0; continue; } //Kerning if (previousGlyph != 0 && mHaveKerning && mUseKerning) { FT_Get_Kerning(mFace, previousGlyph, theGlyph->glyphIndex, FT_KERNING_DEFAULT, &Delta); penX += Delta.x >> 6; penY += Delta.y >> 6; } if (!drawChar(s[i], penX, penY)) Ret = false; penX += theGlyph->Advance; previousGlyph = theGlyph->glyphIndex; }
// ------------------------------------------ texture_font_generate_kerning --- void texture_font_generate_kerning( texture_font_t *self ) { size_t i, j; FT_Library library; FT_Face face; FT_UInt glyph_index, prev_index; texture_glyph_t *glyph, *prev_glyph; FT_Vector kerning; assert( self ); /* Load font */ // if( !texture_font_load_face( &library, self->filename, self->size, &face ) ) // { // return; // } if( !texture_font_load_face( self, &library, self->size, &face ) )// <----- changed { return; } /* For each glyph couple combination, check if kerning is necessary */ /* Starts at index 1 since 0 is for the special backgroudn glyph */ for( i=1; i<self->glyphs->size; ++i ) { glyph = *(texture_glyph_t **) vector_get( self->glyphs, i ); glyph_index = FT_Get_Char_Index( face, glyph->charcode ); vector_clear( glyph->kerning ); for( j=1; j<self->glyphs->size; ++j ) { prev_glyph = *(texture_glyph_t **) 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 ); // printf("%c(%d)-%c(%d): %ld\n", // prev_glyph->charcode, prev_glyph->charcode, // glyph_index, glyph_index, kerning.x); if( kerning.x ) { // 64 * 64 because of 26.6 encoding AND the transform matrix used // in texture_font_load_face (hres = 64) kerning_t k = {prev_glyph->charcode, kerning.x / (float)(64.0f*64.0f)}; vector_push_back( glyph->kerning, &k ); } } } FT_Done_Face( face ); FT_Done_FreeType( library ); }
void FT2Font::load_glyphs() { _VERBOSE("FT2Font::load_glyphs"); /* a small shortcut */ FT_Bool use_kerning = FT_HAS_KERNING( face ); FT_UInt previous = 0; glyphs.resize(0); pen.x = 0; pen.y = 0; for ( unsigned int n = 0; n < text.size(); n++ ) { FT_UInt glyph_index = FT_Get_Char_Index( face, text[n] ); /* retrieve kerning distance and move pen position */ if ( use_kerning && previous && glyph_index ) { FT_Vector delta; FT_Get_Kerning( face, previous, glyph_index, ft_kerning_default, &delta ); pen.x += delta.x; } error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ); if ( error ) { std::cerr << "\tcould not load glyph for " << text[n] << std::endl; continue; } /* ignore errors, jump to next glyph */ /* extract glyph image and store it in our table */ FT_Glyph thisGlyph; error = FT_Get_Glyph( face->glyph, &thisGlyph ); if ( error ) { std::cerr << "\tcould not get glyph for " << text[n] << std::endl; continue; } /* ignore errors, jump to next glyph */ FT_Glyph_Transform( thisGlyph, 0, &pen); pen.x += face->glyph->advance.x; previous = glyph_index; glyphs.push_back(thisGlyph); } // now apply the rotation for (unsigned int n=0; n<glyphs.size(); n++) FT_Glyph_Transform(glyphs[n], &matrix, 0); }
int TTFFont::getKerningOffset(byte left, byte right) const { if (!_hasKerning) return 0; FT_UInt leftGlyph = _glyphSlots[left]; FT_UInt rightGlyph = _glyphSlots[right]; if (!leftGlyph || !rightGlyph) return 0; FT_Vector kerningVector; FT_Get_Kerning(_face, leftGlyph, rightGlyph, FT_KERNING_DEFAULT, &kerningVector); return (kerningVector.x / 64); }