Back to index

lightning-sunbird  0.9+nobinonly
nsCairoFontMetrics.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * mozilla.org.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Stuart Parmenter <pavlov@pavlov.net>
00024  *   Joe Hewitt <hewitt@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsCairoFontMetrics.h"    
00041 #include "nsFont.h"
00042 
00043 #include "nsDirectoryServiceDefs.h"
00044 #include "nsIFile.h"
00045 #include "nsString.h"
00046 
00047 #define FONT_FILE "Vera.ttf"
00048 #define FONT_SIZE 10
00049 /*
00050 #define FONT_FILE "verdana.ttf"
00051 #define FONT_SIZE 12
00052 */
00053 
00054 #define FT_FLOOR(X)  ((X & -64) >> 6)
00055 #define FT_CEIL(X)   (((X + 63) & -64) >> 6)
00056 
00057 static FT_Library ftlib = nsnull;
00058 
00059 NS_IMPL_ISUPPORTS1(nsCairoFontMetrics, nsIFontMetrics)
00060 
00061 nsCairoFontMetrics::nsCairoFontMetrics() :
00062     mMaxAscent(0),
00063     mMaxDescent(0),
00064     mMaxAdvance(0),
00065     mUnderlineOffset(0),
00066     mUnderlineHeight(0)
00067 {
00068     NS_INIT_ISUPPORTS();
00069     if (!ftlib) {
00070         FT_Init_FreeType(&ftlib);
00071     }
00072 }
00073 
00074 nsCairoFontMetrics::~nsCairoFontMetrics()
00075 {
00076     FT_Done_Face(mFace);
00077 }
00078 
00079 static char *
00080 GetFontPath()
00081 {
00082     return strdup("/tmp/fonts/" FONT_FILE);
00083 
00084     nsCOMPtr<nsIFile> aFile;
00085     NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(aFile));
00086     aFile->Append(NS_LITERAL_STRING(FONT_FILE));
00087     nsAutoString pathBuf;
00088     aFile->GetPath(pathBuf);
00089     NS_LossyConvertUCS2toASCII pathCBuf(pathBuf);
00090 
00091     return strdup(pathCBuf.get());
00092 }
00093 
00094 NS_IMETHODIMP
00095 nsCairoFontMetrics::Init(const nsFont& aFont, nsIAtom* aLangGroup,
00096                          nsIDeviceContext *aContext)
00097 {
00098     mFont = aFont;
00099     mLangGroup = aLangGroup;
00100 
00101     mDeviceContext = aContext;
00102     mDev2App = 1.0;
00103 
00104     char *fontPath = GetFontPath();
00105     FT_Error ferr = FT_New_Face(ftlib, fontPath, 0, &mFace);
00106     if (ferr != 0) {
00107         fprintf (stderr, "FT Error: %d\n", ferr);
00108         return NS_ERROR_FAILURE;
00109     }
00110     free(fontPath);
00111 
00112     FT_Set_Char_Size(mFace, 0, FONT_SIZE << 6, 72, 72);
00113 
00114     mMaxAscent  = mFace->bbox.yMax;
00115     mMaxDescent = mFace->bbox.yMin;
00116     mMaxAdvance = mFace->max_advance_width;
00117 
00118     mUnderlineOffset = mFace->underline_position;
00119     mUnderlineHeight = mFace->underline_thickness;
00120 
00121     return NS_OK;
00122 }
00123 
00124 NS_IMETHODIMP
00125 nsCairoFontMetrics::Destroy()
00126 {
00127     return NS_OK;
00128 }
00129 
00130 NS_IMETHODIMP
00131 nsCairoFontMetrics::GetXHeight(nscoord& aResult)
00132 {
00133     aResult = NSToCoordRound(14 * mDev2App);
00134     return NS_OK;
00135 }
00136 
00137 NS_IMETHODIMP
00138 nsCairoFontMetrics::GetSuperscriptOffset(nscoord& aResult)
00139 {
00140     aResult = 0;
00141     return NS_OK;
00142 }
00143 
00144 NS_IMETHODIMP
00145 nsCairoFontMetrics::GetSubscriptOffset(nscoord& aResult)
00146 {
00147     aResult = 0;
00148     return NS_OK;
00149 }
00150 
00151 NS_IMETHODIMP
00152 nsCairoFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
00153 {
00154     aOffset = 0;
00155     aSize = NSToCoordRound(1 * mDev2App);
00156     return NS_OK;
00157 }
00158 
00159 NS_IMETHODIMP
00160 nsCairoFontMetrics::GetUnderline(nscoord& aOffset, nscoord& aSize)
00161 {
00162     const FT_Fixed scale = mFace->size->metrics.y_scale;
00163 
00164     aOffset = FT_FLOOR(FT_MulFix(mUnderlineOffset, scale));
00165     aOffset = NSToCoordRound(aOffset * mDev2App);
00166 
00167     aSize = FT_CEIL(FT_MulFix(mUnderlineHeight, scale));
00168     if (aSize > 1)
00169         aSize = 1;
00170     aSize = NSToCoordRound(aSize * mDev2App);
00171 
00172     return NS_OK;
00173 }
00174 
00175 NS_IMETHODIMP
00176 nsCairoFontMetrics::GetHeight(nscoord &aHeight)
00177 {
00178     aHeight = NSToCoordRound((mFace->size->metrics.height >> 6) * mDev2App);
00179     return NS_OK;
00180 }
00181 
00182 NS_IMETHODIMP
00183 nsCairoFontMetrics::GetInternalLeading(nscoord &aLeading)
00184 {
00185     // aLeading = 0 * mDev2App;
00186     aLeading = 0;
00187     return NS_OK;
00188 }
00189 
00190 NS_IMETHODIMP
00191 nsCairoFontMetrics::GetExternalLeading(nscoord &aLeading)
00192 {
00193     // aLeading = 0 * mDev2App;
00194     aLeading = 0;
00195     return NS_OK;
00196 }
00197 
00198 NS_IMETHODIMP
00199 nsCairoFontMetrics::GetEmHeight(nscoord &aHeight)
00200 {
00201     /* ascent + descent */
00202 #if FONT_SIZE == 10
00203     const nscoord emHeight = 10;
00204 #else
00205     /* XXX this is for 12px verdana ... */
00206     const nscoord emHeight = 14;
00207 #endif
00208 
00209     aHeight = NSToCoordRound(emHeight * mDev2App);
00210     return NS_OK;
00211 }
00212 
00213 NS_IMETHODIMP
00214 nsCairoFontMetrics::GetEmAscent(nscoord &aAscent)
00215 {
00216     /* units above the base line */
00217 #if FONT_SIZE == 10
00218     const nscoord emAscent = 10;
00219 #else
00220     /* XXX this is for 12px verdana ... */
00221     const nscoord emAscent = 12;
00222 #endif
00223     aAscent = NSToCoordRound(emAscent * mDev2App);
00224     return NS_OK;
00225 }
00226 
00227 NS_IMETHODIMP
00228 nsCairoFontMetrics::GetEmDescent(nscoord &aDescent)
00229 {
00230     /* units below the base line */
00231 #if FONT_SIZE == 10
00232     const nscoord emDescent = 0;
00233 #else
00234     /* XXX this is for 12px verdana ... */
00235     const nscoord emDescent = 2;
00236 #endif
00237     aDescent = NSToCoordRound(emDescent * mDev2App);
00238     return NS_OK;
00239 }
00240 
00241 NS_IMETHODIMP
00242 nsCairoFontMetrics::GetMaxHeight(nscoord &aHeight)
00243 {
00244     /* ascent + descent */
00245     aHeight = FT_CEIL(FT_MulFix(mMaxAscent, mFace->size->metrics.y_scale))
00246               - FT_CEIL(FT_MulFix(mMaxDescent, mFace->size->metrics.y_scale))
00247               + 1;
00248 
00249     aHeight = NSToCoordRound(aHeight * mDev2App);
00250     return NS_OK;
00251 }
00252 
00253 NS_IMETHODIMP
00254 nsCairoFontMetrics::GetMaxAscent(nscoord &aAscent)
00255 {
00256     /* units above the base line */
00257     aAscent = FT_CEIL(FT_MulFix(mMaxAscent, mFace->size->metrics.y_scale));
00258     aAscent = NSToCoordRound(aAscent * mDev2App);
00259     return NS_OK;
00260 }
00261 
00262 NS_IMETHODIMP
00263 nsCairoFontMetrics::GetMaxDescent(nscoord &aDescent)
00264 {
00265     /* units below the base line */
00266     aDescent = -FT_CEIL(FT_MulFix(mMaxDescent, mFace->size->metrics.y_scale));
00267     aDescent = NSToCoordRound(aDescent * mDev2App);
00268     return NS_OK;
00269 }
00270 
00271 NS_IMETHODIMP
00272 nsCairoFontMetrics::GetMaxAdvance(nscoord &aAdvance)
00273 {
00274     aAdvance = FT_CEIL(FT_MulFix(mMaxAdvance, mFace->size->metrics.x_scale));
00275     aAdvance = NSToCoordRound(aAdvance * mDev2App);
00276     return NS_OK;
00277 }
00278 
00279 NS_IMETHODIMP
00280 nsCairoFontMetrics::GetLangGroup(nsIAtom** aLangGroup)
00281 {
00282     *aLangGroup = mLangGroup;
00283     NS_IF_ADDREF(*aLangGroup);
00284     return NS_OK;
00285 }
00286 
00287 NS_IMETHODIMP
00288 nsCairoFontMetrics::GetFontHandle(nsFontHandle &aHandle)
00289 {
00290     return NS_ERROR_NOT_IMPLEMENTED;
00291 }
00292 
00293 NS_IMETHODIMP
00294 nsCairoFontMetrics::GetAveCharWidth(nscoord& aAveCharWidth)
00295 {
00296     aAveCharWidth = NSToCoordRound(7 * mDev2App);
00297     return NS_OK;
00298 }
00299 
00300 NS_IMETHODIMP
00301 nsCairoFontMetrics::GetSpaceWidth(nscoord& aSpaceCharWidth)
00302 {
00303     FT_Load_Char(mFace, ' ', FT_LOAD_DEFAULT | FT_LOAD_NO_AUTOHINT);
00304 
00305     aSpaceCharWidth = NSToCoordRound((mFace->glyph->advance.x >> 6) * mDev2App);
00306 
00307     return NS_OK;
00308 }
00309 
00310 nscoord
00311 nsCairoFontMetrics::MeasureString(const char *aString, PRUint32 aLength)
00312 {
00313     nscoord width = 0;
00314     PRUint32 i;
00315     int error;
00316 
00317     FT_UInt glyph_index;
00318     FT_UInt previous = 0;
00319 
00320     for (i=0; i < aLength; ++i) {
00321         glyph_index = FT_Get_Char_Index(mFace, aString[i]);
00322 /*
00323         if (previous && glyph_index) {
00324             FT_Vector delta;
00325             FT_Get_Kerning(mFace, previous, glyph_index,
00326                            FT_KERNING_DEFAULT, &delta);
00327             width += delta.x >> 6;
00328         }
00329 */
00330         error = FT_Load_Glyph(mFace, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_NO_AUTOHINT);
00331         if (error)
00332             continue;
00333 
00334         width += mFace->glyph->advance.x;
00335         previous = glyph_index;
00336     }
00337 
00338     return NSToCoordRound((width >> 6) * mDev2App);
00339 }
00340 
00341 nscoord
00342 nsCairoFontMetrics::MeasureString(const PRUnichar *aString, PRUint32 aLength)
00343 {
00344     nscoord width = 0;
00345     PRUint32 i;
00346     int error;
00347 
00348     FT_UInt glyph_index;
00349     FT_UInt previous = 0;
00350 
00351     for (i=0; i < aLength; ++i) {
00352         glyph_index = FT_Get_Char_Index(mFace, aString[i]);
00353 /*
00354         if (previous && glyph_index) {
00355             FT_Vector delta;
00356             FT_Get_Kerning(mFace, previous, glyph_index,
00357                            FT_KERNING_DEFAULT, &delta);
00358             width += delta.x >> 6;
00359         }
00360 */
00361         error = FT_Load_Glyph(mFace, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_NO_AUTOHINT);
00362         if (error)
00363             continue;
00364 
00365         width += mFace->glyph->advance.x;
00366         previous = glyph_index;
00367     }
00368 
00369     return NSToCoordRound((width >> 6) * mDev2App);
00370 }
00371 
00372 NS_IMETHODIMP
00373 nsCairoFontMetrics::GetLeading(nscoord& aLeading)
00374 {
00375     aLeading = 0;
00376     return NS_OK;
00377 }
00378 
00379 NS_IMETHODIMP
00380 nsCairoFontMetrics::GetNormalLineHeight(nscoord& aLineHeight)
00381 {
00382     aLineHeight = 10;
00383     return NS_OK;
00384 }