00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
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
00081 NS_DECL_ISUPPORTS
00082
00083
00084 NS_DECL_NSISVGRENDERERGLYPHMETRICS
00085
00086
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
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
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 ×);
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
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
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
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
00339 bbox.xMin = bbox.yMin = 32000;
00340 bbox.xMax = bbox.yMax = -32000;
00341
00342
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
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
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
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;
00468
00469 arr->QueryElementAt(0, NS_GET_IID(nsITrueTypeFontCatalogEntry),
00470 getter_AddRefs(font_data->font_entry));
00471 }
00472 else {
00473
00474 nsDependentString *alias = nsnull;
00475 nsSVGLibartGlyphMetricsFT::sFontAliases.Get(NS_ConvertUTF8toUCS2(family_name),
00476 &alias);
00477 if (alias) {
00478
00479
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;
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
00524 nsAutoString empty;
00525 FindFont(empty, PR_FALSE, (void*)&font_data);
00526 }
00527
00528 if (!font_data.font_entry) {
00529
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
00543 mImageDesc.font.face_id=(void*)font_data.font_entry.get();
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