Back to index

lightning-sunbird  0.9+nobinonly
nsFontFreeType.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ex: set tabstop=8 softtabstop=2 shiftwidth=2 expandtab: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Brian Stell <bstell@netscape.com>
00025  *   Louie Zhao  <louie.zhao@sun.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #ifdef DEBUG
00042 // set this to 1 to have the code draw the bounding boxes
00043 #define DEBUG_SHOW_GLYPH_BOX 0
00044 #endif
00045 
00046 #include "gfx-config.h"
00047 #include "nsFontFreeType.h"
00048 #include "nsUnicharUtils.h"
00049 
00050 #if (!defined(MOZ_ENABLE_FREETYPE2))
00051 
00052 nsFreeTypeFont *
00053 nsFreeTypeFont::NewFont(nsITrueTypeFontCatalogEntry *, PRUint16, const char *)
00054 {
00055   return nsnull;
00056 }
00057 
00058 #else
00059 
00060 #include "nsX11AlphaBlend.h"
00061 #include "nsAntiAliasedGlyph.h"
00062 #include "nsFontDebug.h"
00063 #include "nsIServiceManager.h"
00064 
00065 // macros to handle FreeType2 16.16 numbers
00066 #define FT_16_16_TO_REG(x) ((x)>>16)
00067 
00068 #define IMAGE_BUFFER_SIZE 2048
00069 
00070 PRUint32 deltaMicroSeconds(PRTime aStartTime, PRTime aEndTime);
00071 void GetFallbackGlyphMetrics(FT_BBox *aBoundingBox, FT_Face aFace);
00072 
00073 PRUint8 nsFreeTypeFont::sLinearWeightTable[256];
00074 
00075 //
00076 // class nsFreeTypeXImage definition
00077 //
00078 class nsFreeTypeXImage : public nsFreeTypeFont {
00079 public:
00080   nsFreeTypeXImage(nsITrueTypeFontCatalogEntry *aFaceID, PRUint16 aPixelSize,
00081                    const char *aName);
00082   gint DrawString(nsRenderingContextGTK* aContext,
00083                             nsDrawingSurfaceGTK* aSurface, nscoord aX,
00084                             nscoord aY, const PRUnichar* aString,
00085                             PRUint32 aLength);
00086 protected:
00087   nsFreeTypeXImage();
00088 };
00089 
00090 //
00091 // class nsFreeTypeXImageSBC (Single Byte Converter) definition
00092 //
00093 class nsFreeTypeXImageSBC : public nsFreeTypeXImage {
00094 public:
00095   nsFreeTypeXImageSBC(nsITrueTypeFontCatalogEntry *aFaceID,
00096                       PRUint16 aPixelSize, const char *aName);
00097 #ifdef MOZ_MATHML
00098   virtual nsresult GetBoundingMetrics(const PRUnichar*   aString,
00099                                       PRUint32           aLength,
00100                                       nsBoundingMetrics& aBoundingMetrics);
00101 #endif
00102 
00103   virtual gint GetWidth(const PRUnichar* aString, PRUint32 aLength);
00104   virtual gint DrawString(nsRenderingContextGTK* aContext,
00105                           nsDrawingSurfaceGTK* aSurface, nscoord aX,
00106                           nscoord aY, const PRUnichar* aString,
00107                           PRUint32 aLength);
00108 protected:
00109   nsFreeTypeXImageSBC();
00110 };
00111 
00112 #ifdef ENABLE_TIME_MACROS
00113 PRUint32
00114 deltaMicroSeconds(PRTime aStartTime, PRTime aEndTime)
00115 {
00116   PRUint32 delta;
00117   PRUint64 loadTime64;
00118 
00119   LL_SUB(loadTime64, aEndTime, aStartTime);
00120   LL_L2UI(delta, loadTime64);
00121 
00122   return delta;
00123 }
00124 #endif
00125 
00126 //
00127 // class nsFreeTypeFont data/functions
00128 //
00129 nsFreeTypeFont::nsFreeTypeFont()
00130 {
00131   NS_ERROR("should never call nsFreeTypeFont::nsFreeTypeFont");
00132 }
00133 
00134 nsFreeTypeFont *
00135 nsFreeTypeFont::NewFont(nsITrueTypeFontCatalogEntry *aFaceID,
00136                         PRUint16 aPixelSize, const char *aName)
00137 {
00138   // Make sure FreeType is available
00139   nsresult rv;
00140   nsCOMPtr<nsIFreeType2> ft2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv);
00141   if (NS_FAILED(rv)) {
00142     NS_ERROR("FreeType2 routines not available");
00143     return nsnull;
00144   }
00145 
00146   // for now we only support ximage (XGetImage/alpha-blend/XPutImage) display
00147   // when we support XRender then we will need to test if it is
00148   // available and if so use it since it is faster than ximage.
00149   PRBool ximage = PR_TRUE;
00150   PRBool render = PR_FALSE;
00151   nsFreeTypeFont *ftfont;
00152   nsCAutoString familyName;
00153   aFaceID->GetFamilyName(familyName);
00154   nsTTFontFamilyEncoderInfo *ffei =
00155     nsFreeType2::GetCustomEncoderInfo(familyName.get());
00156   if (ximage) {
00157     if (ffei) {
00158       ftfont = new nsFreeTypeXImageSBC(aFaceID, aPixelSize, aName);
00159     }
00160     else {
00161       ftfont = new nsFreeTypeXImage(aFaceID, aPixelSize, aName);
00162     }
00163     return ftfont;
00164   }
00165   else if (render) {
00166     NS_ERROR("need to construct a render type FreeType object");
00167     return nsnull;
00168   }
00169   NS_ERROR("need to construct other type FreeType objects");
00170   return nsnull;
00171 }
00172 
00173 FT_Face
00174 nsFreeTypeFont::getFTFace()
00175 {
00176   FT_Face face = nsnull;
00177   FTC_Manager mgr;
00178   nsresult rv;
00179   mFt2->GetFTCacheManager(&mgr);
00180   rv = mFt2->ManagerLookupSize(mgr, &mImageDesc.font, &face, nsnull);
00181   NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get face/size");
00182   if (NS_FAILED(rv))
00183     return nsnull;
00184   return face;
00185 }
00186 
00187 nsFreeTypeFont::nsFreeTypeFont(nsITrueTypeFontCatalogEntry *aFaceID,
00188                                PRUint16 aPixelSize, const char *aName)
00189 {
00190   PRBool anti_alias = PR_TRUE;
00191   PRBool embedded_bimap = PR_FALSE;
00192   mFaceID = aFaceID;
00193   mPixelSize = aPixelSize;
00194   mImageDesc.font.face_id    = (void*)mFaceID;
00195   mImageDesc.font.pix_width  = aPixelSize;
00196   mImageDesc.font.pix_height = aPixelSize;
00197   mImageDesc.image_type = 0;
00198 
00199   if (aPixelSize < nsFreeType2::gAntiAliasMinimum) {
00200     mImageDesc.image_type |= ftc_image_mono;
00201     anti_alias = PR_FALSE;
00202   }
00203 
00204   if (nsFreeType2::gFreeType2Autohinted)
00205     mImageDesc.image_type |= ftc_image_flag_autohinted;
00206 
00207   if (nsFreeType2::gFreeType2Unhinted)
00208     mImageDesc.image_type |= ftc_image_flag_unhinted;
00209 
00210   PRUint32  num_embedded_bitmaps, i;
00211   PRInt32*  embedded_bitmapheights;
00212   mFaceID->GetEmbeddedBitmapHeights(&num_embedded_bitmaps,
00213                                     &embedded_bitmapheights);
00214   // check if we have an embedded bitmap
00215   if (aPixelSize <= nsFreeType2::gEmbeddedBitmapMaximumHeight) {
00216     if (num_embedded_bitmaps) {
00217       for (i=0; i<num_embedded_bitmaps; i++) {
00218         if (embedded_bitmapheights[i] == aPixelSize) {
00219           embedded_bimap = PR_TRUE;
00220           // unhinted must be set for embedded bitmaps to be used
00221           mImageDesc.image_type |= ftc_image_flag_unhinted;
00222           break;
00223         }
00224       }
00225     }
00226   }
00227 
00228   nsresult rv;
00229   // we checked for this earlier so it should not fail now
00230   mFt2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv);
00231   NS_ASSERTION(NS_SUCCEEDED(rv), "failed to find FreeType routines");
00232 
00233   FREETYPE_FONT_PRINTF(("anti_alias=%d, embedded_bitmap=%d, "
00234                         "AutoHinted=%d, gFreeType2Unhinted = %d, "
00235                         "size=%dpx, \"%s\"",
00236                         anti_alias, embedded_bimap,
00237                         nsFreeType2::gFreeType2Autohinted,
00238                         nsFreeType2::gFreeType2Unhinted,
00239                         aPixelSize, aName));
00240 }
00241 
00242 void
00243 nsFreeTypeFont::LoadFont()
00244 {
00245   if (mAlreadyCalledLoadFont) {
00246     return;
00247   }
00248 
00249   mAlreadyCalledLoadFont = PR_TRUE;
00250   PRUint32 size;
00251   mFaceID->GetCCMap(&size, &mCCMap);
00252 #ifdef NS_FONT_DEBUG_LOAD_FONT
00253   nsCAutoString fileName;
00254   mFaceID->GetFileName(fileName);
00255   if (gFontDebug & NS_FONT_DEBUG_LOAD_FONT) {
00256     printf("loaded \"%s\", size=%d, filename=%s\n",
00257                  mName, mSize, fileName.get());
00258   }
00259 #endif
00260 }
00261 
00262 nsFreeTypeFont::~nsFreeTypeFont()
00263 {
00264 }
00265 
00266 #ifdef MOZ_MATHML
00267 nsresult
00268 nsFreeTypeFont::GetBoundingMetrics(const PRUnichar*   aString,
00269                                    PRUint32           aLength,
00270                                    nsBoundingMetrics& aBoundingMetrics)
00271 {
00272   return doGetBoundingMetrics(aString, aLength,
00273                               &aBoundingMetrics.leftBearing,
00274                               &aBoundingMetrics.rightBearing,
00275                               &aBoundingMetrics.ascent,
00276                               &aBoundingMetrics.descent,
00277                               &aBoundingMetrics.width);
00278 }
00279 #endif
00280 
00281 
00282 
00283 nsresult
00284 nsFreeTypeFont::doGetBoundingMetrics(const PRUnichar* aString, PRUint32 aLength,
00285                                      PRInt32* aLeftBearing,
00286                                      PRInt32* aRightBearing,
00287                                      PRInt32* aAscent,
00288                                      PRInt32* aDescent,
00289                                      PRInt32* aWidth)
00290 {
00291   nsresult rv;
00292 
00293   *aLeftBearing = 0;
00294   *aRightBearing = 0;
00295   *aAscent = 0;
00296   *aDescent = 0;
00297   *aWidth = 0;
00298 
00299   if (aLength < 1) {
00300     return NS_ERROR_FAILURE;
00301   }
00302 
00303   FT_Pos pos = 0;
00304   FT_BBox bbox;
00305   // initialize to "uninitialized" values
00306   bbox.xMin = bbox.yMin = 32000;
00307   bbox.xMax = bbox.yMax = -32000;
00308 
00309   // get the face/size from the FreeType cache
00310   FT_Face face = getFTFace();
00311   NS_ASSERTION(face, "failed to get face/size");
00312   if (!face)
00313     return NS_ERROR_FAILURE;
00314 
00315   FTC_Image_Cache icache;
00316   mFt2->GetImageCache(&icache);
00317   if (!icache)
00318     return NS_ERROR_FAILURE;
00319 
00320   // get the text size
00321   PRUint32 i, extraSurrogateLength;
00322   for (i=0; i<aLength; i+=1+extraSurrogateLength) {
00323     FT_UInt glyph_index;
00324     FT_Glyph glyph;
00325     FT_BBox glyph_bbox;
00326     FT_Pos advance;
00327     extraSurrogateLength=0;
00328 
00329     FT_ULong code_point = aString[i];
00330     if(i<aLength-1 && IS_HIGH_SURROGATE(code_point) && IS_LOW_SURROGATE(aString[i+1])) {
00331       // if surrogate, make UCS4 code point from high aString[i] surrogate and
00332       // low surrogate aString[i+1]
00333       code_point = SURROGATE_TO_UCS4(code_point, aString[i+1]);
00334 
00335       // skip aString[i+1], it is already used as low surrogate
00336       extraSurrogateLength = 1;
00337     }
00338     mFt2->GetCharIndex(face, code_point, &glyph_index);
00339 
00340     //NS_ASSERTION(glyph_index,"failed to get glyph");
00341     if (glyph_index) {
00342       rv = mFt2->ImageCacheLookup(icache, &mImageDesc, glyph_index, &glyph);
00343       NS_ASSERTION(NS_SUCCEEDED(rv),"error loading glyph");
00344     }
00345     if ((glyph_index) && (NS_SUCCEEDED(rv))) {
00346       mFt2->GlyphGetCBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox);
00347       advance = FT_16_16_TO_REG(glyph->advance.x);
00348     }
00349     else {
00350       // allocate space to draw an empty box in
00351       GetFallbackGlyphMetrics(&glyph_bbox, face);
00352       advance = glyph_bbox.xMax + 1;
00353     }
00354     bbox.xMin = PR_MIN(pos+glyph_bbox.xMin, bbox.xMin);
00355     bbox.xMax = PR_MAX(pos+glyph_bbox.xMax, bbox.xMax);
00356     bbox.yMin = PR_MIN(glyph_bbox.yMin, bbox.yMin);
00357     bbox.yMax = PR_MAX(glyph_bbox.yMax, bbox.yMax);
00358     pos += advance;
00359   }
00360 
00361   // check we got at least one size
00362   if (bbox.xMin > bbox.xMax)
00363     bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0;
00364 
00365   *aLeftBearing  = bbox.xMin;
00366   *aRightBearing = bbox.xMax;
00367   *aAscent       = bbox.yMax;
00368   *aDescent      = -bbox.yMin;
00369   *aWidth        = pos;
00370   return NS_OK;
00371 }
00372 
00373 GdkFont*
00374 nsFreeTypeFont::GetGDKFont()
00375 {
00376   return nsnull;
00377 }
00378 
00379 PRBool
00380 nsFreeTypeFont::GetGDKFontIs10646()
00381 {
00382   return PR_TRUE;
00383 }
00384 
00385 PRBool
00386 nsFreeTypeFont::IsFreeTypeFont()
00387 {
00388   return PR_TRUE;
00389 }
00390 
00391 gint
00392 nsFreeTypeFont::GetWidth(const PRUnichar* aString, PRUint32 aLength)
00393 {
00394   FT_UInt glyph_index;
00395   FT_Glyph glyph;
00396   FT_Pos origin_x = 0;
00397 
00398   // get the face/size from the FreeType cache
00399   FT_Face face = getFTFace();
00400   NS_ASSERTION(face, "failed to get face/size");
00401   if (!face)
00402     return 0;
00403 
00404   FTC_Image_Cache icache;
00405   mFt2->GetImageCache(&icache);
00406   if (!icache)
00407     return 0;
00408 
00409   PRUint32 i, extraSurrogateLength;
00410   for (i=0; i<aLength; i+=1+extraSurrogateLength) {
00411     extraSurrogateLength=0;
00412     FT_ULong code_point = aString[i];
00413     if(i<aLength-1 && IS_HIGH_SURROGATE(code_point) && IS_LOW_SURROGATE(aString[i+1])) {
00414       // if surrogate, make UCS4 code point from high aString[i] surrogate and
00415       // low surrogate aString[i+1]
00416       code_point = SURROGATE_TO_UCS4(code_point, aString[i+1]);
00417 
00418       // skip aString[i+1], it is already used as low surrogate
00419       extraSurrogateLength = 1;
00420     }
00421     mFt2->GetCharIndex((FT_Face)face, code_point, &glyph_index);
00422     nsresult rv;
00423     rv = mFt2->ImageCacheLookup(icache, &mImageDesc, glyph_index, &glyph);
00424     NS_ASSERTION(NS_SUCCEEDED(rv),"error loading glyph");
00425     if (NS_FAILED(rv)) {
00426       origin_x += face->size->metrics.x_ppem/2 + 2;
00427       continue;
00428     }
00429     origin_x += FT_16_16_TO_REG(glyph->advance.x);
00430   }
00431 
00432   return origin_x;
00433 }
00434 
00435 gint
00436 nsFreeTypeFont::DrawString(nsRenderingContextGTK* aContext,
00437                             nsDrawingSurfaceGTK* aSurface, nscoord aX,
00438                             nscoord aY, const PRUnichar* aString,
00439                             PRUint32 aLength)
00440 {
00441   NS_ERROR("should never call nsFreeTypeFont::DrawString");
00442   return 0;
00443 }
00444 
00445 PRUint32
00446 nsFreeTypeFont::Convert(const PRUnichar* aSrc, PRUint32 aSrcLen,
00447                            PRUnichar* aDest, PRUint32 aDestLen)
00448 {
00449   NS_ERROR("should not be calling nsFreeTypeFont::Convert");
00450   return 0;
00451 }
00452 
00453 int
00454 nsFreeTypeFont::ascent()
00455 {
00456   FT_Face face = getFTFace();
00457   NS_ASSERTION(face, "failed to get face/size");
00458   if (!face)
00459     return 0;
00460   return FT_DESIGN_UNITS_TO_PIXELS(face->ascender, face->size->metrics.y_scale);
00461 }
00462 
00463 int
00464 nsFreeTypeFont::descent()
00465 {
00466   FT_Face face = getFTFace();
00467   NS_ASSERTION(face, "failed to get face/size");
00468   if (!face)
00469     return 0;
00470   return FT_DESIGN_UNITS_TO_PIXELS(-face->descender, face->size->metrics.y_scale);
00471 }
00472 
00473 int
00474 nsFreeTypeFont::max_ascent()
00475 {
00476   FT_Face face = getFTFace();
00477   NS_ASSERTION(face, "failed to get face/size");
00478   if (!face)
00479     return 0;
00480 
00481   TT_OS2 * tt_os2;
00482   mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2);
00483   NS_ASSERTION(tt_os2, "unable to get OS2 table");
00484   if (tt_os2)
00485      return FT_DESIGN_UNITS_TO_PIXELS(tt_os2->sTypoAscender,
00486                                       face->size->metrics.y_scale);
00487   else
00488      return FT_DESIGN_UNITS_TO_PIXELS(face->bbox.yMax,
00489                                       face->size->metrics.y_scale);
00490 }
00491 
00492 int
00493 nsFreeTypeFont::max_descent()
00494 {
00495   FT_Face face = getFTFace();
00496   NS_ASSERTION(face, "failed to get face/size");
00497   if (!face)
00498     return 0;
00499 
00500   TT_OS2 *tt_os2;
00501   mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2);
00502   NS_ASSERTION(tt_os2, "unable to get OS2 table");
00503   if (tt_os2)
00504      return FT_DESIGN_UNITS_TO_PIXELS(-tt_os2->sTypoDescender,
00505                                       face->size->metrics.y_scale);
00506   else
00507      return FT_DESIGN_UNITS_TO_PIXELS(-face->bbox.yMin,
00508                                       face->size->metrics.y_scale);
00509 }
00510 
00511 int
00512 nsFreeTypeFont::max_width()
00513 {
00514   FT_Face face = getFTFace();
00515   NS_ASSERTION(face, "failed to get face/size");
00516   if (!face)
00517     return 0;
00518   return FT_DESIGN_UNITS_TO_PIXELS(face->max_advance_width,
00519                                    face->size->metrics.x_scale);
00520 }
00521 
00522 PRBool
00523 nsFreeTypeFont::getXHeight(unsigned long &val)
00524 {
00525   FT_Face face = getFTFace();
00526   NS_ASSERTION(face, "failed to get face/size");
00527   if (!face || !val)
00528     return PR_FALSE;
00529   val = FT_DESIGN_UNITS_TO_PIXELS(face->height, face->size->metrics.y_scale);
00530 
00531   return PR_TRUE;
00532 }
00533 
00534 PRBool
00535 nsFreeTypeFont::underlinePosition(long &val)
00536 {
00537   FT_Face face = getFTFace();
00538   NS_ASSERTION(face, "failed to get face/size");
00539   if (!face)
00540     return PR_FALSE;
00541   val = FT_DESIGN_UNITS_TO_PIXELS(-face->underline_position,
00542                                    face->size->metrics.y_scale);
00543   return PR_TRUE;
00544 }
00545 
00546 PRBool
00547 nsFreeTypeFont::underline_thickness(unsigned long &val)
00548 {
00549   FT_Face face = getFTFace();
00550   NS_ASSERTION(face, "failed to get face/size");
00551   if (!face)
00552     return PR_FALSE;
00553   val = FT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness,
00554                                   face->size->metrics.y_scale);
00555   return PR_TRUE;
00556 }
00557 
00558 PRBool
00559 nsFreeTypeFont::superscript_y(long &val)
00560 {
00561   FT_Face face = getFTFace();
00562   NS_ASSERTION(face, "failed to get face/size");
00563   if (!face)
00564     return PR_FALSE;
00565 
00566   TT_OS2 *tt_os2;
00567   mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2);
00568   NS_ASSERTION(tt_os2, "unable to get OS2 table");
00569   if (!tt_os2)
00570     return PR_FALSE;
00571 
00572   val = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySuperscriptYOffset,
00573                                   face->size->metrics.y_scale);
00574   return PR_TRUE;
00575 }
00576 
00577 PRBool
00578 nsFreeTypeFont::subscript_y(long &val)
00579 {
00580   FT_Face face = getFTFace();
00581   NS_ASSERTION(face, "failed to get face/size");
00582   if (!face)
00583     return PR_FALSE;
00584 
00585   TT_OS2 *tt_os2;
00586   mFt2->GetSfntTable(face, ft_sfnt_os2, (void**)&tt_os2);
00587   NS_ASSERTION(tt_os2, "unable to get OS2 table");
00588   if (!tt_os2)
00589     return PR_FALSE;
00590 
00591   val = FT_DESIGN_UNITS_TO_PIXELS(tt_os2->ySubscriptYOffset,
00592                                   face->size->metrics.y_scale);
00593 
00594   // some fonts have the sign wrong. it should be always positive.
00595   val = (val < 0) ? -val : val;
00596   return PR_TRUE;
00597 }
00598 
00599 //
00600 // class nsFreeTypeRender
00601 //
00602 
00603 // this needs to be written
00604 class nsFreeTypeRender : nsFreeTypeFont {
00605 private:
00606   nsFreeTypeRender();
00607 };
00608 
00609 //
00610 // class nsFreeTypeXImage data/functions
00611 //
00612 nsFreeTypeXImage::nsFreeTypeXImage()
00613 {
00614   NS_ERROR("should never call nsFreeTypeXImage::nsFreeTypeXImage");
00615 }
00616 
00617 nsFreeTypeXImage::nsFreeTypeXImage(nsITrueTypeFontCatalogEntry *aFaceID,
00618                                    PRUint16 aPixelSize, const char *aName)
00619 : nsFreeTypeFont(aFaceID, aPixelSize, aName)
00620 {
00621   //NS_ERROR("should never call nsFreeTypeXImage::nsFreeTypeXImage");
00622 }
00623 
00624 gint
00625 nsFreeTypeXImage::DrawString(nsRenderingContextGTK* aContext,
00626                             nsDrawingSurfaceGTK* aSurface, nscoord aX,
00627                             nscoord aY, const PRUnichar* aString,
00628                             PRUint32 aLength)
00629 {
00630 
00631 #if DEBUG_SHOW_GLYPH_BOX
00632   PRUint32 x, y;
00633   // grey shows image size
00634   // red shows character cells
00635   // green box shows text ink
00636 #endif
00637 
00638   if (aLength < 1) {
00639     return 0;
00640   }
00641 
00642   // get the face/size from the FreeType cache
00643   FT_Face face = getFTFace();
00644   NS_ASSERTION(face, "failed to get face/size");
00645   if (!face)
00646     return 0;
00647 
00648   nsresult rslt;
00649   PRInt32 leftBearing, rightBearing, ascent, descent, width;
00650   rslt = doGetBoundingMetrics(aString, aLength, &leftBearing, &rightBearing,
00651                               &ascent, &descent, &width);
00652   if (NS_FAILED(rslt))
00653     return 0;
00654 
00655   // make sure we bring down enough background for blending
00656   rightBearing = PR_MAX(rightBearing, width+1);
00657 
00658   // offset in the ximage to the x origin
00659   PRInt32 x_origin = PR_MAX(0, -leftBearing);
00660   // offset in the ximage to the x origin
00661   PRInt32 y_origin = ascent;
00662   PRInt32 x_pos = x_origin;
00663 
00664   int image_width  = x_origin + rightBearing;
00665   int image_height = y_origin + PR_MAX(descent, 0);
00666   if ((image_width<=0) || (image_height<=0)) {
00667     // if we do not have any pixels then no point in trying to draw
00668     // eg: the space char has 0 height
00669     NS_ASSERTION(width>=0, "Negative width");
00670     return width;
00671   }
00672   Display *dpy = GDK_DISPLAY();
00673   Drawable win = GDK_WINDOW_XWINDOW(aSurface->GetDrawable());
00674   GC gc = GDK_GC_XGC(aContext->GetGC());
00675   XGCValues values;
00676   if (!XGetGCValues(dpy, gc, GCForeground, &values)) {
00677     NS_ERROR("failed to get foreground pixel");
00678     return 0;
00679   }
00680   nscolor color = nsX11AlphaBlend::PixelToNSColor(values.foreground);
00681 
00682 #if DEBUG_SHOW_GLYPH_BOX
00683   // show X/Y origin
00684   XDrawLine(dpy, win, DefaultGC(dpy, 0), aX-2, aY, aX+2, aY);
00685   XDrawLine(dpy, win, DefaultGC(dpy, 0), aX, aY-2, aX, aY+2);
00686   // show width
00687   XDrawLine(dpy, win, DefaultGC(dpy, 0), aX-x_origin,  aY-y_origin-2,
00688                                          aX+rightBearing, aY-y_origin-2);
00689 #endif
00690 
00691   //
00692   // Get the background
00693   //
00694   XImage *sub_image = nsX11AlphaBlend::GetBackground(dpy, DefaultScreen(dpy),
00695                                  win, aX-x_origin, aY-y_origin,
00696                                  image_width, image_height);
00697   if (sub_image==nsnull) {
00698 #ifdef DEBUG
00699     int screen = DefaultScreen(dpy);
00700     // complain if the requested area is not completely off screen
00701     int win_width = DisplayWidth(dpy, screen);
00702     int win_height = DisplayHeight(dpy, screen);
00703     if (((int)(aX-leftBearing+image_width) > 0)  // not hidden to left
00704         && ((int)(aX-leftBearing) < win_width)   // not hidden to right
00705         && ((int)(aY-ascent+image_height) > 0)// not hidden to top
00706         && ((int)(aY-ascent) < win_height))   // not hidden to bottom
00707     {
00708       NS_ASSERTION(sub_image, "failed to get the image");
00709     }
00710 #endif
00711     return 0;
00712   }
00713 
00714 #if DEBUG_SHOW_GLYPH_BOX
00715   DEBUG_AADRAWBOX(sub_image,0,0,image_width,image_height,0,0,0,255/4);
00716   nscolor black NS_RGB(0,255,0);
00717   blendPixel blendPixelFunc = nsX11AlphaBlend::GetBlendPixel();
00718   // x origin
00719   for (x=0; x<(unsigned int)image_height; x++)
00720     if (x%4==0) (*blendPixelFunc)(sub_image, x_origin, x, black, 255/2);
00721   // y origin
00722   for (y=0; y<(unsigned int)image_width; y++)
00723     if (y%4==0) (*blendPixelFunc)(sub_image, y, ascent-1, black, 255/2);
00724 #endif
00725 
00726   FTC_Image_Cache icache;
00727   mFt2->GetImageCache(&icache);
00728   if (!icache)
00729     return 0;
00730 
00731   //
00732   // Get aa glyphs and blend with background
00733   //
00734   blendGlyph blendGlyph = nsX11AlphaBlend::GetBlendGlyph();
00735   PRUint32 i, extraSurrogateLength;
00736   for (i=0; i<aLength; i+=1+extraSurrogateLength) {
00737     FT_UInt glyph_index;
00738     FT_Glyph glyph;
00739     nsresult rv;
00740     FT_BBox glyph_bbox;
00741     FT_ULong code_point = aString[i];
00742     extraSurrogateLength = 0;
00743 
00744     if(i<aLength-1 && IS_HIGH_SURROGATE(code_point) && IS_LOW_SURROGATE(aString[i+1])) {
00745       // if surrogate, make UCS4 code point from high aString[i] surrogate and
00746       // low surrogate aString[i+1]
00747       code_point = SURROGATE_TO_UCS4(code_point, aString[i+1]);
00748 
00749       // skip aString[i+1], it is already used as low surrogate
00750       extraSurrogateLength = 1;
00751     }
00752 
00753     mFt2->GetCharIndex(face, code_point, &glyph_index);
00754     if (glyph_index) {
00755       rv = mFt2->ImageCacheLookup(icache, &mImageDesc, glyph_index, &glyph);
00756     }
00757     if ((glyph_index) && (NS_SUCCEEDED(rv))) {
00758       mFt2->GlyphGetCBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox);
00759     }
00760     else {
00761       // draw an empty box for the missing glyphs
00762       GetFallbackGlyphMetrics(&glyph_bbox, face);
00763       int x, y, w = glyph_bbox.xMax, h = glyph_bbox.yMax;
00764       for (x=1; x<w; x++) {
00765         XPutPixel(sub_image, x_pos+x, ascent-1,   values.foreground);
00766         XPutPixel(sub_image, x_pos+x, ascent-h, values.foreground);
00767       }
00768       for (y=1; y<h; y++) {
00769         XPutPixel(sub_image, x_pos+1, ascent-y, values.foreground);
00770         XPutPixel(sub_image, x_pos+w-1, ascent-y, values.foreground);
00771         x = (y*(w-2))/h;
00772         XPutPixel(sub_image, x_pos+x+1, ascent-y,   values.foreground);
00773       }
00774       x_pos += w + 1;
00775       continue;
00776     }
00777 
00778     FT_BitmapGlyph slot = (FT_BitmapGlyph)glyph;
00779     nsAntiAliasedGlyph aaglyph(glyph_bbox.xMax-glyph_bbox.xMin,
00780                                glyph_bbox.yMax-glyph_bbox.yMin, 0);
00781     PRUint8 buf[IMAGE_BUFFER_SIZE]; // try to use the stack for data
00782     if (!aaglyph.WrapFreeType(&glyph_bbox, slot, buf, IMAGE_BUFFER_SIZE)) {
00783       NS_ERROR("failed to wrap freetype image");
00784       XDestroyImage(sub_image);
00785       return 0;
00786     }
00787 
00788     //
00789     // blend the aa-glyph onto the background
00790     //
00791     NS_ASSERTION(ascent>=glyph_bbox.yMax,"glyph too tall");
00792     NS_ASSERTION(x_pos>=-aaglyph.GetLBearing(),"glyph extends too far to left");
00793 
00794 #if DEBUG_SHOW_GLYPH_BOX
00795   // draw box around part of glyph that extends to the left
00796   // of the main area (negative LBearing)
00797   if (aaglyph.GetLBearing() < 0) {
00798     DEBUG_AADRAWBOX(sub_image, x_pos + aaglyph.GetLBearing(),
00799                     ascent-glyph_bbox.yMax,
00800                     -aaglyph.GetLBearing(), glyph_bbox.yMax, 255,0,0, 255/4);
00801   }
00802   // draw box around main glyph area
00803   DEBUG_AADRAWBOX(sub_image, x_pos, ascent-glyph_bbox.yMax,
00804                   aaglyph.GetAdvance(), glyph_bbox.yMax, 0,255,0, 255/4);
00805   // draw box around part of glyph that extends to the right
00806   // of the main area (negative LBearing)
00807   if (aaglyph.GetRBearing() > (int)aaglyph.GetAdvance()) {
00808     DEBUG_AADRAWBOX(sub_image, x_pos + aaglyph.GetAdvance(),
00809                     ascent-glyph_bbox.yMax,
00810                     aaglyph.GetRBearing()-aaglyph.GetAdvance(),
00811                     glyph_bbox.yMax, 0,0,255, 255/4);
00812   }
00813 #endif
00814     (*blendGlyph)(sub_image, &aaglyph, sLinearWeightTable, color,
00815                   x_pos + aaglyph.GetLBearing(), ascent-glyph_bbox.yMax);
00816 
00817     x_pos += aaglyph.GetAdvance();
00818   }
00819 
00820   //
00821   // Send it to the display
00822   //
00823   XPutImage(dpy, win, gc, sub_image, 0, 0, aX-x_origin , aY-ascent,
00824             image_width, image_height);
00825   XDestroyImage(sub_image);
00826 
00827   return width;
00828 }
00829 
00831 //
00832 // class nsFreeTypeXImage data/functions
00833 //
00835 
00836 nsFreeTypeXImageSBC::nsFreeTypeXImageSBC()
00837 {
00838   NS_ERROR("should never call nsFreeTypeXImageSBC::nsFreeTypeXImageSBC");
00839 }
00840 
00841 nsFreeTypeXImageSBC::nsFreeTypeXImageSBC(nsITrueTypeFontCatalogEntry *aFaceID,
00842                                          PRUint16 aPixelSize,
00843                                          const char *aName)
00844 : nsFreeTypeXImage(aFaceID, aPixelSize, aName)
00845 {
00846 }
00847 
00848 #ifdef MOZ_MATHML
00849 nsresult
00850 nsFreeTypeXImageSBC::GetBoundingMetrics(const PRUnichar*   aString,
00851                                         PRUint32           aLength,
00852                                         nsBoundingMetrics& aBoundingMetrics)
00853 {
00854   nsresult res;
00855   char buf[512];
00856   PRInt32 bufLen = sizeof(buf);
00857   PRInt32 stringLen = aLength;
00858   nsCAutoString familyName;
00859   mFaceID->GetFamilyName(familyName);
00860   nsTTFontFamilyEncoderInfo *ffei =
00861     nsFreeType2::GetCustomEncoderInfo(familyName.get());
00862   NS_ASSERTION(ffei,"failed to find font encoder info");
00863   if (!ffei)
00864     return NS_ERROR_FAILURE;
00865   res = ffei->mEncodingInfo->mConverter->Convert(aString, &stringLen,
00866                                                  buf, &bufLen);
00867   NS_ASSERTION((aLength&&bufLen)||(!aLength&&!bufLen), "converter failed");
00868 
00869   //
00870   // Widen to 16 bit
00871   //
00872   PRUnichar unibuf[512];
00873   int i;
00874   for (i=0; i<bufLen; i++) {
00875     unibuf[i] = (unsigned char)buf[i];
00876   }
00877 
00878   res = nsFreeTypeXImage::GetBoundingMetrics(unibuf, bufLen, aBoundingMetrics);
00879   return res;
00880 }
00881 #endif
00882 
00883 gint
00884 nsFreeTypeXImageSBC::GetWidth(const PRUnichar* aString, PRUint32 aLength)
00885 {
00886   char buf[512];
00887   PRInt32 bufLen = sizeof(buf);
00888   PRInt32 stringLen = aLength;
00889   nsCAutoString familyName;
00890   mFaceID->GetFamilyName(familyName);
00891   nsTTFontFamilyEncoderInfo *ffei =
00892     nsFreeType2::GetCustomEncoderInfo(familyName.get());
00893   NS_ASSERTION(ffei,"failed to find font encoder info");
00894   if (!ffei)
00895     return 0;
00896   ffei->mEncodingInfo->mConverter->Convert(aString, &stringLen,
00897                                                  buf, &bufLen);
00898   NS_ASSERTION((aLength&&bufLen)||(!aLength&&!bufLen), "converter failed");
00899 
00900   //
00901   // Widen to 16 bit
00902   //
00903   PRUnichar unibuf[512];
00904   int i;
00905   for (i=0; i<bufLen; i++) {
00906     unibuf[i] = (unsigned char)buf[i];
00907   }
00908 
00909   return nsFreeTypeXImage::GetWidth(unibuf, bufLen);
00910 }
00911 
00912 gint
00913 nsFreeTypeXImageSBC::DrawString(nsRenderingContextGTK* aContext,
00914                                 nsDrawingSurfaceGTK* aSurface, nscoord aX,
00915                                 nscoord aY, const PRUnichar* aString,
00916                                 PRUint32 aLength)
00917 {
00918   char buf[512];
00919   PRInt32 bufLen = sizeof(buf);
00920   PRInt32 stringLen = aLength;
00921   nsCAutoString familyName;
00922   mFaceID->GetFamilyName(familyName);
00923   nsTTFontFamilyEncoderInfo *ffei =
00924     nsFreeType2::GetCustomEncoderInfo(familyName.get());
00925   NS_ASSERTION(ffei,"failed to find font encoder info");
00926   if (!ffei)
00927     return 0;
00928   ffei->mEncodingInfo->mConverter->Convert(aString, &stringLen,
00929                                            buf, &bufLen);
00930   NS_ASSERTION((aLength&&bufLen)||(!aLength&&!bufLen), "converter failed");
00931 
00932   //
00933   // Widen to 16 bit
00934   //
00935   PRUnichar unibuf[512];
00936   int i;
00937   for (i=0; i<bufLen; i++) {
00938     unibuf[i] = (unsigned char)buf[i];
00939   }
00940 
00941   return nsFreeTypeXImage::DrawString(aContext, aSurface, aX, aY,
00942                                       unibuf, bufLen);
00943 }
00944 
00945 void
00946 GetFallbackGlyphMetrics(FT_BBox *aBoundingBox, FT_Face aFace) {
00947   aBoundingBox->xMin = 0;
00948   aBoundingBox->yMin = 0;
00949   aBoundingBox->xMax = PR_MAX(aFace->size->metrics.x_ppem/2 - 1, 0);
00950   aBoundingBox->yMax = PR_MAX(aFace->size->metrics.y_ppem/2, 1);
00951 }
00952 
00953 void
00954 WeightTableInitCorrection(PRUint8* aTable, PRUint8 aMinValue,
00955                                 double aGain)
00956 {
00957   // setup the wieghting table
00958   for (int i=0; i<256; i++) {
00959     int val = i + (int)rint((double)(i-aMinValue)*aGain);
00960     val = PR_MAX(0, val);
00961     val = PR_MIN(val, 255);
00962     aTable[i] = (PRUint8)val;
00963   }
00964 }
00965 
00966 #endif
00967