T42_Size_Request( FT_Size t42size, /* T42_Size */ FT_Size_Request req ) { T42_Size size = (T42_Size)t42size; T42_Face face = (T42_Face)t42size->face; FT_Error error; FT_Activate_Size( size->ttsize ); error = FT_Request_Size( face->ttf_face, req ); if ( !error ) t42size->metrics = face->ttf_face->size->metrics; return error; }
T42_Size_Init( FT_Size size ) /* T42_Size */ { T42_Size t42size = (T42_Size)size; FT_Face face = size->face; T42_Face t42face = (T42_Face)face; FT_Size ttsize; FT_Error error; error = FT_New_Size( t42face->ttf_face, &ttsize ); t42size->ttsize = ttsize; FT_Activate_Size( ttsize ); return error; }
/* * Class: sage_FreetypeFont * Method: deriveFontFace0 * Signature: (JI)J */ JNIEXPORT jlong JNICALL Java_sage_FreetypeFont_deriveFontFace0 (JNIEnv *env, jobject jo, jlong fontPtr, jint ptSize, jint style) { FTDataStruct* fontData = (FTDataStruct*)(intptr_t) fontPtr; FT_Size newSize; int error = FT_New_Size(fontData->facePtr, &newSize); if (error) { sysOutPrint(env, "Error deriving freetype font of %d\r\n", error); return 0; } FT_Activate_Size(newSize); int scrnDPI = 72;//96; error = FT_Set_Char_Size( fontData->facePtr, /* handle to face object */ 0, /* char_width in 1/64th of points */ (int)(ptSize*64 + 0.5f), /* char_height in 1/64th of points */ scrnDPI, /* horizontal device resolution */ scrnDPI ); /* vertical device resolution */ if (error) { sysOutPrint(env, "Error setting freetype char size of %d\r\n", error); return 0; } FTDataStruct* rv = (FTDataStruct*)malloc(sizeof(FTDataStruct)); rv->sizePtr = newSize; rv->facePtr = fontData->facePtr; rv->style = 0; // Remove styles already applied to the TTF itself if ((style & sage_FreetypeFont_BOLD) != 0) { if ((fontData->facePtr->style_flags & FT_STYLE_FLAG_BOLD) == 0) { rv->style = rv->style | FT_STYLE_FLAG_BOLD; } } if ((style & sage_FreetypeFont_ITALIC) != 0) { if ((fontData->facePtr->style_flags & FT_STYLE_FLAG_ITALIC) == 0) { rv->style = rv->style | FT_STYLE_FLAG_ITALIC; } } return (jlong)(intptr_t) rv; }
T42_Size_Select( FT_Size t42size, /* T42_Size */ FT_ULong strike_index ) { T42_Size size = (T42_Size)t42size; T42_Face face = (T42_Face)t42size->face; FT_Error error; FT_Activate_Size( size->ttsize ); error = FT_Select_Size( face->ttf_face, (FT_Int)strike_index ); if ( !error ) t42size->metrics = face->ttf_face->size->metrics; return error; }
T42_Size_SetChars( T42_Size size, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt horz_resolution, FT_UInt vert_resolution ) { FT_Face face = size->root.face; T42_Face t42face = (T42_Face)face; FT_Activate_Size( size->ttsize ); return FT_Set_Char_Size( t42face->ttf_face, char_width, char_height, horz_resolution, vert_resolution ); }
/* * Class: FreetypeFont * Method: renderGlyph0 * Signature: (JLjava/awt/image/BufferedImage;II)I */ JNIEXPORT jint JNICALL Java_sage_FreetypeFont_renderGlyph0 (JNIEnv *env, jobject jo, jlong fontPtr, jobject buffImage, jint imageX, jint imageY) { FTDataStruct* fontData = (FTDataStruct*)(intptr_t) fontPtr; FT_Face face = fontData->facePtr; FT_Activate_Size(fontData->sizePtr); int error = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if (error) return error; static jmethodID biSetRGB = 0; static jmethodID biGetWidth = 0; static jmethodID biGetHeight = 0; if (!biSetRGB) { biSetRGB = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, buffImage), "setRGB", "(III)V"); biGetWidth = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, buffImage), "getWidth", "()I"); biGetHeight = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, buffImage), "getHeight", "()I"); } int width = face->glyph->bitmap.width; int height = face->glyph->bitmap.rows; int x=0,y=0; imageX += face->glyph->bitmap_left; imageY -= face->glyph->bitmap_top; // imageY += (face->size->metrics.ascender >> 6); int biWidth = (*env)->CallIntMethod(env, buffImage, biGetWidth); int biHeight = (*env)->CallIntMethod(env, buffImage, biGetHeight); unsigned char* bufPtr = face->glyph->bitmap.buffer; for (;y < height; y++, bufPtr += face->glyph->bitmap.pitch) { if (imageY + y < 0 || imageY + y >= biHeight) continue; for (x = 0; x < width; x++) { if (imageX + x < 0 || imageX + x >= biWidth) continue; unsigned char bv = *(bufPtr + x); int color = (bv << 24) | (bv << 16) | (bv << 8) | bv; (*env)->CallVoidMethod(env, buffImage, biSetRGB, x + imageX, y + imageY, color); } } return 0; }
FTC_Manager_Lookup_Size( FTC_Manager manager, FTC_Font font, FT_Face *aface, FT_Size *asize ) { FT_Error error; /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */ if ( aface ) *aface = 0; if ( asize ) *asize = 0; error = FTC_Manager_Lookup_Face( manager, font->face_id, aface ); if ( !error ) { FTC_SizeQueryRec query; FTC_SizeNode node; query.face = *aface; query.width = font->pix_width; query.height = font->pix_height; error = FT_LruList_Lookup( manager->sizes_list, (FT_LruKey)&query, (FT_LruNode*)&node ); if ( !error ) { /* select the size as the current one for this face */ FT_Activate_Size( node->size ); if ( asize ) *asize = node->size; } } return error; }
static int setupFTContext(JNIEnv *env, jobject font2D, FTScalerInfo *scalerInfo, FTScalerContext *context) { int errCode = 0; scalerInfo->env = env; scalerInfo->font2D = font2D; if (context != NULL) { FT_Set_Transform(scalerInfo->face, &context->transform, NULL); errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72); if (errCode == 0) { errCode = FT_Activate_Size(scalerInfo->face->size); } } return errCode; }
static FT_Error ftc_scaler_lookup_size( FTC_Manager manager, FTC_Scaler scaler, FT_Size *asize ) { FT_Face face; FT_Size size = NULL; FT_Error error; error = FTC_Manager_LookupFace( manager, scaler->face_id, &face ); if ( error ) goto Exit; error = FT_New_Size( face, &size ); if ( error ) goto Exit; FT_Activate_Size( size ); if ( scaler->pixel ) error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height ); else error = FT_Set_Char_Size( face, (FT_F26Dot6)scaler->width, (FT_F26Dot6)scaler->height, scaler->x_res, scaler->y_res ); if ( error ) { FT_Done_Size( size ); size = NULL; } Exit: *asize = size; return error; }
ftc_size_node_init( FTC_SizeNode node, FTC_SizeQuery query ) { FT_Face face = query->face; FT_Size size; FT_Error error; node->size = NULL; error = FT_New_Size( face, &size ); if ( !error ) { FT_Activate_Size( size ); error = FT_Set_Pixel_Sizes( query->face, query->width, query->height ); if ( error ) FT_Done_Size( size ); else node->size = size; } return error; }
static Font_Info * _font_slave_int_load(const Slave_Msg_Font_Load *msg, Font_Source_Info *fsi) { int error; int val, dv; int ret; Font_Info *fi = calloc(1, sizeof(*fi)); error = FT_New_Size(fsi->face, &(fi->size)); if (!error) FT_Activate_Size(fi->size); fi->fsize = msg->size; fi->dpi = msg->dpi; fi->real_size = msg->size * 64; fi->fsi = fsi; error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, msg->dpi, msg->dpi); if (error) error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size); if (error) { int i, maxd = 0x7fffffff; int chosen_size = 0; int chosen_size2 = 0; for (i = 0; i < fsi->face->num_fixed_sizes; i++) { int s, cd; s = fsi->face->available_sizes[i].size; cd = chosen_size - fi->real_size; if (cd < 0) cd = -cd; if (cd < maxd) { maxd = cd; chosen_size = s; chosen_size2 = fsi->face->available_sizes[i].y_ppem; if (maxd == 0) break; } } fi->real_size = chosen_size; error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size); if (error) { error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, fi->dpi, fi->dpi); if (error) { /* hack around broken fonts */ fi->real_size = (chosen_size2 / 64) * 60; error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, fi->dpi, fi->dpi); if (error) { ERR("Could not choose the font size for font: '%s:%s'.", msg->file, msg->name); FT_Done_Size(fi->size); free(fi); return NULL; } } } } fi->max_h = 0; val = (int)fsi->face->bbox.yMax; if (fsi->face->units_per_EM != 0) { dv = (fsi->orig_upem * 2048) / fsi->face->units_per_EM; ret = (val * fsi->face->size->metrics.y_scale) / (dv * dv); } else ret = val; fi->max_h += ret; val = -(int)fsi->face->bbox.yMin; if (fsi->face->units_per_EM != 0) { dv = (fsi->orig_upem * 2048) / fsi->face->units_per_EM; ret = (val * fsi->face->size->metrics.y_scale) / (dv * dv); } else ret = val; fi->max_h += ret; fi->runtime_rend = FONT_REND_REGULAR; if ((msg->rend_flags & FONT_REND_SLANT) && !(fsi->face->style_flags & FT_STYLE_FLAG_ITALIC)) fi->runtime_rend |= FONT_REND_SLANT; if ((msg->rend_flags & FONT_REND_WEIGHT) && !(fsi->face->style_flags & FT_STYLE_FLAG_BOLD)) fi->runtime_rend |= FONT_REND_WEIGHT; return fi; }
EAPI Eina_Bool evas_common_text_props_content_create(void *_fi, const Eina_Unicode *text, Evas_Text_Props *text_props, const Evas_BiDi_Paragraph_Props *par_props, size_t par_pos, int len) { RGBA_Font_Int *fi = (RGBA_Font_Int *) _fi; if (text_props->info) { evas_common_text_props_content_unref(text_props); } if (len == 0) { text_props->info = NULL; text_props->start = text_props->len = text_props->text_offset = 0; } text_props->info = calloc(1, sizeof(Evas_Text_Props_Info)); text_props->font_instance = fi; evas_common_font_int_reload(fi); if (fi->src->current_size != fi->size) { FTLOCK(); FT_Activate_Size(fi->ft.size); FTUNLOCK(); fi->src->current_size = fi->size; } #ifdef OT_SUPPORT size_t char_index; Evas_Font_Glyph_Info *gl_itr; Evas_Coord pen_x = 0, adjust_x = 0; (void) par_props; (void) par_pos; evas_common_font_ot_populate_text_props(text, text_props, len); gl_itr = text_props->info->glyph; for (char_index = 0 ; char_index < text_props->len ; char_index++) { FT_UInt idx; RGBA_Font_Glyph *fg; Eina_Bool is_replacement = EINA_FALSE; /* If we got a malformed index, show the replacement char instead */ if (gl_itr->index == 0) { gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR); is_replacement = EINA_TRUE; } idx = gl_itr->index; LKL(fi->ft_mutex); fg = evas_common_font_int_cache_glyph_get(fi, idx); if (!fg) { LKU(fi->ft_mutex); continue; } LKU(fi->ft_mutex); gl_itr->x_bear = fg->glyph_out->left; gl_itr->width = fg->glyph_out->bitmap.width; /* text_props->info->glyph[char_index].advance = * text_props->info->glyph[char_index].index = * already done by the ot function */ if (EVAS_FONT_CHARACTER_IS_INVISIBLE( text[text_props->info->ot[char_index].source_cluster])) { gl_itr->index = 0; /* Reduce the current advance */ if (gl_itr > text_props->info->glyph) { adjust_x -= gl_itr->pen_after - (gl_itr - 1)->pen_after; } else { adjust_x -= gl_itr->pen_after; } } else { if (is_replacement) { /* Update the advance accordingly */ adjust_x += (pen_x + (fg->glyph->advance.x >> 16)) - gl_itr->pen_after; } pen_x = gl_itr->pen_after; } gl_itr->pen_after += adjust_x; fi = text_props->font_instance; gl_itr++; } #else /* We are walking the string in visual ordering */ Evas_Font_Glyph_Info *gl_itr; Eina_Bool use_kerning; FT_UInt prev_index; FT_Face pface = NULL; Evas_Coord pen_x = 0; int adv_d, i; #if !defined(OT_SUPPORT) && defined(BIDI_SUPPORT) Eina_Unicode *base_str = NULL; if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) { text = base_str = eina_unicode_strndup(text, len); evas_bidi_shape_string(base_str, par_props, par_pos, len); } #else (void) par_props; (void) par_pos; #endif FTLOCK(); use_kerning = FT_HAS_KERNING(fi->src->ft.face); FTUNLOCK(); prev_index = 0; i = len; text_props->info->glyph = calloc(len, sizeof(Evas_Font_Glyph_Info)); if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) { text += len - 1; adv_d = -1; } else { adv_d = 1; } gl_itr = text_props->info->glyph; for ( ; i > 0 ; gl_itr++, text += adv_d, i--) { FT_UInt idx; RGBA_Font_Glyph *fg; int _gl, kern; Evas_Coord adv; _gl = *text; if (_gl == 0) break; idx = evas_common_get_char_index(fi, _gl); if (idx == 0) { idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR); } LKL(fi->ft_mutex); fg = evas_common_font_int_cache_glyph_get(fi, idx); if (!fg) { LKU(fi->ft_mutex); continue; } kern = 0; if ((use_kerning) && (prev_index) && (idx) && (pface == fi->src->ft.face)) { if (evas_common_font_query_kerning(fi, prev_index, idx, &kern)) { pen_x += kern; (gl_itr - 1)->pen_after += EVAS_FONT_ROUND_26_6_TO_INT(kern); } } pface = fi->src->ft.face; LKU(fi->ft_mutex); gl_itr->index = idx; gl_itr->x_bear = fg->glyph_out->left; adv = fg->glyph->advance.x >> 10; gl_itr->width = fg->glyph_out->bitmap.width; if (EVAS_FONT_CHARACTER_IS_INVISIBLE(_gl)) { gl_itr->index = 0; } else { pen_x += adv; } gl_itr->pen_after = EVAS_FONT_ROUND_26_6_TO_INT(pen_x); prev_index = idx; } text_props->len = len; # if !defined(OT_SUPPORT) && defined(BIDI_SUPPORT) if (base_str) free(base_str); # endif #endif text_props->text_len = len; text_props->info->refcount = 1; return EINA_TRUE; }
Font::TextSize Font::process(int x, int y, text_iterator start, text_iterator end, Color color) { FT_Activate_Size(m_size); Vec2f pen(x, y); int startX = 0; int endX = 0; if(DoDraw) { // Subtract one line height (since we flipped the Y origin to be like GDI) pen.y += m_size->metrics.ascender >> 6; } FT_UInt prevGlyphIndex = 0; FT_Pos prevRsbDelta = 0; std::vector< std::vector<TexturedVertex> > mapTextureVertices; for(text_iterator it = start; it != end; ) { // Get glyph in glyph map glyph_iterator itGlyph = getNextGlyph(it, end); if(itGlyph == m_glyphs.end()) { continue; } const Glyph & glyph = itGlyph->second; // Kerning if(FT_HAS_KERNING(m_size->face)) { if(prevGlyphIndex != 0) { FT_Vector delta; FT_Get_Kerning(m_size->face, prevGlyphIndex, glyph.index, FT_KERNING_DEFAULT, &delta); pen.x += delta.x >> 6; } prevGlyphIndex = glyph.index; } // Auto hinting adjustments if(prevRsbDelta - glyph.lsb_delta >= 32) { pen.x--; } else if(prevRsbDelta - glyph.lsb_delta < -32) { pen.x++; } prevRsbDelta = glyph.rsb_delta; // Draw if(DoDraw && glyph.size.x != 0 && glyph.size.y != 0) { if(glyph.texture >= mapTextureVertices.size()) { mapTextureVertices.resize(glyph.texture + 1); } addGlyphVertices(mapTextureVertices[glyph.texture], glyph, pen, color); } else { ARX_UNUSED(pen), ARX_UNUSED(color); } // If this is the first drawn char, note the start position if(startX == endX) { startX = glyph.draw_offset.x; } endX = s32(pen.x) + glyph.draw_offset.x + glyph.size.x; // Advance pen.x += glyph.advance.x; }
SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) : SkScalerContext(desc), fFTSize(NULL) { SkAutoMutexAcquire ac(gFTMutex); FT_Error err; if (gFTCount == 0) { err = FT_Init_FreeType(&gFTLibrary); // SkDEBUGF(("FT_Init_FreeType returned %d\n", err)); SkASSERT(err == 0); } ++gFTCount; // load the font file fFaceRec = ref_ft_face(fRec.fFontID); fFace = fFaceRec ? fFaceRec->fFace : NULL; // compute our factors from the record SkMatrix m; fRec.getSingleMatrix(&m); #ifdef DUMP_STRIKE_CREATION SkString keyString; SkFontHost::GetDescriptorKeyString(desc, &keyString); printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n", SkScalarToFloat(fRec.fTextSize), SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX), SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]), SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]), fRec.fHints, fRec.fMaskFormat, keyString.c_str()); #endif // now compute our scale factors SkScalar sx = m.getScaleX(); SkScalar sy = m.getScaleY(); if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) { // sort of give up on hinting sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX())); sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy)); sx = sy = SkScalarAve(sx, sy); SkScalar inv = SkScalarInvert(sx); // flip the skew elements to go from our Y-down system to FreeType's fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv)); fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv)); fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv)); fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv)); } else { fMatrix22.xx = fMatrix22.yy = SK_Fixed1; fMatrix22.xy = fMatrix22.yx = 0; } fScaleX = SkScalarToFixed(sx); fScaleY = SkScalarToFixed(sy); // compute the flags we send to Load_Glyph { uint32_t flags = FT_LOAD_DEFAULT; uint32_t render_flags = FT_LOAD_TARGET_NORMAL; // we force autohinting at the moment switch (fRec.fHints) { case kNo_Hints: flags |= FT_LOAD_NO_HINTING; break; case kSubpixel_Hints: flags |= FT_LOAD_FORCE_AUTOHINT; render_flags = FT_LOAD_TARGET_LIGHT; break; case kNormal_Hints: flags |= FT_LOAD_FORCE_AUTOHINT; #ifdef ANDROID /* Switch to light hinting (vertical only) to address some chars that behaved poorly with NORMAL. In the future we could consider making this choice exposed at runtime to the caller. */ render_flags = FT_LOAD_TARGET_LIGHT; #endif break; } if (SkMask::kBW_Format == fRec.fMaskFormat) render_flags = FT_LOAD_TARGET_MONO; else if (SkMask::kLCD_Format == fRec.fMaskFormat) render_flags = FT_LOAD_TARGET_LCD; fLoadGlyphFlags = flags | render_flags; } // now create the FT_Size { FT_Error err; err = FT_New_Size(fFace, &fFTSize); if (err != 0) { SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%x): FT_Set_Char_Size(0x%x, 0x%x) returned 0x%x\n", fFaceRec->fFontID, fScaleX, fScaleY, err)); fFace = NULL; return; } err = FT_Activate_Size(fFTSize); if (err != 0) { SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n", fFaceRec->fFontID, fScaleX, fScaleY, err)); fFTSize = NULL; } err = FT_Set_Char_Size( fFace, SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY), 72, 72); if (err != 0) { SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%x, 0x%x, 0x%x) returned 0x%x\n", fFaceRec->fFontID, fScaleX, fScaleY, err)); fFace = NULL; return; } FT_Set_Transform( fFace, &fMatrix22, NULL); } }
/* * Class: sage_FreetypeFont * Method: renderGlyphRaw0 * Signature: (JLsage/media/image/RawImage;IIII)Lsage/media/image/RawImage; */ JNIEXPORT jobject JNICALL Java_sage_FreetypeFont_renderGlyphRaw0 (JNIEnv *env, jobject jo, jlong fontPtr, jobject inRawImage, jint rawWidth, jint rawHeight, jint imageX, jint imageY) { static jclass rawImageClass = 0; static jmethodID rawImageConstruct = 0; static jmethodID getDataMeth = 0; if (!rawImageClass) { rawImageClass = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "sage/media/image/RawImage")); if ((*env)->ExceptionOccurred(env)) { return NULL; } rawImageConstruct = (*env)->GetMethodID(env, rawImageClass, "<init>", "(IILjava/nio/ByteBuffer;ZI)V"); if ((*env)->ExceptionOccurred(env)) { return NULL; } getDataMeth = (*env)->GetMethodID(env, rawImageClass, "getData", "()Ljava/nio/ByteBuffer;"); if ((*env)->ExceptionOccurred(env)) { return NULL; } } jobject rv = inRawImage; unsigned char* myImageData = NULL; if (!rv) { sysOutPrint(env, "Creating new RawImage for font rendering w=%d h=%d\r\n", rawWidth, rawHeight); // Create the RawImage object and the native buffer for it if it doesn't exist yet myImageData = (unsigned char*) calloc(4*rawWidth*rawHeight, 1); jobject dbuf = (*env)->NewDirectByteBuffer(env, (void*)myImageData, 4*rawWidth*rawHeight); if ((*env)->ExceptionOccurred(env)) { free(myImageData); return NULL; } rv = (*env)->NewObject(env, rawImageClass, rawImageConstruct, rawWidth, rawHeight, dbuf, JNI_TRUE, 4*rawWidth); if ((*env)->ExceptionOccurred(env)) { free(myImageData); return NULL; } } else { // Get the address to the native image buffer so we can write to it jobject bb = (*env)->CallObjectMethod(env, rv, getDataMeth); if ((*env)->ExceptionOccurred(env)) { return NULL; } myImageData = (unsigned char*) (*env)->GetDirectBufferAddress(env, bb); } FTDataStruct* fontData = (FTDataStruct*)(intptr_t) fontPtr; FT_Face face = fontData->facePtr; FT_Activate_Size(fontData->sizePtr); // Render the glyph to a FT buffer int error = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if (error) return NULL; int width = face->glyph->bitmap.width; int height = face->glyph->bitmap.rows; int x=0,y=0; imageX += face->glyph->bitmap_left; imageY -= face->glyph->bitmap_top; // imageY += (face->size->metrics.ascender >> 6); unsigned char* bufPtr = face->glyph->bitmap.buffer; int yOff, off; // Copy the glyph to our image buffer for (;y < height; y++, bufPtr += face->glyph->bitmap.pitch) { if (imageY + y < 0 || imageY + y >= rawHeight) continue; yOff = (imageY + y)*rawWidth*4; for (x = 0; x < width; x++) { if (imageX + x < 0 || imageX + x >= rawWidth) continue; off = yOff + (imageX + x)*4; unsigned char bv = *(bufPtr + x); myImageData[off] = bv; myImageData[off + 1] = bv; myImageData[off + 2] = bv; myImageData[off + 3] = bv; } } return rv; }
SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) : SkScalerContext(desc) { SkAutoMutexAcquire ac(gFTMutex); if (gFTCount == 0) { if (!InitFreetype()) { sk_throw(); } } ++gFTCount; // load the font file fFTSize = NULL; fFace = NULL; fFaceRec = ref_ft_face(fRec.fFontID); if (NULL == fFaceRec) { return; } fFace = fFaceRec->fFace; // compute our factors from the record SkMatrix m; fRec.getSingleMatrix(&m); #ifdef DUMP_STRIKE_CREATION SkString keyString; SkFontHost::GetDescriptorKeyString(desc, &keyString); printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n", SkScalarToFloat(fRec.fTextSize), SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX), SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]), SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]), fRec.getHinting(), fRec.fMaskFormat, keyString.c_str()); #endif // now compute our scale factors SkScalar sx = m.getScaleX(); SkScalar sy = m.getScaleY(); if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) { // sort of give up on hinting sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX())); sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy)); sx = sy = SkScalarAve(sx, sy); SkScalar inv = SkScalarInvert(sx); // flip the skew elements to go from our Y-down system to FreeType's fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv)); fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv)); fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv)); fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv)); } else { fMatrix22.xx = fMatrix22.yy = SK_Fixed1; fMatrix22.xy = fMatrix22.yx = 0; } fScaleX = SkScalarToFixed(sx); fScaleY = SkScalarToFixed(sy); // compute the flags we send to Load_Glyph { FT_Int32 loadFlags = FT_LOAD_DEFAULT; if (SkMask::kBW_Format == fRec.fMaskFormat) { // See http://code.google.com/p/chromium/issues/detail?id=43252#c24 loadFlags = FT_LOAD_TARGET_MONO; if (fRec.getHinting() == SkPaint::kNo_Hinting) loadFlags = FT_LOAD_NO_HINTING; } else { switch (fRec.getHinting()) { case SkPaint::kNo_Hinting: loadFlags = FT_LOAD_NO_HINTING; break; case SkPaint::kSlight_Hinting: loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT break; case SkPaint::kNormal_Hinting: loadFlags = FT_LOAD_TARGET_NORMAL; break; case SkPaint::kFull_Hinting: loadFlags = FT_LOAD_TARGET_NORMAL; if (SkMask::kHorizontalLCD_Format == fRec.fMaskFormat) loadFlags = FT_LOAD_TARGET_LCD; else if (SkMask::kVerticalLCD_Format == fRec.fMaskFormat) loadFlags = FT_LOAD_TARGET_LCD_V; break; default: SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting()); break; } } if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) loadFlags |= FT_LOAD_NO_BITMAP; fLoadGlyphFlags = loadFlags; } // now create the FT_Size { FT_Error err; err = FT_New_Size(fFace, &fFTSize); if (err != 0) { SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%x): FT_Set_Char_Size(0x%x, 0x%x) returned 0x%x\n", fFaceRec->fFontID, fScaleX, fScaleY, err)); fFace = NULL; return; } err = FT_Activate_Size(fFTSize); if (err != 0) { SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n", fFaceRec->fFontID, fScaleX, fScaleY, err)); fFTSize = NULL; } err = FT_Set_Char_Size( fFace, SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY), 72, 72); if (err != 0) { SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%x, 0x%x, 0x%x) returned 0x%x\n", fFaceRec->fFontID, fScaleX, fScaleY, err)); fFace = NULL; return; } FT_Set_Transform( fFace, &fMatrix22, NULL); } }
/* * Class: FreetypeFont * Method: loadGlyph0 * Signature: (JI)V */ JNIEXPORT void JNICALL Java_sage_FreetypeFont_loadGlyph0 (JNIEnv *env, jobject jo, jlong fontPtr, jint glyphCode) { //FT_Face face = (FT_Face) facePtr; FTDataStruct* fontData = (FTDataStruct*)(intptr_t) fontPtr; FT_Activate_Size(fontData->sizePtr); int error = FT_Load_Glyph(fontData->facePtr, glyphCode, FT_LOAD_FORCE_AUTOHINT); if ((fontData->style & FT_STYLE_FLAG_BOLD) != 0) { // Apply bold effect if (fontData->facePtr->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { /* some reasonable strength */ FT_Pos strength = FT_MulFix(fontData->facePtr->units_per_EM, fontData->facePtr->size->metrics.y_scale ) / 42; FT_BBox bbox_before, bbox_after; // The bounding box code was what XBMC was using to do this calculation; but the // examples in the freetype library use the *4 math below which then doesn't clip // the text when we render it. // FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_before); FT_Outline_Embolden(&fontData->facePtr->glyph->outline, strength); // ignore error // FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_after); // FT_Pos dx = bbox_after.xMax - bbox_before.xMax; // FT_Pos dy = bbox_after.yMax - bbox_before.yMax; FT_Pos dx = strength * 4; FT_Pos dy = dx; if (fontData->facePtr->glyph->advance.x) fontData->facePtr->glyph->advance.x += dx; if (fontData->facePtr->glyph->advance.y) fontData->facePtr->glyph->advance.y += dy; fontData->facePtr->glyph->metrics.width += dx; fontData->facePtr->glyph->metrics.height += dy; fontData->facePtr->glyph->metrics.horiBearingY += dy; fontData->facePtr->glyph->metrics.horiAdvance += dx; fontData->facePtr->glyph->metrics.vertBearingX -= dx / 2; fontData->facePtr->glyph->metrics.vertBearingY += dy; fontData->facePtr->glyph->metrics.vertAdvance += dy; } } if ((fontData->style & FT_STYLE_FLAG_ITALIC) != 0) { // Apply italics effect if (fontData->facePtr->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { /* For italic, simply apply a shear transform, with an angle */ /* of about 12 degrees. */ FT_Matrix transform; transform.xx = 0x10000L; transform.yx = 0x00000L; transform.xy = 0x06000L; transform.yy = 0x10000L; FT_BBox bbox_before, bbox_after; FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_before); FT_Outline_Transform(&fontData->facePtr->glyph->outline, &transform); FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_after); FT_Pos dx = bbox_after.xMax - bbox_before.xMax; FT_Pos dy = bbox_after.yMax - bbox_before.yMax; fontData->facePtr->glyph->metrics.width += dx; fontData->facePtr->glyph->metrics.height += dy; } } }
void xd::font::render(const std::string& text, const font_style& style, xd::shader_program::handle shader, const glm::mat4& mvp, glm::vec2 *pos) { // check if we're rendering using this font or a linked font if (style.m_type && style.m_type->length() != 0) { font_map_t::iterator i = m_linked_fonts.find(*style.m_type); if (i == m_linked_fonts.end()) throw invalid_font_type(*style.m_type); font_style linked_style = style; linked_style.m_type = boost::none; i->second->render(text, linked_style, shader, mvp, pos); return; } // check if the font size is already loaded auto it = m_face->sizes.find(style.m_size); if (it == m_face->sizes.end()) { // create a new size FT_Size size; if (FT_New_Size(m_face->handle, &size) != 0) throw font_load_failed(m_filename); // free the size in catch block if something goes wrong try { if (FT_Activate_Size(size) != 0) throw font_load_failed(m_filename); // set the pixel size if (FT_Set_Pixel_Sizes(m_face->handle, 0, style.m_size) != 0) throw font_load_failed(m_filename); // pre-load 7-bit ASCII glyphs for (int i = 0; i < 128; i++) { load_glyph(i, style.m_size); } } catch (...) { // free the size and re-throw FT_Done_Size(size); throw; } // insert the newly loaded size in the map m_face->sizes.insert(std::make_pair(style.m_size, size)); } else { // activate the size FT_Activate_Size(it->second); } // bind to first texture unit glActiveTexture(GL_TEXTURE0); // setup the shader shader->use(); shader->bind_uniform(m_mvp_uniform, mvp); shader->bind_uniform(m_color_uniform, style.m_color); shader->bind_uniform(m_texture_uniform, 0); // is kerning supported FT_Bool kerning = FT_HAS_KERNING(m_face->handle); // render each glyph in the string glm::vec2 text_pos; if (pos) text_pos = *pos; FT_UInt prev_glyph_index = 0; auto i = text.begin(); while (i != text.end()) { // get the unicode code point utf8::uint32_t char_index = utf8::next(i, text.end()); // get the cached glyph, or cache if it is not yet cached const detail::font::glyph& glyph = load_glyph(char_index, style.m_size); // bind the texture glBindTexture(GL_TEXTURE_2D, glyph.texture_id); // check for kerning if (kerning && glyph.glyph_index && prev_glyph_index) { FT_Vector kerning_delta; FT_Get_Kerning(m_face->handle, prev_glyph_index, glyph.glyph_index, FT_KERNING_DEFAULT, &kerning_delta); text_pos.x += kerning_delta.x >> 6; } // calculate exact offset glm::vec2 glyph_pos = text_pos; glyph_pos.x += glyph.offset.x; glyph_pos.y += glyph.offset.y; // add optional letter spacing glyph_pos.x += style.m_letter_spacing/2; // if shadow is enabled, draw the shadow first if (style.m_shadow) { // calculate shadow position glm::vec2 shadow_pos = glyph_pos; shadow_pos.x += style.m_shadow->x; shadow_pos.y += style.m_shadow->y; // calculate shadow color glm::vec4 shadow_color = style.m_shadow->color; shadow_color.a *= style.m_color.a; // bind uniforms shader->bind_uniform(m_color_uniform, shadow_color); shader->bind_uniform(m_position_uniform, shadow_pos); // draw shadow glyph.quad_ptr->render(); // restore the text color shader->bind_uniform(m_color_uniform, style.m_color); } // if outline is enabled, draw outline if (style.m_outline) { // calculate outline color glm::vec4 outline_color = style.m_outline->color; outline_color.a *= style.m_color.a; // bind color shader->bind_uniform(m_color_uniform, outline_color); // draw font multiple times times to draw outline (EXPENSIVE!) for (int x = -style.m_outline->width; x <= style.m_outline->width; x++) { for (int y = -style.m_outline->width; y <= style.m_outline->width; y++) { if (x == 0 && y == 0) continue; shader->bind_uniform(m_position_uniform, glyph_pos + glm::vec2(x, y)); glyph.quad_ptr->render(); } } // restore the text color shader->bind_uniform(m_color_uniform, style.m_color); } // bind uniforms shader->bind_uniform(m_position_uniform, glyph_pos); // draw the glyph glyph.quad_ptr->render(); // advance the position text_pos += glyph.advance; text_pos.x += style.m_letter_spacing; // keep track of previous glyph to do kerning prev_glyph_index = glyph.glyph_index; }