unsigned int iV_GetTextHeight(const char *string) { uint32_t height; TextRun tr(string, "en", HB_SCRIPT_COMMON, HB_DIRECTION_LTR); std::tie(std::ignore, height) = getShaper().getTextMetrics(tr, getFTFace(s_FondID)); return height; }
unsigned int iV_GetTextWidth(const char *string) { uint32_t width; TextRun tr(string, "en", HB_SCRIPT_COMMON, HB_DIRECTION_LTR); std::tie(width, std::ignore) = getShaper().getTextMetrics(tr, getFTFace(s_FondID)); return width; }
int nsFreeTypeFont::descent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return 0; return FT_DESIGN_UNITS_TO_PIXELS(-face->descender, face->size->metrics.y_scale); }
int nsFreeTypeFont::max_width() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return 0; return FT_DESIGN_UNITS_TO_PIXELS(face->max_advance_width, face->size->metrics.x_scale); }
PRBool nsFreeTypeFont::underline_thickness(unsigned long &val) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; val = FT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness, face->size->metrics.y_scale); return PR_TRUE; }
PRBool nsFreeTypeFont::getXHeight(unsigned long &val) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face || !val) return PR_FALSE; val = FT_DESIGN_UNITS_TO_PIXELS(face->height, face->size->metrics.y_scale); return PR_TRUE; }
PRBool nsFreeTypeFont::superscript_y(long &val) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; TT_OS2 *tt_os2; mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2); NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (!tt_os2) return PR_FALSE; val = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySuperscriptYOffset, face->size->metrics.y_scale); return PR_TRUE; }
int nsFreeTypeFont::max_descent() { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return 0; TT_OS2 *tt_os2; mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2); NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (tt_os2) return FT_DESIGN_UNITS_TO_PIXELS(-tt_os2->sTypoDescender, face->size->metrics.y_scale); else return FT_DESIGN_UNITS_TO_PIXELS(-face->bbox.yMin, face->size->metrics.y_scale); }
gint nsFreeTypeFont::GetWidth(const PRUnichar* aString, PRUint32 aLength) { FT_UInt glyph_index; FT_Glyph glyph; FT_Pos origin_x = 0; // get the face/size from the FreeType cache FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return 0; FTC_Image_Cache icache; mFt2->GetImageCache(&icache); if (!icache) return 0; PRUint32 i, extraSurrogateLength; for (i=0; i<aLength; i+=1+extraSurrogateLength) { extraSurrogateLength=0; FT_ULong code_point = aString[i]; if(i<aLength-1 && IS_HIGH_SURROGATE(code_point) && IS_LOW_SURROGATE(aString[i+1])) { // if surrogate, make UCS4 code point from high aString[i] surrogate and // low surrogate aString[i+1] code_point = SURROGATE_TO_UCS4(code_point, aString[i+1]); // skip aString[i+1], it is already used as low surrogate extraSurrogateLength = 1; } mFt2->GetCharIndex((FT_Face)face, code_point, &glyph_index); nsresult rv; rv = mFt2->ImageCacheLookup(icache, &mImageDesc, glyph_index, &glyph); NS_ASSERTION(NS_SUCCEEDED(rv),"error loading glyph"); if (NS_FAILED(rv)) { origin_x += face->size->metrics.x_ppem/2 + 2; continue; } origin_x += FT_16_16_TO_REG(glyph->advance.x); } return origin_x; }
PRBool nsFreeTypeFont::subscript_y(long &val) { FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return PR_FALSE; TT_OS2 *tt_os2; mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2); NS_ASSERTION(tt_os2, "unable to get OS2 table"); if (!tt_os2) return PR_FALSE; val = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySubscriptYOffset, face->size->metrics.y_scale); // some fonts have the sign wrong. it should be always positive. val = (val < 0) ? -val : val; return PR_TRUE; }
gint nsFreeTypeXImage::DrawString(nsRenderingContextGTK* aContext, nsDrawingSurfaceGTK* aSurface, nscoord aX, nscoord aY, const PRUnichar* aString, PRUint32 aLength) { #if DEBUG_SHOW_GLYPH_BOX PRUint32 x, y; // grey shows image size // red shows character cells // green box shows text ink #endif if (aLength < 1) { return 0; } // get the face/size from the FreeType cache FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return 0; nsresult rslt; PRInt32 leftBearing, rightBearing, ascent, descent, width; rslt = doGetBoundingMetrics(aString, aLength, &leftBearing, &rightBearing, &ascent, &descent, &width); if (NS_FAILED(rslt)) return 0; // make sure we bring down enough background for blending rightBearing = PR_MAX(rightBearing, width+1); // offset in the ximage to the x origin PRInt32 x_origin = PR_MAX(0, -leftBearing); // offset in the ximage to the x origin PRInt32 y_origin = ascent; PRInt32 x_pos = x_origin; int image_width = x_origin + rightBearing; int image_height = y_origin + PR_MAX(descent, 0); if ((image_width<=0) || (image_height<=0)) { // if we do not have any pixels then no point in trying to draw // eg: the space char has 0 height NS_ASSERTION(width>=0, "Negative width"); return width; } Display *dpy = GDK_DISPLAY(); Drawable win = GDK_WINDOW_XWINDOW(aSurface->GetDrawable()); GC gc = GDK_GC_XGC(aContext->GetGC()); XGCValues values; if (!XGetGCValues(dpy, gc, GCForeground, &values)) { NS_ERROR("failed to get foreground pixel"); return 0; } nscolor color = nsX11AlphaBlend::PixelToNSColor(values.foreground); #if DEBUG_SHOW_GLYPH_BOX // show X/Y origin XDrawLine(dpy, win, DefaultGC(dpy, 0), aX-2, aY, aX+2, aY); XDrawLine(dpy, win, DefaultGC(dpy, 0), aX, aY-2, aX, aY+2); // show width XDrawLine(dpy, win, DefaultGC(dpy, 0), aX-x_origin, aY-y_origin-2, aX+rightBearing, aY-y_origin-2); #endif // // Get the background // XImage *sub_image = nsX11AlphaBlend::GetBackground(dpy, DefaultScreen(dpy), win, aX-x_origin, aY-y_origin, image_width, image_height); if (sub_image==nsnull) { #ifdef DEBUG int screen = DefaultScreen(dpy); // complain if the requested area is not completely off screen int win_width = DisplayWidth(dpy, screen); int win_height = DisplayHeight(dpy, screen); if (((int)(aX-leftBearing+image_width) > 0) // not hidden to left && ((int)(aX-leftBearing) < win_width) // not hidden to right && ((int)(aY-ascent+image_height) > 0)// not hidden to top && ((int)(aY-ascent) < win_height)) // not hidden to bottom { NS_ASSERTION(sub_image, "failed to get the image"); } #endif return 0; } #if DEBUG_SHOW_GLYPH_BOX DEBUG_AADRAWBOX(sub_image,0,0,image_width,image_height,0,0,0,255/4); nscolor black NS_RGB(0,255,0); blendPixel blendPixelFunc = nsX11AlphaBlend::GetBlendPixel(); // x origin for (x=0; x<(unsigned int)image_height; x++) if (x%4==0) (*blendPixelFunc)(sub_image, x_origin, x, black, 255/2); // y origin for (y=0; y<(unsigned int)image_width; y++) if (y%4==0) (*blendPixelFunc)(sub_image, y, ascent-1, black, 255/2); #endif FTC_Image_Cache icache; mFt2->GetImageCache(&icache); if (!icache) return 0; // // Get aa glyphs and blend with background // blendGlyph blendGlyph = nsX11AlphaBlend::GetBlendGlyph(); PRUint32 i, extraSurrogateLength; for (i=0; i<aLength; i+=1+extraSurrogateLength) { FT_UInt glyph_index; FT_Glyph glyph; nsresult rv; FT_BBox glyph_bbox; FT_ULong code_point = aString[i]; extraSurrogateLength = 0; if(i<aLength-1 && IS_HIGH_SURROGATE(code_point) && IS_LOW_SURROGATE(aString[i+1])) { // if surrogate, make UCS4 code point from high aString[i] surrogate and // low surrogate aString[i+1] code_point = SURROGATE_TO_UCS4(code_point, aString[i+1]); // skip aString[i+1], it is already used as low surrogate extraSurrogateLength = 1; } mFt2->GetCharIndex(face, code_point, &glyph_index); if (glyph_index) { rv = mFt2->ImageCacheLookup(icache, &mImageDesc, glyph_index, &glyph); } if ((glyph_index) && (NS_SUCCEEDED(rv))) { mFt2->GlyphGetCBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox); } else { // draw an empty box for the missing glyphs GetFallbackGlyphMetrics(&glyph_bbox, face); int x, y, w = glyph_bbox.xMax, h = glyph_bbox.yMax; for (x=1; x<w; x++) { XPutPixel(sub_image, x_pos+x, ascent-1, values.foreground); XPutPixel(sub_image, x_pos+x, ascent-h, values.foreground); } for (y=1; y<h; y++) { XPutPixel(sub_image, x_pos+1, ascent-y, values.foreground); XPutPixel(sub_image, x_pos+w-1, ascent-y, values.foreground); x = (y*(w-2))/h; XPutPixel(sub_image, x_pos+x+1, ascent-y, values.foreground); } x_pos += w + 1; continue; } FT_BitmapGlyph slot = (FT_BitmapGlyph)glyph; nsAntiAliasedGlyph aaglyph(glyph_bbox.xMax-glyph_bbox.xMin, glyph_bbox.yMax-glyph_bbox.yMin, 0); PRUint8 buf[IMAGE_BUFFER_SIZE]; // try to use the stack for data if (!aaglyph.WrapFreeType(&glyph_bbox, slot, buf, IMAGE_BUFFER_SIZE)) { NS_ERROR("failed to wrap freetype image"); XDestroyImage(sub_image); return 0; } // // blend the aa-glyph onto the background // NS_ASSERTION(ascent>=glyph_bbox.yMax,"glyph too tall"); NS_ASSERTION(x_pos>=-aaglyph.GetLBearing(),"glyph extends too far to left"); #if DEBUG_SHOW_GLYPH_BOX // draw box around part of glyph that extends to the left // of the main area (negative LBearing) if (aaglyph.GetLBearing() < 0) { DEBUG_AADRAWBOX(sub_image, x_pos + aaglyph.GetLBearing(), ascent-glyph_bbox.yMax, -aaglyph.GetLBearing(), glyph_bbox.yMax, 255,0,0, 255/4); } // draw box around main glyph area DEBUG_AADRAWBOX(sub_image, x_pos, ascent-glyph_bbox.yMax, aaglyph.GetAdvance(), glyph_bbox.yMax, 0,255,0, 255/4); // draw box around part of glyph that extends to the right // of the main area (negative LBearing) if (aaglyph.GetRBearing() > (int)aaglyph.GetAdvance()) { DEBUG_AADRAWBOX(sub_image, x_pos + aaglyph.GetAdvance(), ascent-glyph_bbox.yMax, aaglyph.GetRBearing()-aaglyph.GetAdvance(), glyph_bbox.yMax, 0,0,255, 255/4); } #endif (*blendGlyph)(sub_image, &aaglyph, sLinearWeightTable, color, x_pos + aaglyph.GetLBearing(), ascent-glyph_bbox.yMax); x_pos += aaglyph.GetAdvance(); } // // Send it to the display // XPutImage(dpy, win, gc, sub_image, 0, 0, aX-x_origin , aY-ascent, image_width, image_height); XDestroyImage(sub_image); return width; }
nsresult nsFreeTypeFont::doGetBoundingMetrics(const PRUnichar* aString, PRUint32 aLength, PRInt32* aLeftBearing, PRInt32* aRightBearing, PRInt32* aAscent, PRInt32* aDescent, PRInt32* aWidth) { nsresult rv; *aLeftBearing = 0; *aRightBearing = 0; *aAscent = 0; *aDescent = 0; *aWidth = 0; if (aLength < 1) { return NS_ERROR_FAILURE; } FT_Pos pos = 0; FT_BBox bbox; // initialize to "uninitialized" values bbox.xMin = bbox.yMin = 32000; bbox.xMax = bbox.yMax = -32000; // get the face/size from the FreeType cache FT_Face face = getFTFace(); NS_ASSERTION(face, "failed to get face/size"); if (!face) return NS_ERROR_FAILURE; FTC_Image_Cache icache; mFt2->GetImageCache(&icache); if (!icache) return NS_ERROR_FAILURE; // get the text size PRUint32 i, extraSurrogateLength; for (i=0; i<aLength; i+=1+extraSurrogateLength) { FT_UInt glyph_index; FT_Glyph glyph; FT_BBox glyph_bbox; FT_Pos advance; extraSurrogateLength=0; FT_ULong code_point = aString[i]; if(i<aLength-1 && IS_HIGH_SURROGATE(code_point) && IS_LOW_SURROGATE(aString[i+1])) { // if surrogate, make UCS4 code point from high aString[i] surrogate and // low surrogate aString[i+1] code_point = SURROGATE_TO_UCS4(code_point, aString[i+1]); // skip aString[i+1], it is already used as low surrogate extraSurrogateLength = 1; } mFt2->GetCharIndex(face, code_point, &glyph_index); //NS_ASSERTION(glyph_index,"failed to get glyph"); if (glyph_index) { rv = mFt2->ImageCacheLookup(icache, &mImageDesc, glyph_index, &glyph); NS_ASSERTION(NS_SUCCEEDED(rv),"error loading glyph"); } if ((glyph_index) && (NS_SUCCEEDED(rv))) { mFt2->GlyphGetCBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox); advance = FT_16_16_TO_REG(glyph->advance.x); } else { // allocate space to draw an empty box in GetFallbackGlyphMetrics(&glyph_bbox, face); advance = glyph_bbox.xMax + 1; } bbox.xMin = PR_MIN(pos+glyph_bbox.xMin, bbox.xMin); bbox.xMax = PR_MAX(pos+glyph_bbox.xMax, bbox.xMax); bbox.yMin = PR_MIN(glyph_bbox.yMin, bbox.yMin); bbox.yMax = PR_MAX(glyph_bbox.yMax, bbox.yMax); pos += advance; } // check we got at least one size if (bbox.xMin > bbox.xMax) bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0; *aLeftBearing = bbox.xMin; *aRightBearing = bbox.xMax; *aAscent = bbox.yMax; *aDescent = -bbox.yMin; *aWidth = pos; return NS_OK; }
int iV_GetTextBelowBase(void) { FT_Face face = getFTFace(s_FondID); return face->size->metrics.descender >> 6; }
int iV_GetTextAboveBase(void) { FT_Face face = getFTFace(s_FondID); return -(face->size->metrics.ascender >> 6); }
int iV_GetTextLineSize() { FT_Face face = getFTFace(s_FondID); return (face->size->metrics.ascender - face->size->metrics.descender) >> 6; }