gfx/src/nsDeviceContext.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsDeviceContext.h"
     7 #include <algorithm>                    // for max
     8 #include "gfxASurface.h"                // for gfxASurface, etc
     9 #include "gfxFont.h"                    // for gfxFontGroup
    10 #include "gfxImageSurface.h"            // for gfxImageSurface
    11 #include "gfxPoint.h"                   // for gfxSize
    12 #include "mozilla/Attributes.h"         // for MOZ_FINAL
    13 #include "mozilla/Preferences.h"        // for Preferences
    14 #include "mozilla/Services.h"           // for GetObserverService
    15 #include "mozilla/mozalloc.h"           // for operator new
    16 #include "nsCRT.h"                      // for nsCRT
    17 #include "nsDebug.h"                    // for NS_NOTREACHED, NS_ASSERTION, etc
    18 #include "nsFont.h"                     // for nsFont
    19 #include "nsFontMetrics.h"              // for nsFontMetrics
    20 #include "nsIAtom.h"                    // for nsIAtom, do_GetAtom
    21 #include "nsID.h"
    22 #include "nsIDeviceContextSpec.h"       // for nsIDeviceContextSpec
    23 #include "nsILanguageAtomService.h"     // for nsILanguageAtomService, etc
    24 #include "nsIObserver.h"                // for nsIObserver, etc
    25 #include "nsIObserverService.h"         // for nsIObserverService
    26 #include "nsIScreen.h"                  // for nsIScreen
    27 #include "nsIScreenManager.h"           // for nsIScreenManager
    28 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
    29 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
    30 #include "nsIWidget.h"                  // for nsIWidget, NS_NATIVE_WINDOW
    31 #include "nsRect.h"                     // for nsRect
    32 #include "nsRenderingContext.h"         // for nsRenderingContext
    33 #include "nsServiceManagerUtils.h"      // for do_GetService
    34 #include "nsString.h"               // for nsDependentString
    35 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
    36 #include "nsThreadUtils.h"              // for NS_IsMainThread
    38 #if !XP_MACOSX
    39 #include "gfxPDFSurface.h"
    40 #endif
    42 #ifdef MOZ_WIDGET_GTK
    43 #include "gfxPSSurface.h"
    44 #elif XP_WIN
    45 #include "gfxWindowsSurface.h"
    46 #elif XP_MACOSX
    47 #include "gfxQuartzSurface.h"
    48 #endif
    50 using namespace mozilla;
    51 using mozilla::services::GetObserverService;
    53 class nsFontCache MOZ_FINAL : public nsIObserver
    54 {
    55 public:
    56     nsFontCache()   { MOZ_COUNT_CTOR(nsFontCache); }
    57     ~nsFontCache()  { MOZ_COUNT_DTOR(nsFontCache); }
    59     NS_DECL_ISUPPORTS
    60     NS_DECL_NSIOBSERVER
    62     void Init(nsDeviceContext* aContext);
    63     void Destroy();
    65     nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
    66                            gfxUserFontSet* aUserFontSet,
    67                            gfxTextPerfMetrics* aTextPerf,
    68                            nsFontMetrics*& aMetrics);
    70     void FontMetricsDeleted(const nsFontMetrics* aFontMetrics);
    71     void Compact();
    72     void Flush();
    74 protected:
    75     nsDeviceContext*          mContext; // owner
    76     nsCOMPtr<nsIAtom>         mLocaleLanguage;
    77     nsTArray<nsFontMetrics*>  mFontMetrics;
    78 };
    80 NS_IMPL_ISUPPORTS(nsFontCache, nsIObserver)
    82 // The Init and Destroy methods are necessary because it's not
    83 // safe to call AddObserver from a constructor or RemoveObserver
    84 // from a destructor.  That should be fixed.
    85 void
    86 nsFontCache::Init(nsDeviceContext* aContext)
    87 {
    88     mContext = aContext;
    89     // register as a memory-pressure observer to free font resources
    90     // in low-memory situations.
    91     nsCOMPtr<nsIObserverService> obs = GetObserverService();
    92     if (obs)
    93         obs->AddObserver(this, "memory-pressure", false);
    95     nsCOMPtr<nsILanguageAtomService> langService;
    96     langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
    97     if (langService) {
    98         mLocaleLanguage = langService->GetLocaleLanguage();
    99     }
   100     if (!mLocaleLanguage) {
   101         mLocaleLanguage = do_GetAtom("x-western");
   102     }
   103 }
   105 void
   106 nsFontCache::Destroy()
   107 {
   108     nsCOMPtr<nsIObserverService> obs = GetObserverService();
   109     if (obs)
   110         obs->RemoveObserver(this, "memory-pressure");
   111     Flush();
   112 }
   114 NS_IMETHODIMP
   115 nsFontCache::Observe(nsISupports*, const char* aTopic, const char16_t*)
   116 {
   117     if (!nsCRT::strcmp(aTopic, "memory-pressure"))
   118         Compact();
   119     return NS_OK;
   120 }
   122 nsresult
   123 nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
   124                            gfxUserFontSet* aUserFontSet,
   125                            gfxTextPerfMetrics* aTextPerf,
   126                            nsFontMetrics*& aMetrics)
   127 {
   128     if (!aLanguage)
   129         aLanguage = mLocaleLanguage;
   131     // First check our cache
   132     // start from the end, which is where we put the most-recent-used element
   134     nsFontMetrics* fm;
   135     int32_t n = mFontMetrics.Length() - 1;
   136     for (int32_t i = n; i >= 0; --i) {
   137         fm = mFontMetrics[i];
   138         if (fm->Font().Equals(aFont) && fm->GetUserFontSet() == aUserFontSet &&
   139             fm->Language() == aLanguage) {
   140             if (i != n) {
   141                 // promote it to the end of the cache
   142                 mFontMetrics.RemoveElementAt(i);
   143                 mFontMetrics.AppendElement(fm);
   144             }
   145             fm->GetThebesFontGroup()->UpdateFontList();
   146             NS_ADDREF(aMetrics = fm);
   147             return NS_OK;
   148         }
   149     }
   151     // It's not in the cache. Get font metrics and then cache them.
   153     fm = new nsFontMetrics();
   154     NS_ADDREF(fm);
   155     nsresult rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet, aTextPerf);
   156     if (NS_SUCCEEDED(rv)) {
   157         // the mFontMetrics list has the "head" at the end, because append
   158         // is cheaper than insert
   159         mFontMetrics.AppendElement(fm);
   160         aMetrics = fm;
   161         NS_ADDREF(aMetrics);
   162         return NS_OK;
   163     }
   164     fm->Destroy();
   165     NS_RELEASE(fm);
   167     // One reason why Init() fails is because the system is running out of
   168     // resources. e.g., on Win95/98 only a very limited number of GDI
   169     // objects are available. Compact the cache and try again.
   171     Compact();
   172     fm = new nsFontMetrics();
   173     NS_ADDREF(fm);
   174     rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet, aTextPerf);
   175     if (NS_SUCCEEDED(rv)) {
   176         mFontMetrics.AppendElement(fm);
   177         aMetrics = fm;
   178         return NS_OK;
   179     }
   180     fm->Destroy();
   181     NS_RELEASE(fm);
   183     // could not setup a new one, send an old one (XXX search a "best
   184     // match"?)
   186     n = mFontMetrics.Length() - 1; // could have changed in Compact()
   187     if (n >= 0) {
   188         aMetrics = mFontMetrics[n];
   189         NS_ADDREF(aMetrics);
   190         return NS_OK;
   191     }
   193     NS_POSTCONDITION(NS_SUCCEEDED(rv),
   194                      "font metrics should not be null - bug 136248");
   195     return rv;
   196 }
   198 void
   199 nsFontCache::FontMetricsDeleted(const nsFontMetrics* aFontMetrics)
   200 {
   201     mFontMetrics.RemoveElement(aFontMetrics);
   202 }
   204 void
   205 nsFontCache::Compact()
   206 {
   207     // Need to loop backward because the running element can be removed on
   208     // the way
   209     for (int32_t i = mFontMetrics.Length()-1; i >= 0; --i) {
   210         nsFontMetrics* fm = mFontMetrics[i];
   211         nsFontMetrics* oldfm = fm;
   212         // Destroy() isn't here because we want our device context to be
   213         // notified
   214         NS_RELEASE(fm); // this will reset fm to nullptr
   215         // if the font is really gone, it would have called back in
   216         // FontMetricsDeleted() and would have removed itself
   217         if (mFontMetrics.IndexOf(oldfm) != mFontMetrics.NoIndex) {
   218             // nope, the font is still there, so let's hold onto it too
   219             NS_ADDREF(oldfm);
   220         }
   221     }
   222 }
   224 void
   225 nsFontCache::Flush()
   226 {
   227     for (int32_t i = mFontMetrics.Length()-1; i >= 0; --i) {
   228         nsFontMetrics* fm = mFontMetrics[i];
   229         // Destroy() will unhook our device context from the fm so that we
   230         // won't waste time in triggering the notification of
   231         // FontMetricsDeleted() in the subsequent release
   232         fm->Destroy();
   233         NS_RELEASE(fm);
   234     }
   235     mFontMetrics.Clear();
   236 }
   238 nsDeviceContext::nsDeviceContext()
   239     : mWidth(0), mHeight(0), mDepth(0),
   240       mAppUnitsPerDevPixel(-1), mAppUnitsPerDevNotScaledPixel(-1),
   241       mAppUnitsPerPhysicalInch(-1),
   242       mPixelScale(1.0f), mPrintingScale(1.0f),
   243       mFontCache(nullptr)
   244 {
   245     MOZ_ASSERT(NS_IsMainThread(), "nsDeviceContext created off main thread");
   246 }
   248 // Note: we use a bare pointer for mFontCache so that nsFontCache
   249 // can be an incomplete type in nsDeviceContext.h.
   250 // Therefore we have to do all the refcounting by hand.
   251 nsDeviceContext::~nsDeviceContext()
   252 {
   253     if (mFontCache) {
   254         mFontCache->Destroy();
   255         NS_RELEASE(mFontCache);
   256     }
   257 }
   259 nsresult
   260 nsDeviceContext::GetMetricsFor(const nsFont& aFont,
   261                                nsIAtom* aLanguage,
   262                                gfxUserFontSet* aUserFontSet,
   263                                gfxTextPerfMetrics* aTextPerf,
   264                                nsFontMetrics*& aMetrics)
   265 {
   266     if (!mFontCache) {
   267         mFontCache = new nsFontCache();
   268         NS_ADDREF(mFontCache);
   269         mFontCache->Init(this);
   270     }
   272     return mFontCache->GetMetricsFor(aFont, aLanguage, aUserFontSet,
   273                                      aTextPerf, aMetrics);
   274 }
   276 nsresult
   277 nsDeviceContext::FlushFontCache(void)
   278 {
   279     if (mFontCache)
   280         mFontCache->Flush();
   281     return NS_OK;
   282 }
   284 nsresult
   285 nsDeviceContext::FontMetricsDeleted(const nsFontMetrics* aFontMetrics)
   286 {
   287     if (mFontCache) {
   288         mFontCache->FontMetricsDeleted(aFontMetrics);
   289     }
   290     return NS_OK;
   291 }
   293 bool
   294 nsDeviceContext::IsPrinterSurface()
   295 {
   296     return mPrintingSurface != nullptr;
   297 }
   299 void
   300 nsDeviceContext::SetDPI()
   301 {
   302     float dpi = -1.0f;
   304     // PostScript, PDF and Mac (when printing) all use 72 dpi
   305     // Use a printing DC to determine the other dpi values
   306     if (mPrintingSurface) {
   307         switch (mPrintingSurface->GetType()) {
   308         case gfxSurfaceType::PDF:
   309         case gfxSurfaceType::PS:
   310         case gfxSurfaceType::Quartz:
   311             dpi = 72.0f;
   312             break;
   313 #ifdef XP_WIN
   314         case gfxSurfaceType::Win32:
   315         case gfxSurfaceType::Win32Printing: {
   316             HDC dc = reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
   317             int32_t OSVal = GetDeviceCaps(dc, LOGPIXELSY);
   318             dpi = 144.0f;
   319             mPrintingScale = float(OSVal) / dpi;
   320             break;
   321         }
   322 #endif
   323         default:
   324             NS_NOTREACHED("Unexpected printing surface type");
   325             break;
   326         }
   328         mAppUnitsPerDevNotScaledPixel =
   329             NS_lround((AppUnitsPerCSSPixel() * 96) / dpi);
   330     } else {
   331         // A value of -1 means use the maximum of 96 and the system DPI.
   332         // A value of 0 means use the system DPI. A positive value is used as the DPI.
   333         // This sets the physical size of a device pixel and thus controls the
   334         // interpretation of physical units.
   335         int32_t prefDPI = Preferences::GetInt("layout.css.dpi", -1);
   337         if (prefDPI > 0) {
   338             dpi = prefDPI;
   339         } else if (mWidget) {
   340             dpi = mWidget->GetDPI();
   342             if (prefDPI < 0) {
   343                 dpi = std::max(96.0f, dpi);
   344             }
   345         } else {
   346             dpi = 96.0f;
   347         }
   349         CSSToLayoutDeviceScale scale = mWidget ? mWidget->GetDefaultScale()
   350                                                : CSSToLayoutDeviceScale(1.0);
   351         double devPixelsPerCSSPixel = scale.scale;
   353         mAppUnitsPerDevNotScaledPixel =
   354             std::max(1, NS_lround(AppUnitsPerCSSPixel() / devPixelsPerCSSPixel));
   355     }
   357     NS_ASSERTION(dpi != -1.0, "no dpi set");
   359     mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevNotScaledPixel);
   360     UpdateScaledAppUnits();
   361 }
   363 nsresult
   364 nsDeviceContext::Init(nsIWidget *aWidget)
   365 {
   366     if (mScreenManager && mWidget == aWidget)
   367         return NS_OK;
   369     mWidget = aWidget;
   370     SetDPI();
   372     if (mScreenManager)
   373         return NS_OK;
   375     mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
   377     return NS_OK;
   378 }
   380 already_AddRefed<nsRenderingContext>
   381 nsDeviceContext::CreateRenderingContext()
   382 {
   383     nsRefPtr<gfxASurface> printingSurface = mPrintingSurface;
   384 #ifdef XP_MACOSX
   385     // CreateRenderingContext() can be called (on reflow) after EndPage()
   386     // but before BeginPage().  On OS X (and only there) mPrintingSurface
   387     // will in this case be null, because OS X printing surfaces are
   388     // per-page, and therefore only truly valid between calls to BeginPage()
   389     // and EndPage().  But we can get away with fudging things here, if need
   390     // be, by using a cached copy.
   391     if (!printingSurface) {
   392       printingSurface = mCachedPrintingSurface;
   393     }
   394 #endif
   395     nsRefPtr<nsRenderingContext> pContext = new nsRenderingContext();
   397     RefPtr<gfx::DrawTarget> dt =
   398       gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(printingSurface,
   399                                                              gfx::IntSize(mWidth, mHeight));
   401     pContext->Init(this, dt);
   402     pContext->ThebesContext()->SetFlag(gfxContext::FLAG_DISABLE_SNAPPING);
   403     pContext->Scale(mPrintingScale, mPrintingScale);
   405     return pContext.forget();
   406 }
   408 nsresult
   409 nsDeviceContext::GetDepth(uint32_t& aDepth)
   410 {
   411     if (mDepth == 0) {
   412         nsCOMPtr<nsIScreen> primaryScreen;
   413         mScreenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
   414         primaryScreen->GetColorDepth(reinterpret_cast<int32_t *>(&mDepth));
   415     }
   417     aDepth = mDepth;
   418     return NS_OK;
   419 }
   421 nsresult
   422 nsDeviceContext::GetDeviceSurfaceDimensions(nscoord &aWidth, nscoord &aHeight)
   423 {
   424     if (mPrintingSurface) {
   425         // we have a printer device
   426         aWidth = mWidth;
   427         aHeight = mHeight;
   428     } else {
   429         nsRect area;
   430         ComputeFullAreaUsingScreen(&area);
   431         aWidth = area.width;
   432         aHeight = area.height;
   433     }
   435     return NS_OK;
   436 }
   438 nsresult
   439 nsDeviceContext::GetRect(nsRect &aRect)
   440 {
   441     if (mPrintingSurface) {
   442         // we have a printer device
   443         aRect.x = 0;
   444         aRect.y = 0;
   445         aRect.width = mWidth;
   446         aRect.height = mHeight;
   447     } else
   448         ComputeFullAreaUsingScreen ( &aRect );
   450     return NS_OK;
   451 }
   453 nsresult
   454 nsDeviceContext::GetClientRect(nsRect &aRect)
   455 {
   456     if (mPrintingSurface) {
   457         // we have a printer device
   458         aRect.x = 0;
   459         aRect.y = 0;
   460         aRect.width = mWidth;
   461         aRect.height = mHeight;
   462     }
   463     else
   464         ComputeClientRectUsingScreen(&aRect);
   466     return NS_OK;
   467 }
   469 nsresult
   470 nsDeviceContext::InitForPrinting(nsIDeviceContextSpec *aDevice)
   471 {
   472     NS_ENSURE_ARG_POINTER(aDevice);
   474     mDeviceContextSpec = aDevice;
   476     nsresult rv = aDevice->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface));
   477     if (NS_FAILED(rv))
   478         return NS_ERROR_FAILURE;
   480     Init(nullptr);
   482     CalcPrintingSize();
   484     return NS_OK;
   485 }
   487 nsresult
   488 nsDeviceContext::BeginDocument(const nsAString& aTitle,
   489                                char16_t*       aPrintToFileName,
   490                                int32_t          aStartPage,
   491                                int32_t          aEndPage)
   492 {
   493     static const char16_t kEmpty[] = { '\0' };
   494     nsresult rv;
   496     rv = mPrintingSurface->BeginPrinting(aTitle,
   497                                          nsDependentString(aPrintToFileName ? aPrintToFileName : kEmpty));
   499     if (NS_SUCCEEDED(rv) && mDeviceContextSpec)
   500         rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName, aStartPage, aEndPage);
   502     return rv;
   503 }
   506 nsresult
   507 nsDeviceContext::EndDocument(void)
   508 {
   509     nsresult rv = NS_OK;
   511     if (mPrintingSurface) {
   512         rv = mPrintingSurface->EndPrinting();
   513         if (NS_SUCCEEDED(rv))
   514             mPrintingSurface->Finish();
   515     }
   517     if (mDeviceContextSpec)
   518         mDeviceContextSpec->EndDocument();
   520     return rv;
   521 }
   524 nsresult
   525 nsDeviceContext::AbortDocument(void)
   526 {
   527     nsresult rv = mPrintingSurface->AbortPrinting();
   529     if (mDeviceContextSpec)
   530         mDeviceContextSpec->EndDocument();
   532     return rv;
   533 }
   536 nsresult
   537 nsDeviceContext::BeginPage(void)
   538 {
   539     nsresult rv = NS_OK;
   541     if (mDeviceContextSpec)
   542         rv = mDeviceContextSpec->BeginPage();
   544     if (NS_FAILED(rv)) return rv;
   546 #ifdef XP_MACOSX
   547     // We need to get a new surface for each page on the Mac, as the
   548     // CGContextRefs are only good for one page.
   549     mDeviceContextSpec->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface));
   550 #endif
   552     rv = mPrintingSurface->BeginPage();
   554     return rv;
   555 }
   557 nsresult
   558 nsDeviceContext::EndPage(void)
   559 {
   560     nsresult rv = mPrintingSurface->EndPage();
   562 #ifdef XP_MACOSX
   563     // We need to release the CGContextRef in the surface here, plus it's
   564     // not something you would want anyway, as these CGContextRefs are only
   565     // good for one page.  But we need to keep a cached reference to it, since
   566     // CreateRenderingContext() may try to access it when mPrintingSurface
   567     // would normally be null.  See bug 665218.  If we just stop nulling out
   568     // mPrintingSurface here (and thereby make that our cached copy), we'll
   569     // break all our null checks on mPrintingSurface.  See bug 684622.
   570     mCachedPrintingSurface = mPrintingSurface;
   571     mPrintingSurface = nullptr;
   572 #endif
   574     if (mDeviceContextSpec)
   575         mDeviceContextSpec->EndPage();
   577     return rv;
   578 }
   580 void
   581 nsDeviceContext::ComputeClientRectUsingScreen(nsRect* outRect)
   582 {
   583     // we always need to recompute the clientRect
   584     // because the window may have moved onto a different screen. In the single
   585     // monitor case, we only need to do the computation if we haven't done it
   586     // once already, and remember that we have because we're assured it won't change.
   587     nsCOMPtr<nsIScreen> screen;
   588     FindScreen (getter_AddRefs(screen));
   589     if (screen) {
   590         int32_t x, y, width, height;
   591         screen->GetAvailRect(&x, &y, &width, &height);
   593         // convert to device units
   594         outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
   595         outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
   596         outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
   597         outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
   598     }
   599 }
   601 void
   602 nsDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect)
   603 {
   604     // if we have more than one screen, we always need to recompute the clientRect
   605     // because the window may have moved onto a different screen. In the single
   606     // monitor case, we only need to do the computation if we haven't done it
   607     // once already, and remember that we have because we're assured it won't change.
   608     nsCOMPtr<nsIScreen> screen;
   609     FindScreen ( getter_AddRefs(screen) );
   610     if ( screen ) {
   611         int32_t x, y, width, height;
   612         screen->GetRect ( &x, &y, &width, &height );
   614         // convert to device units
   615         outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
   616         outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
   617         outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
   618         outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
   620         mWidth = outRect->width;
   621         mHeight = outRect->height;
   622     }
   623 }
   625 //
   626 // FindScreen
   627 //
   628 // Determines which screen intersects the largest area of the given surface.
   629 //
   630 void
   631 nsDeviceContext::FindScreen(nsIScreen** outScreen)
   632 {
   633     if (mWidget && mWidget->GetNativeData(NS_NATIVE_WINDOW))
   634         mScreenManager->ScreenForNativeWidget(mWidget->GetNativeData(NS_NATIVE_WINDOW),
   635                                               outScreen);
   636     else
   637         mScreenManager->GetPrimaryScreen(outScreen);
   638 }
   640 void
   641 nsDeviceContext::CalcPrintingSize()
   642 {
   643     if (!mPrintingSurface)
   644         return;
   646     bool inPoints = true;
   648     gfxSize size(0, 0);
   649     switch (mPrintingSurface->GetType()) {
   650     case gfxSurfaceType::Image:
   651         inPoints = false;
   652         size = reinterpret_cast<gfxImageSurface*>(mPrintingSurface.get())->GetSize();
   653         break;
   655 #if defined(MOZ_PDF_PRINTING)
   656     case gfxSurfaceType::PDF:
   657         inPoints = true;
   658         size = reinterpret_cast<gfxPDFSurface*>(mPrintingSurface.get())->GetSize();
   659         break;
   660 #endif
   662 #ifdef MOZ_WIDGET_GTK
   663     case gfxSurfaceType::PS:
   664         inPoints = true;
   665         size = reinterpret_cast<gfxPSSurface*>(mPrintingSurface.get())->GetSize();
   666         break;
   667 #endif
   669 #ifdef XP_MACOSX
   670     case gfxSurfaceType::Quartz:
   671         inPoints = true; // this is really only true when we're printing
   672         size = reinterpret_cast<gfxQuartzSurface*>(mPrintingSurface.get())->GetSize();
   673         break;
   674 #endif
   676 #ifdef XP_WIN
   677     case gfxSurfaceType::Win32:
   678     case gfxSurfaceType::Win32Printing:
   679         {
   680             inPoints = false;
   681             HDC dc = reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
   682             if (!dc)
   683                 dc = GetDC((HWND)mWidget->GetNativeData(NS_NATIVE_WIDGET));
   684             size.width = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, HORZRES)/mPrintingScale, AppUnitsPerDevPixel());
   685             size.height = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, VERTRES)/mPrintingScale, AppUnitsPerDevPixel());
   686             mDepth = (uint32_t)::GetDeviceCaps(dc, BITSPIXEL);
   687             if (dc != reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC())
   688                 ReleaseDC((HWND)mWidget->GetNativeData(NS_NATIVE_WIDGET), dc);
   689             break;
   690         }
   691 #endif
   693     default:
   694         NS_ERROR("trying to print to unknown surface type");
   695     }
   697     if (inPoints) {
   698         // For printing, CSS inches and physical inches are identical
   699         // so it doesn't matter which we use here
   700         mWidth = NSToCoordRound(float(size.width) * AppUnitsPerPhysicalInch() / 72);
   701         mHeight = NSToCoordRound(float(size.height) * AppUnitsPerPhysicalInch() / 72);
   702     } else {
   703         mWidth = NSToIntRound(size.width);
   704         mHeight = NSToIntRound(size.height);
   705     }
   706 }
   708 bool nsDeviceContext::CheckDPIChange() {
   709     int32_t oldDevPixels = mAppUnitsPerDevNotScaledPixel;
   710     int32_t oldInches = mAppUnitsPerPhysicalInch;
   712     SetDPI();
   714     return oldDevPixels != mAppUnitsPerDevNotScaledPixel ||
   715         oldInches != mAppUnitsPerPhysicalInch;
   716 }
   718 bool
   719 nsDeviceContext::SetPixelScale(float aScale)
   720 {
   721     if (aScale <= 0) {
   722         NS_NOTREACHED("Invalid pixel scale value");
   723         return false;
   724     }
   725     int32_t oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
   726     mPixelScale = aScale;
   727     UpdateScaledAppUnits();
   728     return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel;
   729 }
   731 void
   732 nsDeviceContext::UpdateScaledAppUnits()
   733 {
   734     mAppUnitsPerDevPixel =
   735         std::max(1, NSToIntRound(float(mAppUnitsPerDevNotScaledPixel) / mPixelScale));
   736     // adjust mPixelScale to reflect appunit rounding
   737     mPixelScale = float(mAppUnitsPerDevNotScaledPixel) / mAppUnitsPerDevPixel;
   738 }

mercurial