Back to index

lightning-sunbird  0.9+nobinonly
nsSVGGDIPlusGlyphMetrics.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 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 the Mozilla SVG project.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Crocodile Clips Ltd..
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include <windows.h>
00040 
00041 // unknwn.h is needed to build with WIN32_LEAN_AND_MEAN
00042 #include <unknwn.h>
00043 
00044 #include <Gdiplus.h>
00045 using namespace Gdiplus;
00046 
00047 #include "nsUnicharUtils.h"
00048 #include "nsCOMPtr.h"
00049 #include "nsISVGGlyphMetricsSource.h"
00050 #include "nsPromiseFlatString.h"
00051 #include "nsFont.h"
00052 #include "nsPresContext.h"
00053 #include "nsDeviceContextWin.h"
00054 #include "nsISVGGDIPlusGlyphMetrics.h"
00055 #include "nsSVGGDIPlusGlyphMetrics.h"
00056 #include "float.h"
00057 #include "nsIDOMSVGMatrix.h"
00058 #include "nsIDOMSVGRect.h"
00059 #include "nsSVGTypeCIDs.h"
00060 #include "nsIComponentManager.h"
00061 #include "nsDataHashtable.h"
00062 
00067 
00068 
00073 class nsWindowsDC {
00074 public:
00075   nsWindowsDC(nsPresContext* presContext);
00076   ~nsWindowsDC();
00077   operator HDC() { return mHDC; }
00078 private:
00079   bool isWndDC;
00080   HWND mWND;
00081   HDC mHDC;
00082 };
00083 
00087 nsWindowsDC::nsWindowsDC(nsPresContext* presContext)
00088 {
00089   nsIDeviceContext* devicecontext = presContext->DeviceContext();
00090 
00091   isWndDC=((nsDeviceContextWin *)devicecontext)->mDC==nsnull;
00092   if (isWndDC) {
00093     mWND = (HWND)((nsDeviceContextWin *)devicecontext)->mWidget;
00094     NS_ASSERTION(mWND, "no window and no handle in devicecontext (continuing with screen dc)");
00095     mHDC = ::GetDC(mWND);
00096   }
00097   else
00098     mHDC = ((nsDeviceContextWin *)devicecontext)->mDC;
00099 }
00100 
00101 nsWindowsDC::~nsWindowsDC()
00102 {
00103   if (isWndDC)
00104     ::ReleaseDC(mWND, mHDC);
00105 }
00106 
00111 
00112 
00115 class nsSVGGDIPlusGlyphMetrics : public nsISVGGDIPlusGlyphMetrics
00116 {
00117 protected:
00118   friend nsresult NS_NewSVGGDIPlusGlyphMetrics(nsISVGRendererGlyphMetrics **result,
00119                                                nsISVGGlyphMetricsSource *src);
00120   friend void NS_InitSVGGDIPlusGlyphMetricsGlobals();
00121   friend void NS_FreeSVGGDIPlusGlyphMetricsGlobals();
00122   nsSVGGDIPlusGlyphMetrics(nsISVGGlyphMetricsSource *src);
00123   ~nsSVGGDIPlusGlyphMetrics();
00124 public:
00125   // nsISupports interface:
00126   NS_DECL_ISUPPORTS
00127 
00128   // nsISVGRendererGlyphMetrics interface:
00129   NS_DECL_NSISVGRENDERERGLYPHMETRICS
00130 
00131   // nsISVGGDIPlusGlyphMetrics interface:
00132   NS_IMETHOD_(const RectF*) GetBoundingRect();
00133   NS_IMETHOD_(void) GetSubBoundingRect(PRUint32 charoffset, PRUint32 count,
00134                                        RectF* retval, PRBool aLocalCoord = PR_TRUE);
00135   NS_IMETHOD_(const Font*) GetFont();
00136   NS_IMETHOD_(TextRenderingHint) GetTextRenderingHint();
00137   
00138 protected:
00139   void MarkRectForUpdate() { mRectNeedsUpdate = PR_TRUE; }
00140   void ClearFontInfo() { if (mFont) { delete mFont; mFont = nsnull; }}
00141   void InitializeFontInfo();
00142   void GetGlobalTransform(Matrix *matrix);
00143   void PrepareGraphics(Graphics &g);
00144   float GetPixelScale();
00145 
00146 private:  
00147   PRBool mRectNeedsUpdate;
00148   RectF mRect;
00149   Font *mFont;
00150   nsCOMPtr<nsISVGGlyphMetricsSource> mSource;
00151   
00152 public:
00153   static nsDataHashtable<nsStringHashKey,const nsString*> sFontAliases;
00154 };
00155 
00158 //----------------------------------------------------------------------
00159 // implementation:
00160 
00161 nsDataHashtable<nsStringHashKey,const nsString*>
00162 nsSVGGDIPlusGlyphMetrics::sFontAliases;
00163 
00164 nsSVGGDIPlusGlyphMetrics::nsSVGGDIPlusGlyphMetrics(nsISVGGlyphMetricsSource *src)
00165     : mRectNeedsUpdate(PR_TRUE), mFont(nsnull), mSource(src)
00166 {
00167 }
00168 
00169 nsSVGGDIPlusGlyphMetrics::~nsSVGGDIPlusGlyphMetrics()
00170 {
00171   ClearFontInfo();
00172 }
00173 
00174 nsresult
00175 NS_NewSVGGDIPlusGlyphMetrics(nsISVGRendererGlyphMetrics **result,
00176                              nsISVGGlyphMetricsSource *src)
00177 {
00178   *result = new nsSVGGDIPlusGlyphMetrics(src);
00179   if (!*result) return NS_ERROR_OUT_OF_MEMORY;
00180   
00181   NS_ADDREF(*result);
00182   return NS_OK;
00183 }
00184 
00185 void NS_InitSVGGDIPlusGlyphMetricsGlobals()
00186 {
00187   NS_ASSERTION(!nsSVGGDIPlusGlyphMetrics::sFontAliases.IsInitialized(),
00188                "already initialized");
00189   nsSVGGDIPlusGlyphMetrics::sFontAliases.Init(3);
00190 
00191   static NS_NAMED_LITERAL_STRING(arial, "arial");
00192   nsSVGGDIPlusGlyphMetrics::sFontAliases.Put(NS_LITERAL_STRING("helvetica"),
00193                                              &arial);
00194 
00195   static NS_NAMED_LITERAL_STRING(courier, "courier new");
00196   nsSVGGDIPlusGlyphMetrics::sFontAliases.Put(NS_LITERAL_STRING("courier"),
00197                                              &courier);
00198 
00199   static NS_NAMED_LITERAL_STRING(times, "times new roman");
00200   nsSVGGDIPlusGlyphMetrics::sFontAliases.Put(NS_LITERAL_STRING("times"),
00201                                              &times);
00202 }
00203 
00204 void NS_FreeSVGGDIPlusGlyphMetricsGlobals()
00205 {
00206   nsSVGGDIPlusGlyphMetrics::sFontAliases.Clear();
00207 }
00208 
00209 //----------------------------------------------------------------------
00210 // nsISupports methods:
00211 
00212 NS_IMPL_ADDREF(nsSVGGDIPlusGlyphMetrics)
00213 NS_IMPL_RELEASE(nsSVGGDIPlusGlyphMetrics)
00214 
00215 NS_INTERFACE_MAP_BEGIN(nsSVGGDIPlusGlyphMetrics)
00216   NS_INTERFACE_MAP_ENTRY(nsISVGRendererGlyphMetrics)
00217   NS_INTERFACE_MAP_ENTRY(nsISVGGDIPlusGlyphMetrics)
00218   NS_INTERFACE_MAP_ENTRY(nsISupports)
00219 NS_INTERFACE_MAP_END
00220 
00221 //----------------------------------------------------------------------
00222 // nsISVGRendererGlyphMetrics methods:
00223 
00225 NS_IMETHODIMP
00226 nsSVGGDIPlusGlyphMetrics::GetBaselineOffset(PRUint16 baselineIdentifier, float *_retval)
00227 {
00228   if (!GetFont()) {
00229     NS_ERROR("no font");
00230     return NS_ERROR_FAILURE;
00231   }
00232   NS_ASSERTION(GetFont()->GetUnit()==UnitPixel, "font unit is not in world units");
00233 
00234   switch (baselineIdentifier) {
00235     case BASELINE_TEXT_BEFORE_EDGE:
00236       *_retval = GetBoundingRect()->Y;
00237       break;
00238     case BASELINE_TEXT_AFTER_EDGE:
00239       *_retval = (float)(UINT16)(GetBoundingRect()->Y + GetBoundingRect()->Height + 0.5);
00240       break;
00241     case BASELINE_CENTRAL:
00242     case BASELINE_MIDDLE:
00243       *_retval = (float)(UINT16)(GetBoundingRect()->Y + GetBoundingRect()->Height/2.0 + 0.5);
00244       break;
00245     case BASELINE_ALPHABETIC:
00246     default:
00247     {
00248       FontFamily family;
00249       GetFont()->GetFamily(&family);
00250       INT style = GetFont()->GetStyle();
00251       // alternatively to rounding here, we could set the
00252       // pixeloffsetmode to 'PixelOffsetModeHalf' on painting
00253       *_retval = (float)(UINT16)(GetBoundingRect()->Y
00254                                  + GetFont()->GetSize()
00255                                    *family.GetCellAscent(style)/family.GetEmHeight(style)
00256                                  + 0.5);
00257 #ifdef DEBUG
00258 //       printf("Glyph Metrics:\n"
00259 //              "--------------\n"
00260 //              "ascent:%d\n"
00261 //              "boundingheight:%f\n"
00262 //              "fontheight:%f\n"
00263 //              "fontsize:%f\n"
00264 //              "emheight:%d\n"
00265 //              "linespacing:%d\n"
00266 //              "calculated offset:%f\n"
00267 //              "descent:%d\n"
00268 //              "fh-bh:%f\n"
00269 //              "fontsize/emheight:%f\n"
00270 //              "fontheight/linespacing:%f\n"
00271 //              "boundingheight/(ascent+descent):%f\n"
00272 //              "boundingbox.Y:%f\n"
00273 //              "--------------\n",
00274 //              family.GetCellAscent(style),
00275 //              GetBoundingRect()->Height,
00276 //              GetFontHeight(),
00277 //              GetFont()->GetSize(),
00278 //              family.GetEmHeight(style),
00279 //              family.GetLineSpacing(style),
00280 //              *_retval,
00281 //              family.GetCellDescent(style),
00282 //              GetFontHeight()-GetBoundingRect()->Height,
00283 //              GetFont()->GetSize()/family.GetEmHeight(style),
00284 //              GetFontHeight()/family.GetLineSpacing(style),
00285 //              GetBoundingRect()->Height/(family.GetCellAscent(style)+family.GetCellDescent(style)),
00286 //              GetBoundingRect()->Y);
00287 #endif
00288     }
00289     break;
00290   }
00291   
00292   return NS_OK;
00293 }
00294 
00295 
00297 NS_IMETHODIMP
00298 nsSVGGDIPlusGlyphMetrics::GetAdvance(float *aAdvance)
00299 {
00300   // XXX
00301   *aAdvance = GetBoundingRect()->Width;
00302   return NS_OK;
00303 }
00304 
00305 
00307 NS_IMETHODIMP
00308 nsSVGGDIPlusGlyphMetrics::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
00309 {
00310   *_retval = nsnull;
00311 
00312   RectF bounds;
00313   GetSubBoundingRect(charnum, 1, &bounds);
00314   
00315   nsCOMPtr<nsIDOMSVGRect> rect = do_CreateInstance(NS_SVGRECT_CONTRACTID);
00316 
00317   NS_ASSERTION(rect, "could not create rect");
00318   if (!rect) return NS_ERROR_FAILURE;
00319   
00320   rect->SetX(bounds.X);
00321   rect->SetY(bounds.Y);
00322   rect->SetWidth(bounds.Width);
00323   rect->SetHeight(bounds.Height);
00324 
00325   *_retval = rect;
00326   NS_ADDREF(*_retval);
00327   
00328   return NS_OK;
00329 }
00330 
00331 NS_IMETHODIMP
00332 nsSVGGDIPlusGlyphMetrics::GetAdvanceOfChar(PRUint32 charnum, float *advance)
00333 {
00334   RectF bounds;
00335   GetSubBoundingRect(charnum, 1, &bounds);
00336 
00337   // not really correct, but seems the best that GDI+ has to offer
00338   *advance = bounds.Width;
00339   
00340   return NS_OK;
00341 }
00342 
00344 NS_IMETHODIMP
00345 nsSVGGDIPlusGlyphMetrics::Update(PRUint32 updatemask, PRBool *_retval)
00346 {
00347   *_retval = PR_FALSE;
00348   
00349   if (updatemask & nsISVGGlyphMetricsSource::UPDATEMASK_CHARACTER_DATA) {
00350     MarkRectForUpdate();
00351     *_retval = PR_TRUE;
00352   }
00353 
00354   if (updatemask & nsISVGGlyphMetricsSource::UPDATEMASK_FONT) {
00355     ClearFontInfo();
00356     MarkRectForUpdate();
00357     *_retval = PR_TRUE;
00358   }
00359   
00360   return NS_OK;
00361 }
00362 
00363 //----------------------------------------------------------------------
00364 // nsISVGGDIPlusGlyphMetrics methods:
00365 
00366 NS_IMETHODIMP_(const RectF*)
00367 nsSVGGDIPlusGlyphMetrics::GetBoundingRect()
00368 {
00369   if (!mRectNeedsUpdate) return &mRect;
00370   mRectNeedsUpdate = PR_FALSE;
00371   
00372   nsAutoString text;
00373   mSource->GetCharacterData(text);
00374 
00375   GetSubBoundingRect(0, text.Length(), &mRect);
00376 
00377   return &mRect;
00378 
00379 }
00380 
00381 NS_IMETHODIMP_(void)
00382 nsSVGGDIPlusGlyphMetrics::GetSubBoundingRect(PRUint32 charoffset, PRUint32 count,
00383                                              RectF* retval, PRBool aLocalCoord)
00384 {
00385   nsCOMPtr<nsPresContext> presContext;
00386   mSource->GetPresContext(getter_AddRefs(presContext));
00387   NS_ASSERTION(presContext, "null prescontext");
00388 
00389   nsWindowsDC devicehandle(presContext);
00390   Graphics graphics(devicehandle);
00391   PrepareGraphics(graphics);
00392   
00393   nsAutoString text;
00394   mSource->GetCharacterData(text);
00395   
00396   StringFormat stringFormat(StringFormat::GenericTypographic());
00397   stringFormat.SetFormatFlags(stringFormat.GetFormatFlags() |
00398                               StringFormatFlagsMeasureTrailingSpaces);
00399   
00400   CharacterRange charRange(charoffset, count);
00401   stringFormat.SetMeasurableCharacterRanges(1, &charRange);
00402   
00403   Region region;
00404   region.MakeEmpty();
00405   
00406   // we measure in the transformed coordinate system...
00407   GraphicsState state = graphics.Save();
00408   
00409   Matrix m;
00410   GetGlobalTransform(&m);
00411   graphics.MultiplyTransform(&m);
00412   
00413   graphics.MeasureCharacterRanges(PromiseFlatString(text).get(), -1, GetFont(),
00414                                   RectF(0.0f, 0.0f, FLT_MAX, FLT_MAX), &stringFormat, 1, &region);
00415   
00416   if (aLocalCoord) {
00417     // ... and obtain the bounds in our local coord system
00418     graphics.Restore(state);
00419   }
00420   
00421   region.GetBounds(retval, &graphics);  
00422 }
00423 
00424 NS_IMETHODIMP_(const Font*)
00425 nsSVGGDIPlusGlyphMetrics::GetFont()
00426 {
00427   InitializeFontInfo();
00428   return mFont;
00429 }
00430 
00431 NS_IMETHODIMP_(TextRenderingHint)
00432 nsSVGGDIPlusGlyphMetrics::GetTextRenderingHint()
00433 {
00434   // when the text is stroked, we have to turn off hinting so that
00435   // stroke and fill match up exactely:
00436   bool forceUnhinted = PR_FALSE;
00437   {
00438     PRUint16 type;
00439     mSource->GetStrokePaintType(&type);
00440     forceUnhinted = (type != nsISVGGeometrySource::PAINT_TYPE_NONE); 
00441   }
00442 
00443   PRUint16 textRendering;
00444   mSource->GetTextRendering(&textRendering);
00445   switch (textRendering) {
00446     case nsISVGGlyphMetricsSource::TEXT_RENDERING_OPTIMIZESPEED:
00447       return TextRenderingHintSingleBitPerPixel;
00448       break;
00449     case nsISVGGlyphMetricsSource::TEXT_RENDERING_OPTIMIZELEGIBILITY:
00450       return forceUnhinted ?
00451         TextRenderingHintAntiAlias :
00452         TextRenderingHintAntiAliasGridFit;
00453       break;
00454     case nsISVGGlyphMetricsSource::TEXT_RENDERING_GEOMETRICPRECISION:
00455     case nsISVGGlyphMetricsSource::TEXT_RENDERING_AUTO:
00456     default:
00457       return TextRenderingHintAntiAlias;
00458       break;
00459   }
00460 }
00461 
00462 // helper function used in
00463 // nsSVGGDIPlusGlyphMetrics::InitializeFontInfo() to construct a gdi+
00464 // fontfamily object
00465 static PRBool FindFontFamily(const nsString& aFamily, PRBool aGeneric, void *aData)
00466 {
00467   PRBool retval = PR_TRUE;
00468   
00469 #ifdef DEBUG
00470 //   printf("trying to instantiate font %s, generic=%d\n", NS_ConvertUCS2toUTF8(aFamily).get(),
00471 //          aGeneric);
00472 #endif
00473   
00474   FontFamily *family = nsnull;
00475   if (!aGeneric)
00476     family = new FontFamily(aFamily.get());
00477   else {
00478     PRUint8 id;
00479     nsFont::GetGenericID(aFamily, &id);
00480     switch (id) {
00481       case kGenericFont_serif:
00482         family = FontFamily::GenericSerif()->Clone();
00483         break;
00484       case kGenericFont_monospace:
00485         family = FontFamily::GenericMonospace()->Clone();
00486         break;
00487       case kGenericFont_sans_serif:
00488       default:
00489         family = FontFamily::GenericSansSerif()->Clone();
00490         break;
00491     }
00492   }
00493 
00494   if (family->IsAvailable()) {
00495     retval = PR_FALSE; // break
00496     *(FontFamily**)aData = family;
00497   }
00498   else {
00499     delete family;
00500     
00501     //try alias if there is one:
00502     const nsString *alias = nsnull;
00503     nsAutoString canonical_name(aFamily);
00504     ToLowerCase(canonical_name);
00505     nsSVGGDIPlusGlyphMetrics::sFontAliases.Get(canonical_name, &alias);
00506     if (alias) {
00507       // XXX this might cause a stack-overflow if there are cyclic
00508       // aliases in sFontAliases
00509       retval = FindFontFamily(*alias, PR_FALSE, aData);
00510     }
00511   }
00512 
00513   return retval;
00514 }
00515 
00516 void
00517 nsSVGGDIPlusGlyphMetrics::InitializeFontInfo()
00518 {
00519   if (mFont) return; // already initialized
00520 
00521   nsCOMPtr<nsPresContext> presContext;
00522   mSource->GetPresContext(getter_AddRefs(presContext));
00523   if (!presContext) {
00524     NS_ERROR("null prescontext");
00525     return;
00526   }
00527 
00528   float pxPerTwips;
00529   pxPerTwips = presContext->TwipsToPixels();
00530   pxPerTwips/=GetPixelScale();
00531   
00532   nsFont font;
00533   mSource->GetFont(&font);
00534 
00535   FontFamily *pFamily = nsnull;
00536   font.EnumerateFamilies(FindFontFamily, (void*)&pFamily);
00537   NS_ASSERTION(pFamily, "couldn't create family");
00538 
00539   int style = FontStyleRegular;
00540   if (font.style == NS_FONT_STYLE_ITALIC) style |= FontStyleItalic;
00541   if (font.weight % 100 == 0) { // absolute case
00542     if (font.weight >= 600) style |= FontStyleBold;
00543   }
00544   else if (font.weight % 100 < 50) { // relative 'bolder' case
00545     style |= FontStyleBold;
00546   }
00547 
00548   if (font.decorations & NS_FONT_DECORATION_UNDERLINE) style |= FontStyleUnderline;
00549   if (font.decorations & NS_FONT_DECORATION_LINE_THROUGH) style |= FontStyleStrikeout;
00550   
00551   mFont = new Font(pFamily, font.size*pxPerTwips, style, UnitPixel); 
00552   NS_ASSERTION(mFont->IsAvailable(),"font not available");
00553   delete pFamily;
00554   pFamily = nsnull;
00555   
00556 #ifdef DEBUG
00557 //   {
00558 //     FontFamily fontFamily;
00559 //     mFont->GetFamily(&fontFamily);
00560 //     WCHAR familyName[100];
00561 //     fontFamily.GetFamilyName(familyName);
00562 //     printf("font loaded: "); printf(NS_ConvertUCS2toUTF8(familyName).get()); printf("\n");
00563 //   }
00564 #endif
00565 }
00566 
00567 void
00568 nsSVGGDIPlusGlyphMetrics::GetGlobalTransform(Matrix *matrix)
00569 {
00570   nsCOMPtr<nsIDOMSVGMatrix> ctm;
00571   mSource->GetCanvasTM(getter_AddRefs(ctm));
00572   NS_ASSERTION(ctm, "graphic source didn't specify a ctm");
00573   
00574   float m[6];
00575   float val;
00576   ctm->GetA(&val);
00577   m[0] = val;
00578   
00579   ctm->GetB(&val);
00580   m[1] = val;
00581   
00582   ctm->GetC(&val);  
00583   m[2] = val;  
00584   
00585   ctm->GetD(&val);  
00586   m[3] = val;  
00587   
00588   ctm->GetE(&val);
00589   m[4] = val;
00590   
00591   ctm->GetF(&val);
00592   m[5] = val;
00593 
00594   matrix->SetElements(m[0],m[1],m[2],m[3],m[4],m[5]);
00595 }
00596 
00597 
00598 void
00599 nsSVGGDIPlusGlyphMetrics::PrepareGraphics(Graphics &g)
00600 {
00601   g.SetPageUnit(UnitPixel);
00602   // XXX for some reason the Graphics object that we derive from our
00603   // measurement dcs is never correctly scaled for devices like
00604   // printers. Hence we scale manually here:
00605   g.SetPageScale(GetPixelScale());
00606   g.SetSmoothingMode(SmoothingModeAntiAlias);
00607   //g.SetPixelOffsetMode(PixelOffsetModeHalf);
00608   g.SetTextRenderingHint(GetTextRenderingHint());
00609 }
00610 
00611 float
00612 nsSVGGDIPlusGlyphMetrics::GetPixelScale()
00613 {
00614   nsCOMPtr<nsPresContext> presContext;
00615   mSource->GetPresContext(getter_AddRefs(presContext));
00616   if (!presContext) {
00617     NS_ERROR("null prescontext");
00618     return 1.0f;
00619   }
00620 
00621   float scale;
00622   presContext->DeviceContext()->GetCanonicalPixelScale(scale);
00623   return scale;
00624 }