/layout/svg/renderer/src/libart/nsSVGLibartGlyphMetricsFT.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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
00006  * Version 1.1 (the "License"); you may not use this file except in
00007  * compliance with 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 the Mozilla SVG project.
00016  *
00017  * The Initial Developer of the Original Code is 
00018  * .
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *    Leon Sha <leon.sha@sun.com>
00024  *    Alex Fritze <alex@croczilla.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 NPL, 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 "nsCOMPtr.h"
00041 #include "nsISVGGlyphMetricsSource.h"
00042 #include "nsISVGRendererGlyphMetrics.h"
00043 #include "nsPromiseFlatString.h"
00044 #include "nsFont.h"
00045 #include "nsIFontMetrics.h"
00046 #include "nsIPresContext.h"
00047 #include "float.h"
00048 #include "nsIDOMSVGMatrix.h"
00049 #include "nsIDOMSVGRect.h"
00050 #include "nsSVGTypeCIDs.h"
00051 #include "nsIComponentManager.h"
00052 #include "nsISVGLibartGlyphMetricsFT.h"
00053 #include "nsIDeviceContext.h"
00054 #include "nsFreeType.h"
00055 #include "nsIServiceManager.h"
00056 #include "libart-incs.h"
00057 #include "nsArray.h"
00058 #include "nsDataHashtable.h"
00059 #include "nsIPromptService.h"
00060 
00065 
00066 
00069 class nsSVGLibartGlyphMetricsFT : public nsISVGLibartGlyphMetricsFT
00070 {
00071 protected:
00072   friend nsresult NS_NewSVGLibartGlyphMetrics(nsISVGRendererGlyphMetrics **result,
00073                                               nsISVGGlyphMetricsSource *src);
00074   friend void NS_InitSVGLibartGlyphMetricsGlobals();
00075   friend void NS_FreeSVGLibartGlyphMetricsGlobals();
00076 
00077   nsSVGLibartGlyphMetricsFT(nsISVGGlyphMetricsSource *src);
00078   ~nsSVGLibartGlyphMetricsFT();
00079 
00080   // nsISupports interface:
00081   NS_DECL_ISUPPORTS
00082 
00083   // nsISVGRendererGlyphMetrics interface:
00084   NS_DECL_NSISVGRENDERERGLYPHMETRICS
00085 
00086   // nsISVGLibartGlyphMetrics interface:
00087   NS_IMETHOD_(FT_Face) GetFTFace();
00088   NS_IMETHOD_(float) GetPixelScale();
00089   NS_IMETHOD_(float) GetTwipsToPixels();
00090   NS_IMETHOD GetBoundingMetrics(PRInt32* aLeftBearing,
00091                                 PRInt32* aRightBearing,
00092                                 PRInt32* aAscent,
00093                                 PRInt32* aDescent,
00094                                 PRInt32* aWidth);
00095 
00096   // helpers :
00097   void ClearFontInfo() { mImageDesc.font.face_id=nsnull; }
00098   void InitializeFontInfo();
00099   
00100 private:
00101   PRUint16 mPixelSize;
00102   FTC_Image_Desc mImageDesc;
00103   nsCOMPtr<nsISVGGlyphMetricsSource> mSource;
00104   
00105   static nsCOMPtr<nsIFreeType2> sFt2;
00106   static PRBool sFontErrorShown;
00107 public:
00108   static nsDataHashtable<nsStringHashKey,nsDependentString*> sFontAliases;  
00109 };
00110 
00113 //----------------------------------------------------------------------
00114 // implementation:
00115 
00116 nsCOMPtr<nsIFreeType2> nsSVGLibartGlyphMetricsFT::sFt2;
00117 PRBool nsSVGLibartGlyphMetricsFT::sFontErrorShown = PR_FALSE;
00118 
00119 nsDataHashtable<nsStringHashKey,nsDependentString*>
00120 nsSVGLibartGlyphMetricsFT::sFontAliases;
00121 
00122 
00123 nsSVGLibartGlyphMetricsFT::nsSVGLibartGlyphMetricsFT(nsISVGGlyphMetricsSource *src):mSource(src)
00124 {
00125   mImageDesc.font.face_id=nsnull;
00126 }
00127 
00128 nsSVGLibartGlyphMetricsFT::~nsSVGLibartGlyphMetricsFT()
00129 {
00130   ClearFontInfo();
00131 }
00132 
00133 nsresult
00134 NS_NewSVGLibartGlyphMetrics(nsISVGRendererGlyphMetrics **result,
00135                              nsISVGGlyphMetricsSource *src)
00136 {
00137   *result = new nsSVGLibartGlyphMetricsFT(src);
00138   if (!*result) return NS_ERROR_OUT_OF_MEMORY;
00139   
00140   NS_ADDREF(*result);
00141   return NS_OK;
00142 }
00143 
00144 void NS_InitSVGLibartGlyphMetricsGlobals()
00145 {
00146   NS_ASSERTION(!nsSVGLibartGlyphMetricsFT::sFt2, "ft2 already initialized");
00147   nsSVGLibartGlyphMetricsFT::sFt2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv);
00148   
00149   NS_ASSERTION(!nsSVGLibartGlyphMetricsFT::sFontAliases.IsInitialized(),
00150                "font aliases already initialized");
00151   nsSVGLibartGlyphMetricsFT::sFontAliases.Init(3);
00152 
00153   static NS_NAMED_LITERAL_STRING(arial, "arial");
00154   nsSVGLibartGlyphMetricsFT::sFontAliases.Put(NS_LITERAL_STRING("helvetica"),
00155                                               &arial);
00156 
00157   static NS_NAMED_LITERAL_STRING(courier, "courier new");
00158   nsSVGLibartGlyphMetricsFT::sFontAliases.Put(NS_LITERAL_STRING("courier"),
00159                                               &courier);
00160 
00161   static NS_NAMED_LITERAL_STRING(times, "times new roman");
00162   nsSVGLibartGlyphMetricsFT::sFontAliases.Put(NS_LITERAL_STRING("times"),
00163                                               &times);
00164 }
00165 
00166 void NS_FreeSVGLibartGlyphMetricsGlobals()
00167 {
00168   NS_ASSERTION(nsSVGLibartGlyphMetricsFT::sFt2, "ft2 never initialized");
00169   nsSVGLibartGlyphMetricsFT::sFt2 = nsnull;
00170   
00171   NS_ASSERTION(nsSVGLibartGlyphMetricsFT::sFontAliases.IsInitialized(),
00172                "font aliases never initialized");
00173   nsSVGLibartGlyphMetricsFT::sFontAliases.Clear();
00174 }
00175 
00176 //----------------------------------------------------------------------
00177 // nsISupports methods:
00178 
00179 NS_IMPL_ADDREF(nsSVGLibartGlyphMetricsFT)
00180 NS_IMPL_RELEASE(nsSVGLibartGlyphMetricsFT)
00181 
00182 NS_INTERFACE_MAP_BEGIN(nsSVGLibartGlyphMetricsFT)
00183   NS_INTERFACE_MAP_ENTRY(nsISVGRendererGlyphMetrics)
00184   NS_INTERFACE_MAP_ENTRY(nsISVGLibartGlyphMetricsFT)
00185   NS_INTERFACE_MAP_ENTRY(nsISupports)
00186 NS_INTERFACE_MAP_END
00187 
00188 //----------------------------------------------------------------------
00189 // nsISVGRendererGlyphMetrics methods:
00190 
00192 NS_IMETHODIMP
00193 nsSVGLibartGlyphMetricsFT::GetBaselineOffset(PRUint16 baselineIdentifier, float *_retval)
00194 {
00195   *_retval = 0.0f;
00196   
00197   switch (baselineIdentifier) {
00198     case BASELINE_TEXT_BEFORE_EDGE:
00199       break;
00200     case BASELINE_TEXT_AFTER_EDGE:
00201       break;
00202     case BASELINE_CENTRAL:
00203     case BASELINE_MIDDLE:
00204       break;
00205     case BASELINE_ALPHABETIC:
00206     default:
00207     break;
00208   }
00209   
00210   return NS_OK;
00211 }
00212 
00213 
00215 NS_IMETHODIMP
00216 nsSVGLibartGlyphMetricsFT::GetAdvance(float *aAdvance)
00217 {
00218   *aAdvance = 0.0f;
00219   return NS_OK;
00220 }
00221 
00223 NS_IMETHODIMP
00224 nsSVGLibartGlyphMetricsFT::GetBoundingBox(nsIDOMSVGRect * *aBoundingBox)
00225 {
00226   *aBoundingBox = nsnull;
00227 
00228   nsCOMPtr<nsIDOMSVGRect> rect = do_CreateInstance(NS_SVGRECT_CONTRACTID);
00229 
00230   NS_ASSERTION(rect, "could not create rect");
00231   if (!rect) return NS_ERROR_FAILURE;
00232   
00233   rect->SetX(0);
00234   rect->SetY(0);
00235   rect->SetWidth(0);
00236   rect->SetHeight(0);
00237 
00238   *aBoundingBox = rect;
00239   NS_ADDREF(*aBoundingBox);
00240   
00241   return NS_OK;
00242 }
00243 
00245 NS_IMETHODIMP
00246 nsSVGLibartGlyphMetricsFT::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
00247 {
00248   *_retval = nsnull;
00249 
00250   nsCOMPtr<nsIDOMSVGRect> rect = do_CreateInstance(NS_SVGRECT_CONTRACTID);
00251 
00252   NS_ASSERTION(rect, "could not create rect");
00253   if (!rect) return NS_ERROR_FAILURE;
00254   
00255   rect->SetX(0);
00256   rect->SetY(0);
00257   rect->SetWidth(0);
00258   rect->SetHeight(0);
00259 
00260   *_retval = rect;
00261   NS_ADDREF(*_retval);
00262   
00263   return NS_OK;
00264 }
00265 
00267 NS_IMETHODIMP
00268 nsSVGLibartGlyphMetricsFT::Update(PRUint32 updatemask, PRBool *_retval)
00269 {
00270   *_retval = PR_FALSE;
00271   return NS_OK;
00272 }
00273 
00274 //----------------------------------------------------------------------
00275 // nsISVGLibartGlyphMetrics methods:
00276 
00277 NS_IMETHODIMP_(FT_Face)
00278 nsSVGLibartGlyphMetricsFT::GetFTFace()
00279 {
00280   InitializeFontInfo();
00281   nsresult rv;
00282   FT_Face face = nsnull;
00283   FTC_Manager mgr;
00284   sFt2->GetFTCacheManager(&mgr);
00285   rv = sFt2->ManagerLookupSize(mgr, &mImageDesc.font, &face, nsnull);
00286   NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get face/size");
00287   if (NS_FAILED(rv))
00288     return nsnull;
00289   return face;
00290 }
00291 
00292 NS_IMETHODIMP_(float)
00293 nsSVGLibartGlyphMetricsFT::GetPixelScale()
00294 {
00295   nsCOMPtr<nsIPresContext> presContext;
00296   mSource->GetPresContext(getter_AddRefs(presContext));
00297   if (!presContext) {
00298     NS_ERROR("null prescontext");
00299     return 1.0f;
00300   }
00301 
00302   nsCOMPtr<nsIDeviceContext> devicecontext;
00303   presContext->GetDeviceContext(getter_AddRefs(devicecontext));
00304 
00305   float scale;
00306   devicecontext->GetCanonicalPixelScale(scale);
00307   return scale;
00308 }  
00309 
00310 NS_IMETHODIMP_(float)
00311 nsSVGLibartGlyphMetricsFT::GetTwipsToPixels()
00312 {
00313   nsCOMPtr<nsIPresContext> presContext;
00314   mSource->GetPresContext(getter_AddRefs(presContext));
00315   if (!presContext) {
00316     NS_ERROR("null prescontext");
00317     return 1.0f;
00318   }
00319   float twipstopixel;
00320   presContext->GetTwipsToPixels(&twipstopixel);
00321   return twipstopixel;
00322 }  
00323 
00324 NS_IMETHODIMP
00325 nsSVGLibartGlyphMetricsFT::GetBoundingMetrics(PRInt32* aLeftBearing,
00326                                               PRInt32* aRightBearing,
00327                                               PRInt32* aAscent,
00328                                               PRInt32* aDescent,
00329                                               PRInt32* aWidth)
00330 {
00331   *aLeftBearing = 0;
00332   *aRightBearing = 0;
00333   *aAscent = 0;
00334   *aDescent = 0;
00335   *aWidth = 0;
00336   nsresult rv;
00337   FT_BBox bbox;
00338   // initialize to "uninitialized" values
00339   bbox.xMin = bbox.yMin = 32000;
00340   bbox.xMax = bbox.yMax = -32000;
00341 
00342   // get the face/size from the FreeType cache
00343   FT_Face face = GetFTFace();
00344   if (!face) {
00345     NS_ERROR("could not get face");
00346     return NS_ERROR_FAILURE;
00347   }
00348   
00349   FT_GlyphSlot glyphslot=face->glyph;
00350 
00351   FT_UInt glyph_index;
00352   FT_Glyph glyph;
00353   FT_BBox glyph_bbox;
00354 
00355   nsAutoString mtext;
00356   mSource->GetCharacterData(mtext);
00357   nsAString::const_iterator start, end;
00358   mtext.BeginReading(start);
00359   mtext.EndReading(end);
00360   PRUint32 size, i;
00361   
00362   FT_Pos advance,pos=0;
00363 
00364   for ( ; start != end; start.advance(size)) 
00365   {
00366     const PRUnichar* buf = start.get();
00367     size = start.size_forward();
00368     pos=advance=0;
00369     if (size < 1) {
00370       return NS_ERROR_FAILURE;
00371     }
00372     // fragment at 'buf' is 'size' characters long
00373     for (i=0; i<size; ++i)
00374     {
00375       PRUnichar tt=*buf++;
00376       sFt2->GetCharIndex(face, (FT_ULong)tt, &glyph_index);
00377       NS_ASSERTION(glyph_index,"failed to get glyph");
00378 //      if (glyph_index) {
00379       rv = sFt2->LoadGlyph(face,glyph_index,FT_LOAD_RENDER);
00380       NS_ASSERTION(NS_SUCCEEDED(rv),"error loading glyph bitmap");
00381       rv = sFt2->GetGlyph(glyphslot,&glyph);
00382       NS_ASSERTION(NS_SUCCEEDED(rv),"error get glyph");
00383       sFt2->GlyphGetCBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox);
00384       advance = ((glyph->advance.x)>>16);
00385 //      }
00386       bbox.xMin = PR_MIN(pos+glyph_bbox.xMin, bbox.xMin);
00387       bbox.xMax = PR_MAX(pos+glyph_bbox.xMax, bbox.xMax);
00388       bbox.yMin = PR_MIN(glyph_bbox.yMin, bbox.yMin);
00389       bbox.yMax = PR_MAX(glyph_bbox.yMax, bbox.yMax);
00390       pos += advance;
00391     }
00392   } 
00393   if (bbox.xMin > bbox.xMax)
00394     bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0;
00395   *aLeftBearing  = bbox.xMin;
00396   *aRightBearing = bbox.xMax;
00397   *aAscent       = bbox.yMax;
00398   *aDescent      = -bbox.yMin;
00399   *aWidth        = pos;
00400   return NS_OK;
00401 }
00402 
00403 //----------------------------------------------------------------------
00404 // Implementation helpers:
00405 
00406 
00407 struct FindFontStruct {
00408   nsCOMPtr<nsIFontCatalogService> catalog;
00409   nsCOMPtr<nsITrueTypeFontCatalogEntry> font_entry;
00410   nsFont font;
00411 };
00412 
00413 static PRBool
00414 FindFont(const nsString& aFamily, PRBool aGeneric, void *aData)
00415 {
00416   PRBool retval = PR_TRUE;
00417   
00418   FindFontStruct* &font_data = (FindFontStruct*) aData;
00419   
00420 #ifdef DEBUG
00421   printf("trying to instantiate font %s, generic=%d\n", NS_ConvertUCS2toUTF8(aFamily).get(),
00422          aGeneric);
00423 #endif
00424 
00425   nsCAutoString family_name;
00426   
00427   if (aGeneric) {
00428     PRUint8 id;
00429     nsFont::GetGenericID(aFamily, &id);
00430     switch (id) {
00431       case kGenericFont_serif:
00432         family_name = NS_LITERAL_CSTRING("times new roman");
00433         break;
00434       case kGenericFont_monospace:
00435         family_name = NS_LITERAL_CSTRING("courier new");
00436         break;
00437       case kGenericFont_sans_serif:
00438       default:
00439         family_name = NS_LITERAL_CSTRING("arial");
00440         break;
00441     }
00442   }
00443   else {
00444     family_name = NS_ConvertUCS2toUTF8(aFamily);
00445     ToLowerCase(family_name);
00446   }
00447   
00448   nsCAutoString language;
00449   PRUint16 slant = nsIFontCatalogService::kFCSlantRoman;
00450   if (font_data->font.style && NS_FONT_STYLE_ITALIC)
00451     slant = nsIFontCatalogService::kFCSlantItalic;
00452     
00453   nsCOMPtr<nsIArray> arr;
00454   font_data->catalog->GetFontCatalogEntries(family_name,
00455                                             language,
00456                                             font_data->font.weight,
00457                                             nsIFontCatalogService::kFCWeightAny,
00458                                             slant,
00459                                             nsIFontCatalogService::kFCSpacingAny,
00460                                             getter_AddRefs(arr));
00461   PRUint32 count;
00462   arr->GetLength(&count);
00463 #ifdef DEBUG
00464   printf("FindFont(%s): number of fonts found: %d\n", family_name.get(), count);
00465 #endif
00466   if (count>0) {
00467     retval =  PR_FALSE; // break
00468     // just take the first one for now:
00469     arr->QueryElementAt(0, NS_GET_IID(nsITrueTypeFontCatalogEntry),
00470                         getter_AddRefs(font_data->font_entry));
00471   }
00472   else {
00473     // try alias if there is one:
00474     nsDependentString *alias = nsnull;
00475     nsSVGLibartGlyphMetricsFT::sFontAliases.Get(NS_ConvertUTF8toUCS2(family_name),
00476                                                 &alias);
00477     if (alias) {
00478       // XXX this might cause a stack-overflow if there are cyclic
00479       // aliases in sFontAliases
00480       retval = FindFont(nsString(*alias), PR_FALSE, aData);      
00481     }
00482   }
00483   
00484   return retval;      
00485 }
00486 
00487 void
00488 nsSVGLibartGlyphMetricsFT::InitializeFontInfo()
00489 {
00490   if (mImageDesc.font.face_id!=nsnull) return; // already initialized
00491   
00492   FindFontStruct font_data;
00493   mSource->GetFont(&font_data.font);
00494 
00495   font_data.catalog = do_GetService("@mozilla.org/gfx/xfontcatalogservice;1");  
00496   if (!font_data.catalog) {
00497     NS_ERROR("Font Catalog Service init failed\n");
00498     return;
00499   }  
00500 
00501 #ifdef DEBUG
00502   {
00503     printf("Families available:\n");
00504     nsCAutoString empty;
00505     nsCOMPtr<nsIArray> arr;
00506     font_data.catalog->GetFontCatalogEntries(empty, empty, 0, 0, 0, 0, getter_AddRefs(arr));
00507     PRUint32 c;
00508     arr->GetLength(&c);
00509     for (PRUint32 i=0;i<c;++i) {
00510       nsCOMPtr<nsITrueTypeFontCatalogEntry> font = do_QueryElementAt(arr, i);
00511       nsCAutoString family, style, vendor;
00512       font->GetFamilyName(family);
00513       font->GetStyleName(style);
00514       font->GetVendorID(vendor);
00515       printf("* %s, %s, %s\n", family.get(), style.get(), vendor.get());
00516     }
00517   }
00518 #endif
00519 
00520   font_data.font.EnumerateFamilies(FindFont, (void*)&font_data);
00521 
00522   if (!font_data.font_entry) {
00523     // try to find *any* font
00524     nsAutoString empty;
00525     FindFont(empty, PR_FALSE, (void*)&font_data);
00526   }
00527   
00528   if (!font_data.font_entry) {
00529 //    NS_ERROR("svg libart renderer can't find a font (let alone a suitable one)");
00530     if (!sFontErrorShown) {
00531       nsCOMPtr<nsIPromptService> prompter(do_GetService("@mozilla.org/embedcomp/prompt-service;1"));
00532       nsXPIDLString title(NS_LITERAL_STRING("Font Configuration Error"));
00533       nsXPIDLString msg(NS_LITERAL_STRING("The Libart/Freetype SVG rendering backend can't find any truetype fonts on your system. "
00534                                           "Please go to http://www.mozilla.org/projects/fonts/unix/enabling_truetype.html and "
00535                                           "follow steps 2-7."));
00536       prompter->Alert(nsnull, title, msg);
00537       sFontErrorShown = PR_TRUE;
00538     }
00539     return;
00540   }
00541 
00542   // fill mImageDesc:
00543   mImageDesc.font.face_id=(void*)font_data.font_entry.get(); // XXX do we need to addref?
00544   float twipstopixel = GetTwipsToPixels();
00545   float scale = GetPixelScale();
00546   mImageDesc.font.pix_width = (int)((float)(font_data.font.size)*twipstopixel/scale);
00547   mImageDesc.font.pix_height = (int)((float)(font_data.font.size)*twipstopixel/scale);
00548   mImageDesc.image_type |= ftc_image_grays;
00549 }
00550 

Generated on Wed Sep 10 22:25:24 2003 for Mozilla SVG Project Rendering Backend by doxygen1.3