Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / gfx / src / thebes / nsThebesDeviceContext.cpp
blob19803875ba44bb0adef41a9c19621f9798f3b980
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is thebes gfx
17 * The Initial Developer of the Original Code is
18 * mozilla.org.
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Vladimir Vukicevic <vladimir@pobox.com>
24 * Stuart Parmenter <pavlov@pavlov.net>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsIServiceManager.h"
41 #include "nsIPref.h"
42 #include "nsCRT.h"
44 #include "nsThebesDeviceContext.h"
45 #include "nsThebesRenderingContext.h"
47 #include "nsIView.h"
48 #include "nsILookAndFeel.h"
50 #ifdef MOZ_ENABLE_GTK2
51 // for getenv
52 #include <cstdlib>
53 // for round
54 #include <cmath>
56 #include <gtk/gtk.h>
57 #include <gdk/gdk.h>
59 #include "nsFont.h"
61 #include <pango/pango.h>
62 #ifdef MOZ_X11
63 #include <gdk/gdkx.h>
64 #include <pango/pangox.h>
65 #endif /* MOZ_X11 */
66 #include <pango/pango-fontmap.h>
67 #endif /* GTK2 */
69 #include "gfxImageSurface.h"
71 #ifdef MOZ_ENABLE_GTK2
72 #include "nsSystemFontsGTK2.h"
73 #include "gfxPDFSurface.h"
74 #include "gfxPSSurface.h"
75 static nsSystemFontsGTK2 *gSystemFonts = nsnull;
76 #elif XP_WIN
77 #include "nsSystemFontsWin.h"
78 #include "gfxWindowsSurface.h"
79 #include "gfxPDFSurface.h"
80 static nsSystemFontsWin *gSystemFonts = nsnull;
81 #ifndef WINCE
82 #include <usp10.h>
83 #endif
84 #elif defined(XP_OS2)
85 #include "nsSystemFontsOS2.h"
86 #include "gfxPDFSurface.h"
87 static nsSystemFontsOS2 *gSystemFonts = nsnull;
88 #elif defined(XP_BEOS)
89 #include "nsSystemFontsBeOS.h"
90 static nsSystemFontsBeOS *gSystemFonts = nsnull;
91 #elif XP_MACOSX
92 #include "nsSystemFontsMac.h"
93 #include "gfxQuartzSurface.h"
94 #include "gfxImageSurface.h"
95 static nsSystemFontsMac *gSystemFonts = nsnull;
96 #elif defined(MOZ_WIDGET_QT)
97 #include "nsSystemFontsQt.h"
98 static nsSystemFontsQt *gSystemFonts = nsnull;
99 #else
100 #error Need to declare gSystemFonts!
101 #endif
103 #if defined(MOZ_ENABLE_GTK2) && defined(MOZ_X11)
104 extern "C" {
105 static int x11_error_handler (Display *dpy, XErrorEvent *err) {
106 NS_ASSERTION(PR_FALSE, "X Error");
107 return 0;
110 #endif
112 #ifdef PR_LOGGING
113 PRLogModuleInfo* gThebesGFXLog = nsnull;
114 #endif
116 NS_IMPL_ISUPPORTS_INHERITED0(nsThebesDeviceContext, DeviceContextImpl)
118 nsThebesDeviceContext::nsThebesDeviceContext()
120 #ifdef PR_LOGGING
121 if (!gThebesGFXLog)
122 gThebesGFXLog = PR_NewLogModule("thebesGfx");
123 #endif
125 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("#### Creating DeviceContext %p\n", this));
127 mDepth = 0;
128 mWidth = 0;
129 mHeight = 0;
130 mPrintingScale = 1.0f;
132 mWidgetSurfaceCache.Init();
134 #if defined(XP_WIN) && !defined(WINCE)
135 SCRIPT_DIGITSUBSTITUTE sds;
136 ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &sds);
137 #endif
140 nsThebesDeviceContext::~nsThebesDeviceContext()
144 /* static */ void
145 nsThebesDeviceContext::Shutdown()
147 delete gSystemFonts;
148 gSystemFonts = nsnull;
151 PRBool
152 nsThebesDeviceContext::IsPrinterSurface()
154 return(mPrintingSurface != NULL);
157 nsresult
158 nsThebesDeviceContext::SetDPI()
160 PRInt32 dpi = -1;
161 PRBool dotsArePixels = PR_TRUE;
163 // PostScript, PDF and Mac (when printing) all use 72 dpi
164 if (mPrintingSurface &&
165 (mPrintingSurface->GetType() == gfxASurface::SurfaceTypePDF ||
166 mPrintingSurface->GetType() == gfxASurface::SurfaceTypePS ||
167 mPrintingSurface->GetType() == gfxASurface::SurfaceTypeQuartz)) {
168 dpi = 72;
169 dotsArePixels = PR_FALSE;
170 } else {
171 // Get prefVal the value of the preference
172 // "layout.css.dpi"
173 // or -1 if we can't get it.
174 // If it's negative, use the default DPI setting
175 // If it's 0, force the use of the OS's set resolution. Set this if your
176 // X server has the correct DPI and it's less than 96dpi.
177 // If it's positive, we use it as the logical resolution
178 nsresult rv;
179 PRInt32 prefDPI;
180 nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID, &rv));
181 if (NS_SUCCEEDED(rv) && prefs) {
182 rv = prefs->GetIntPref("layout.css.dpi", &prefDPI);
183 if (NS_FAILED(rv)) {
184 prefDPI = -1;
188 #if defined(MOZ_ENABLE_GTK2)
189 GdkScreen *screen = gdk_screen_get_default();
190 gtk_settings_get_for_screen(screen); // Make sure init is run so we have a resolution
191 PRInt32 OSVal = PRInt32(round(gdk_screen_get_resolution(screen)));
193 if (prefDPI == 0) // Force the use of the OS dpi
194 dpi = OSVal;
195 else // Otherwise, the minimum dpi is 96dpi
196 dpi = PR_MAX(OSVal, 96);
198 #elif defined(XP_WIN)
199 // XXX we should really look at the widget if !dc but it is currently always null
200 HDC dc = GetPrintHDC();
201 if (dc) {
202 PRInt32 OSVal = GetDeviceCaps(dc, LOGPIXELSY);
204 dpi = 144;
205 mPrintingScale = float(OSVal)/dpi;
206 dotsArePixels = PR_FALSE;
207 } else {
208 dc = GetDC((HWND)nsnull);
210 PRInt32 OSVal = GetDeviceCaps(dc, LOGPIXELSY);
212 ReleaseDC((HWND)nsnull, dc);
214 if (OSVal != 0)
215 dpi = OSVal;
218 #elif defined(XP_OS2)
219 // get a printer DC if available, otherwise create a new (memory) DC
220 HDC dc = GetPrintHDC();
221 PRBool doCloseDC = PR_FALSE;
222 if (dc <= 0) { // test for NULLHANDLE/DEV_ERROR or HDC_ERROR
223 // create DC compatible with the screen
224 dc = DevOpenDC((HAB)1, OD_MEMORY,"*",0L, NULL, NULLHANDLE);
225 doCloseDC = PR_TRUE;
227 if (dc > 0) {
228 // we do have a DC and we can query the DPI setting from it
229 LONG lDPI;
230 if (DevQueryCaps(dc, CAPS_VERTICAL_FONT_RES, 1, &lDPI))
231 dpi = lDPI;
232 if (doCloseDC)
233 DevCloseDC(dc);
235 if (dpi < 0) // something didn't work before, fall back to hardcoded DPI value
236 dpi = 96;
237 #elif defined(XP_MACOSX)
239 // we probably want to actually get a real DPI here?
240 dpi = 96;
242 #elif defined(MOZ_WIDGET_QT)
243 // TODO: get real DPI here with Qt methods
244 dpi = 96;
245 #else
246 #error undefined platform dpi
247 #endif
249 if (prefDPI > 0 && !mPrintingSurface)
250 dpi = prefDPI;
253 NS_ASSERTION(dpi != -1, "no dpi set");
255 if (dotsArePixels) {
256 // First figure out the closest multiple of 96, which is the number of
257 // dev pixels per CSS pixel. Then, divide that into AppUnitsPerCSSPixel()
258 // to get the number of app units per dev pixel. The PR_MAXes are to
259 // make sure we don't end up dividing by zero.
260 PRUint32 roundedDPIScaleFactor = (dpi + 48)/96;
261 #ifdef MOZ_WIDGET_GTK2
262 // be more conservative about activating scaling on GTK2, since the dpi
263 // information is more likely to be wrong
264 roundedDPIScaleFactor = dpi/96;
265 #endif
266 mAppUnitsPerDevNotScaledPixel =
267 PR_MAX(1, AppUnitsPerCSSPixel() / PR_MAX(1, roundedDPIScaleFactor));
268 } else {
269 /* set mAppUnitsPerDevPixel so we're using exactly 72 dpi, even
270 * though that means we have a non-integer number of device "pixels"
271 * per CSS pixel
273 mAppUnitsPerDevNotScaledPixel = (AppUnitsPerCSSPixel() * 96) / dpi;
276 mAppUnitsPerInch = NSIntPixelsToAppUnits(dpi, mAppUnitsPerDevNotScaledPixel);
278 UpdateScaledAppUnits();
280 return NS_OK;
283 NS_IMETHODIMP
284 nsThebesDeviceContext::Init(nsNativeWidget aWidget)
286 mWidget = aWidget;
288 SetDPI();
291 #if defined(MOZ_ENABLE_GTK2) && defined(MOZ_X11)
292 if (getenv ("MOZ_X_SYNC")) {
293 PR_LOG (gThebesGFXLog, PR_LOG_DEBUG, ("+++ Enabling XSynchronize\n"));
294 XSynchronize (gdk_x11_get_default_xdisplay(), True);
295 XSetErrorHandler(x11_error_handler);
298 #endif
300 mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
302 return NS_OK;
305 NS_IMETHODIMP
306 nsThebesDeviceContext::CreateRenderingContext(nsIView *aView,
307 nsIRenderingContext *&aContext)
309 // This is currently only called by the caret code
310 NS_ENSURE_ARG_POINTER(aView);
311 NS_PRECONDITION(aView->HasWidget(), "View has no widget!");
313 nsCOMPtr<nsIWidget> widget;
314 widget = aView->GetWidget();
316 return CreateRenderingContext(widget, aContext);
319 NS_IMETHODIMP
320 nsThebesDeviceContext::CreateRenderingContext(nsIWidget *aWidget,
321 nsIRenderingContext *&aContext)
323 nsresult rv;
325 aContext = nsnull;
326 nsCOMPtr<nsIRenderingContext> pContext;
327 rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
328 if (NS_SUCCEEDED(rv)) {
329 nsRefPtr<gfxASurface> surface(aWidget->GetThebesSurface());
330 if (surface)
331 rv = pContext->Init(this, surface);
332 else
333 rv = NS_ERROR_FAILURE;
335 if (NS_SUCCEEDED(rv)) {
336 aContext = pContext;
337 NS_ADDREF(aContext);
341 return rv;
344 NS_IMETHODIMP
345 nsThebesDeviceContext::CreateRenderingContext(nsIRenderingContext *&aContext)
347 nsresult rv = NS_OK;
349 aContext = nsnull;
350 nsCOMPtr<nsIRenderingContext> pContext;
351 rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
352 if (NS_SUCCEEDED(rv)) {
353 if (mPrintingSurface)
354 rv = pContext->Init(this, mPrintingSurface);
355 else
356 rv = NS_ERROR_FAILURE;
358 if (NS_SUCCEEDED(rv)) {
359 pContext->Scale(mPrintingScale, mPrintingScale);
360 aContext = pContext;
361 NS_ADDREF(aContext);
365 return rv;
368 NS_IMETHODIMP
369 nsThebesDeviceContext::CreateRenderingContextInstance(nsIRenderingContext *&aContext)
371 nsCOMPtr<nsIRenderingContext> renderingContext = new nsThebesRenderingContext();
372 if (!renderingContext)
373 return NS_ERROR_OUT_OF_MEMORY;
375 aContext = renderingContext;
376 NS_ADDREF(aContext);
378 return NS_OK;
381 NS_IMETHODIMP
382 nsThebesDeviceContext::SupportsNativeWidgets(PRBool &aSupportsWidgets)
384 aSupportsWidgets = PR_TRUE;
385 return NS_OK;
388 NS_IMETHODIMP
389 nsThebesDeviceContext::ClearCachedSystemFonts()
391 //clear our cache of stored system fonts
392 if (gSystemFonts) {
393 delete gSystemFonts;
394 gSystemFonts = nsnull;
396 return NS_OK;
399 NS_IMETHODIMP
400 nsThebesDeviceContext::GetSystemFont(nsSystemFontID aID, nsFont *aFont) const
402 if (!gSystemFonts) {
403 #ifdef MOZ_ENABLE_GTK2
404 gSystemFonts = new nsSystemFontsGTK2();
405 #elif XP_WIN
406 gSystemFonts = new nsSystemFontsWin();
407 #elif XP_OS2
408 gSystemFonts = new nsSystemFontsOS2();
409 #elif defined(XP_BEOS)
410 gSystemFonts = new nsSystemFontsBeOS();
411 #elif XP_MACOSX
412 gSystemFonts = new nsSystemFontsMac();
413 #elif defined(MOZ_WIDGET_QT)
414 gSystemFonts = new nsSystemFontsQt();
415 #else
416 #error Need to know how to create gSystemFonts, fix me!
417 #endif
420 nsString fontName;
421 gfxFontStyle fontStyle;
422 nsresult rv = gSystemFonts->GetSystemFont(aID, &fontName, &fontStyle);
423 NS_ENSURE_SUCCESS(rv, rv);
425 aFont->name = fontName;
426 aFont->style = fontStyle.style;
427 aFont->systemFont = fontStyle.systemFont;
428 aFont->variant = NS_FONT_VARIANT_NORMAL;
429 aFont->familyNameQuirks = fontStyle.familyNameQuirks;
430 aFont->weight = fontStyle.weight;
431 aFont->decorations = NS_FONT_DECORATION_NONE;
432 aFont->size = NSFloatPixelsToAppUnits(fontStyle.size, UnscaledAppUnitsPerDevPixel());
433 //aFont->langGroup = fontStyle.langGroup;
434 aFont->sizeAdjust = fontStyle.sizeAdjust;
436 return rv;
439 NS_IMETHODIMP
440 nsThebesDeviceContext::CheckFontExistence(const nsString& aFaceName)
442 return NS_OK;
445 NS_IMETHODIMP
446 nsThebesDeviceContext::GetDepth(PRUint32& aDepth)
448 nsCOMPtr<nsIScreen> primaryScreen;
449 if (mDepth == 0) {
450 mScreenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
451 primaryScreen->GetColorDepth(reinterpret_cast<PRInt32 *>(&mDepth));
454 aDepth = mDepth;
455 return NS_OK;
458 NS_IMETHODIMP
459 nsThebesDeviceContext::GetPaletteInfo(nsPaletteInfo& aPaletteInfo)
461 aPaletteInfo.isPaletteDevice = PR_FALSE;
462 aPaletteInfo.sizePalette = 0;
463 aPaletteInfo.numReserved = 0;
464 aPaletteInfo.palette = nsnull;
465 return NS_OK;
469 NS_IMETHODIMP
470 nsThebesDeviceContext::ConvertPixel(nscolor aColor, PRUint32 & aPixel)
472 aPixel = aColor;
473 return NS_OK;
476 NS_IMETHODIMP
477 nsThebesDeviceContext::GetDeviceSurfaceDimensions(nscoord &aWidth, nscoord &aHeight)
479 if (mPrintingSurface) {
480 // we have a printer device
481 aWidth = mWidth;
482 aHeight = mHeight;
483 } else {
484 nsRect area;
485 ComputeFullAreaUsingScreen(&area);
486 aWidth = area.width;
487 aHeight = area.height;
490 return NS_OK;
493 NS_IMETHODIMP
494 nsThebesDeviceContext::GetRect(nsRect &aRect)
496 if (mPrintingSurface) {
497 // we have a printer device
498 aRect.x = 0;
499 aRect.y = 0;
500 aRect.width = mWidth;
501 aRect.height = mHeight;
502 } else
503 ComputeFullAreaUsingScreen ( &aRect );
505 return NS_OK;
508 NS_IMETHODIMP
509 nsThebesDeviceContext::GetClientRect(nsRect &aRect)
511 if (mPrintingSurface) {
512 // we have a printer device
513 aRect.x = 0;
514 aRect.y = 0;
515 aRect.width = mWidth;
516 aRect.height = mHeight;
518 else
519 ComputeClientRectUsingScreen(&aRect);
521 return NS_OK;
524 NS_IMETHODIMP
525 nsThebesDeviceContext::PrepareNativeWidget(nsIWidget* aWidget, void** aOut)
527 *aOut = nsnull;
528 return NS_OK;
533 * below methods are for printing
535 NS_IMETHODIMP
536 nsThebesDeviceContext::InitForPrinting(nsIDeviceContextSpec *aDevice)
538 NS_ENSURE_ARG_POINTER(aDevice);
540 mDeviceContextSpec = aDevice;
542 nsresult rv = aDevice->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface));
543 if (NS_FAILED(rv))
544 return NS_ERROR_FAILURE;
546 Init(nsnull);
548 CalcPrintingSize();
550 return NS_OK;
554 NS_IMETHODIMP
555 nsThebesDeviceContext::PrepareDocument(PRUnichar * aTitle,
556 PRUnichar* aPrintToFileName)
558 return NS_OK;
562 NS_IMETHODIMP
563 nsThebesDeviceContext::BeginDocument(PRUnichar* aTitle,
564 PRUnichar* aPrintToFileName,
565 PRInt32 aStartPage,
566 PRInt32 aEndPage)
568 static const PRUnichar kEmpty[] = { '\0' };
569 nsresult rv;
571 rv = mPrintingSurface->BeginPrinting(nsDependentString(aTitle ? aTitle : kEmpty),
572 nsDependentString(aPrintToFileName ? aPrintToFileName : kEmpty));
574 if (NS_SUCCEEDED(rv) && mDeviceContextSpec)
575 rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName, aStartPage, aEndPage);
577 return rv;
581 NS_IMETHODIMP
582 nsThebesDeviceContext::EndDocument(void)
584 nsresult rv = NS_OK;
586 if (mPrintingSurface) {
587 rv = mPrintingSurface->EndPrinting();
588 if (NS_SUCCEEDED(rv))
589 mPrintingSurface->Finish();
592 if (mDeviceContextSpec)
593 mDeviceContextSpec->EndDocument();
595 return rv;
599 NS_IMETHODIMP
600 nsThebesDeviceContext::AbortDocument(void)
602 nsresult rv = mPrintingSurface->AbortPrinting();
604 if (mDeviceContextSpec)
605 mDeviceContextSpec->EndDocument();
607 return rv;
611 NS_IMETHODIMP
612 nsThebesDeviceContext::BeginPage(void)
614 nsresult rv = NS_OK;
616 if (mDeviceContextSpec)
617 rv = mDeviceContextSpec->BeginPage();
619 if (NS_FAILED(rv)) return rv;
621 /* We need to get a new surface for each page on the Mac */
622 #ifdef XP_MACOSX
623 mDeviceContextSpec->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface));
624 #endif
625 rv = mPrintingSurface->BeginPage();
627 return rv;
630 NS_IMETHODIMP
631 nsThebesDeviceContext::EndPage(void)
633 nsresult rv = mPrintingSurface->EndPage();
635 /* We need to release the CGContextRef in the surface here, plus it's
636 not something you would want anyway, as these CGContextRefs are only good
637 for one page. */
638 #ifdef XP_MACOSX
639 mPrintingSurface = nsnull;
640 #endif
642 if (mDeviceContextSpec)
643 mDeviceContextSpec->EndPage();
645 return rv;
648 /** End printing methods **/
650 void
651 nsThebesDeviceContext::ComputeClientRectUsingScreen(nsRect* outRect)
653 // we always need to recompute the clientRect
654 // because the window may have moved onto a different screen. In the single
655 // monitor case, we only need to do the computation if we haven't done it
656 // once already, and remember that we have because we're assured it won't change.
657 nsCOMPtr<nsIScreen> screen;
658 FindScreen (getter_AddRefs(screen));
659 if (screen) {
660 PRInt32 x, y, width, height;
661 screen->GetAvailRect(&x, &y, &width, &height);
663 // convert to device units
664 outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
665 outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
666 outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
667 outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
671 void
672 nsThebesDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect)
674 // if we have more than one screen, we always need to recompute the clientRect
675 // because the window may have moved onto a different screen. In the single
676 // monitor case, we only need to do the computation if we haven't done it
677 // once already, and remember that we have because we're assured it won't change.
678 nsCOMPtr<nsIScreen> screen;
679 FindScreen ( getter_AddRefs(screen) );
680 if ( screen ) {
681 PRInt32 x, y, width, height;
682 screen->GetRect ( &x, &y, &width, &height );
684 // convert to device units
685 outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
686 outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
687 outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
688 outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
690 mWidth = outRect->width;
691 mHeight = outRect->height;
698 // FindScreen
700 // Determines which screen intersects the largest area of the given surface.
702 void
703 nsThebesDeviceContext::FindScreen(nsIScreen** outScreen)
705 if (mWidget)
706 mScreenManager->ScreenForNativeWidget(mWidget, outScreen);
707 else
708 mScreenManager->GetPrimaryScreen(outScreen);
711 void
712 nsThebesDeviceContext::CalcPrintingSize()
714 if (!mPrintingSurface)
715 return;
717 PRBool inPoints = PR_TRUE;
719 gfxSize size;
720 switch (mPrintingSurface->GetType()) {
721 case gfxASurface::SurfaceTypeImage:
722 inPoints = PR_FALSE;
723 size = reinterpret_cast<gfxImageSurface*>(mPrintingSurface.get())->GetSize();
724 break;
726 #if defined(MOZ_ENABLE_GTK2) || defined(XP_WIN) || defined(XP_OS2)
727 case gfxASurface::SurfaceTypePDF:
728 inPoints = PR_TRUE;
729 size = reinterpret_cast<gfxPDFSurface*>(mPrintingSurface.get())->GetSize();
730 break;
731 #endif
733 #ifdef MOZ_ENABLE_GTK2
734 case gfxASurface::SurfaceTypePS:
735 inPoints = PR_TRUE;
736 size = reinterpret_cast<gfxPSSurface*>(mPrintingSurface.get())->GetSize();
737 break;
738 #endif
740 #ifdef XP_MACOSX
741 case gfxASurface::SurfaceTypeQuartz:
742 inPoints = PR_TRUE; // this is really only true when we're printing
743 size = reinterpret_cast<gfxQuartzSurface*>(mPrintingSurface.get())->GetSize();
744 break;
745 #endif
747 #ifdef XP_WIN
748 case gfxASurface::SurfaceTypeWin32:
749 case gfxASurface::SurfaceTypeWin32Printing:
751 inPoints = PR_FALSE;
752 HDC dc = GetPrintHDC();
753 if (!dc)
754 dc = GetDC((HWND)mWidget);
755 size.width = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, HORZRES)/mPrintingScale, AppUnitsPerDevPixel());
756 size.height = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, VERTRES)/mPrintingScale, AppUnitsPerDevPixel());
757 mDepth = (PRUint32)::GetDeviceCaps(dc, BITSPIXEL);
758 if (dc != (HDC)GetPrintHDC())
759 ReleaseDC((HWND)mWidget, dc);
760 break;
762 #endif
764 #ifdef XP_OS2
765 case gfxASurface::SurfaceTypeOS2:
767 inPoints = PR_FALSE;
768 // we already set the size in the surface constructor we set for
769 // printing, so just get those values here
770 size = reinterpret_cast<gfxOS2Surface*>(mPrintingSurface.get())->GetSize();
771 // as they are in pixels we need to scale them to app units
772 size.width = NSFloatPixelsToAppUnits(size.width, AppUnitsPerDevPixel());
773 size.height = NSFloatPixelsToAppUnits(size.height, AppUnitsPerDevPixel());
774 // still need to get the depth from the device context
775 HDC dc = GetPrintHDC();
776 LONG value;
777 if (DevQueryCaps(dc, CAPS_COLOR_BITCOUNT, 1, &value))
778 mDepth = value;
779 else
780 mDepth = 8; // default to 8bpp, should be enough for printers
781 break;
783 #endif
784 default:
785 NS_ASSERTION(0, "trying to print to unknown surface type");
788 if (inPoints) {
789 mWidth = NSToCoordRound(float(size.width) * AppUnitsPerInch() / 72);
790 mHeight = NSToCoordRound(float(size.height) * AppUnitsPerInch() / 72);
791 } else {
792 mWidth = NSToIntRound(size.width);
793 mHeight = NSToIntRound(size.height);
797 PRBool nsThebesDeviceContext::CheckDPIChange() {
798 PRInt32 oldDevPixels = mAppUnitsPerDevNotScaledPixel;
799 PRInt32 oldInches = mAppUnitsPerInch;
801 SetDPI();
803 return oldDevPixels != mAppUnitsPerDevNotScaledPixel ||
804 oldInches != mAppUnitsPerInch;
807 PRBool
808 nsThebesDeviceContext::SetPixelScale(float aScale)
810 if (aScale <= 0) {
811 NS_NOTREACHED("Invalid pixel scale value");
812 return PR_FALSE;
814 PRInt32 oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
815 mPixelScale = aScale;
816 UpdateScaledAppUnits();
817 return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel;
820 void
821 nsThebesDeviceContext::UpdateScaledAppUnits()
823 mAppUnitsPerDevPixel = PR_MAX(1, PRInt32(float(mAppUnitsPerDevNotScaledPixel) / mPixelScale));
826 #if defined(XP_WIN) || defined(XP_OS2)
828 nsThebesDeviceContext::GetPrintHDC()
830 if (mPrintingSurface) {
831 switch (mPrintingSurface->GetType()) {
832 #ifdef XP_WIN
833 case gfxASurface::SurfaceTypeWin32:
834 case gfxASurface::SurfaceTypeWin32Printing:
835 return reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
836 #endif
838 #ifdef XP_OS2
839 case gfxASurface::SurfaceTypeOS2:
840 return GpiQueryDevice(reinterpret_cast<gfxOS2Surface*>(mPrintingSurface.get())->GetPS());
841 #endif
843 default:
844 NS_ASSERTION(0, "invalid surface type in GetPrintHDC");
845 break;
849 return nsnull;
851 #endif