/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * mozilla.org. * Portions created by the Initial Developer are Copyright (C) 2004 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Stuart Parmenter * Joe Hewitt * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsCairoFontMetrics.h" #include "nsFont.h" #include "nsDirectoryServiceDefs.h" #include "nsIFile.h" #include "nsString.h" #define FONT_FILE "Vera.ttf" #define FONT_SIZE 10 /* #define FONT_FILE "verdana.ttf" #define FONT_SIZE 12 */ #define FT_FLOOR(X) ((X & -64) >> 6) #define FT_CEIL(X) (((X + 63) & -64) >> 6) static FT_Library ftlib = nsnull; NS_IMPL_ISUPPORTS1(nsCairoFontMetrics, nsIFontMetrics) nsCairoFontMetrics::nsCairoFontMetrics() : mMaxAscent(0), mMaxDescent(0), mMaxAdvance(0), mUnderlineOffset(0), mUnderlineHeight(0) { NS_INIT_ISUPPORTS(); if (!ftlib) { FT_Init_FreeType(&ftlib); } } nsCairoFontMetrics::~nsCairoFontMetrics() { FT_Done_Face(mFace); } static char * GetFontPath() { return strdup("/tmp/fonts/" FONT_FILE); nsCOMPtr aFile; NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(aFile)); aFile->Append(NS_LITERAL_STRING(FONT_FILE)); nsAutoString pathBuf; aFile->GetPath(pathBuf); NS_LossyConvertUCS2toASCII pathCBuf(pathBuf); return strdup(pathCBuf.get()); } NS_IMETHODIMP nsCairoFontMetrics::Init(const nsFont& aFont, nsIAtom* aLangGroup, nsIDeviceContext *aContext) { mFont = aFont; mLangGroup = aLangGroup; mDeviceContext = aContext; mDev2App = 1.0; char *fontPath = GetFontPath(); FT_Error ferr = FT_New_Face(ftlib, fontPath, 0, &mFace); if (ferr != 0) { fprintf (stderr, "FT Error: %d\n", ferr); return NS_ERROR_FAILURE; } free(fontPath); FT_Set_Char_Size(mFace, 0, FONT_SIZE << 6, 72, 72); mMaxAscent = mFace->bbox.yMax; mMaxDescent = mFace->bbox.yMin; mMaxAdvance = mFace->max_advance_width; mUnderlineOffset = mFace->underline_position; mUnderlineHeight = mFace->underline_thickness; return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::Destroy() { return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetXHeight(nscoord& aResult) { aResult = NSToCoordRound(14 * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetSuperscriptOffset(nscoord& aResult) { aResult = 0; return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetSubscriptOffset(nscoord& aResult) { aResult = 0; return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize) { aOffset = 0; aSize = NSToCoordRound(1 * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetUnderline(nscoord& aOffset, nscoord& aSize) { const FT_Fixed scale = mFace->size->metrics.y_scale; aOffset = FT_FLOOR(FT_MulFix(mUnderlineOffset, scale)); aOffset = NSToCoordRound(aOffset * mDev2App); aSize = FT_CEIL(FT_MulFix(mUnderlineHeight, scale)); if (aSize > 1) aSize = 1; aSize = NSToCoordRound(aSize * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetHeight(nscoord &aHeight) { aHeight = NSToCoordRound((mFace->size->metrics.height >> 6) * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetInternalLeading(nscoord &aLeading) { // aLeading = 0 * mDev2App; aLeading = 0; return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetExternalLeading(nscoord &aLeading) { // aLeading = 0 * mDev2App; aLeading = 0; return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetEmHeight(nscoord &aHeight) { /* ascent + descent */ #if FONT_SIZE == 10 const nscoord emHeight = 10; #else /* XXX this is for 12px verdana ... */ const nscoord emHeight = 14; #endif aHeight = NSToCoordRound(emHeight * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetEmAscent(nscoord &aAscent) { /* units above the base line */ #if FONT_SIZE == 10 const nscoord emAscent = 10; #else /* XXX this is for 12px verdana ... */ const nscoord emAscent = 12; #endif aAscent = NSToCoordRound(emAscent * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetEmDescent(nscoord &aDescent) { /* units below the base line */ #if FONT_SIZE == 10 const nscoord emDescent = 0; #else /* XXX this is for 12px verdana ... */ const nscoord emDescent = 2; #endif aDescent = NSToCoordRound(emDescent * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetMaxHeight(nscoord &aHeight) { /* ascent + descent */ aHeight = FT_CEIL(FT_MulFix(mMaxAscent, mFace->size->metrics.y_scale)) - FT_CEIL(FT_MulFix(mMaxDescent, mFace->size->metrics.y_scale)) + 1; aHeight = NSToCoordRound(aHeight * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetMaxAscent(nscoord &aAscent) { /* units above the base line */ aAscent = FT_CEIL(FT_MulFix(mMaxAscent, mFace->size->metrics.y_scale)); aAscent = NSToCoordRound(aAscent * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetMaxDescent(nscoord &aDescent) { /* units below the base line */ aDescent = -FT_CEIL(FT_MulFix(mMaxDescent, mFace->size->metrics.y_scale)); aDescent = NSToCoordRound(aDescent * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetMaxAdvance(nscoord &aAdvance) { aAdvance = FT_CEIL(FT_MulFix(mMaxAdvance, mFace->size->metrics.x_scale)); aAdvance = NSToCoordRound(aAdvance * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetLangGroup(nsIAtom** aLangGroup) { *aLangGroup = mLangGroup; NS_IF_ADDREF(*aLangGroup); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetFontHandle(nsFontHandle &aHandle) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsCairoFontMetrics::GetAveCharWidth(nscoord& aAveCharWidth) { aAveCharWidth = NSToCoordRound(7 * mDev2App); return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetSpaceWidth(nscoord& aSpaceCharWidth) { FT_Load_Char(mFace, ' ', FT_LOAD_DEFAULT | FT_LOAD_NO_AUTOHINT); aSpaceCharWidth = NSToCoordRound((mFace->glyph->advance.x >> 6) * mDev2App); return NS_OK; } nscoord nsCairoFontMetrics::MeasureString(const char *aString, PRUint32 aLength) { nscoord width = 0; PRUint32 i; int error; FT_UInt glyph_index; FT_UInt previous = 0; for (i=0; i < aLength; ++i) { glyph_index = FT_Get_Char_Index(mFace, aString[i]); /* if (previous && glyph_index) { FT_Vector delta; FT_Get_Kerning(mFace, previous, glyph_index, FT_KERNING_DEFAULT, &delta); width += delta.x >> 6; } */ error = FT_Load_Glyph(mFace, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_NO_AUTOHINT); if (error) continue; width += mFace->glyph->advance.x; previous = glyph_index; } return NSToCoordRound((width >> 6) * mDev2App); } nscoord nsCairoFontMetrics::MeasureString(const PRUnichar *aString, PRUint32 aLength) { nscoord width = 0; PRUint32 i; int error; FT_UInt glyph_index; FT_UInt previous = 0; for (i=0; i < aLength; ++i) { glyph_index = FT_Get_Char_Index(mFace, aString[i]); /* if (previous && glyph_index) { FT_Vector delta; FT_Get_Kerning(mFace, previous, glyph_index, FT_KERNING_DEFAULT, &delta); width += delta.x >> 6; } */ error = FT_Load_Glyph(mFace, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_NO_AUTOHINT); if (error) continue; width += mFace->glyph->advance.x; previous = glyph_index; } return NSToCoordRound((width >> 6) * mDev2App); } NS_IMETHODIMP nsCairoFontMetrics::GetLeading(nscoord& aLeading) { aLeading = 0; return NS_OK; } NS_IMETHODIMP nsCairoFontMetrics::GetNormalLineHeight(nscoord& aLineHeight) { aLineHeight = 10; return NS_OK; }