Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr...
[wine-gecko.git] / gfx / src / thebes / nsThebesDeviceContext.cpp
blob33aab4d5aebf4686ac62fa16e15e594e9ae673c5
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 #include <usp10.h>
82 #elif defined(XP_OS2)
83 #include "nsSystemFontsOS2.h"
84 #include "gfxPDFSurface.h"
85 static nsSystemFontsOS2 *gSystemFonts = nsnull;
86 #elif defined(XP_BEOS)
87 #include "nsSystemFontsBeOS.h"
88 static nsSystemFontsBeOS *gSystemFonts = nsnull;
89 #elif XP_MACOSX
90 #include "nsSystemFontsMac.h"
91 #include "gfxQuartzSurface.h"
92 #include "gfxImageSurface.h"
93 static nsSystemFontsMac *gSystemFonts = nsnull;
94 #elif defined(MOZ_WIDGET_QT)
95 #include "nsSystemFontsQt.h"
96 static nsSystemFontsQt *gSystemFonts = nsnull;
97 #else
98 #error Need to declare gSystemFonts!
99 #endif
101 #if defined(MOZ_ENABLE_GTK2) && defined(MOZ_X11)
102 extern "C" {
103 static int x11_error_handler (Display *dpy, XErrorEvent *err) {
104 NS_ASSERTION(PR_FALSE, "X Error");
105 return 0;
108 #endif
110 #ifdef PR_LOGGING
111 PRLogModuleInfo* gThebesGFXLog = nsnull;
112 #endif
114 NS_IMPL_ISUPPORTS_INHERITED0(nsThebesDeviceContext, DeviceContextImpl)
116 nsThebesDeviceContext::nsThebesDeviceContext()
118 #ifdef PR_LOGGING
119 if (!gThebesGFXLog)
120 gThebesGFXLog = PR_NewLogModule("thebesGfx");
121 #endif
123 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("#### Creating DeviceContext %p\n", this));
125 mDepth = 0;
126 mWidth = 0;
127 mHeight = 0;
128 mPrintingScale = 1.0f;
130 mWidgetSurfaceCache.Init();
132 #ifdef XP_WIN
133 SCRIPT_DIGITSUBSTITUTE sds;
134 ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &sds);
135 #endif
138 nsThebesDeviceContext::~nsThebesDeviceContext()
142 /* static */ void
143 nsThebesDeviceContext::Shutdown()
145 delete gSystemFonts;
146 gSystemFonts = nsnull;
149 nsresult
150 nsThebesDeviceContext::SetDPI()
152 PRInt32 dpi = -1;
153 PRBool dotsArePixels = PR_TRUE;
155 // PostScript, PDF and Mac (when printing) all use 72 dpi
156 if (mPrintingSurface &&
157 (mPrintingSurface->GetType() == gfxASurface::SurfaceTypePDF ||
158 mPrintingSurface->GetType() == gfxASurface::SurfaceTypePS ||
159 mPrintingSurface->GetType() == gfxASurface::SurfaceTypeQuartz)) {
160 dpi = 72;
161 dotsArePixels = PR_FALSE;
162 } else {
163 // Get prefVal the value of the preference
164 // "layout.css.dpi"
165 // or -1 if we can't get it.
166 // If it's negative, use the default DPI setting
167 // If it's 0, force the use of the OS's set resolution. Set this if your
168 // X server has the correct DPI and it's less than 96dpi.
169 // If it's positive, we use it as the logical resolution
170 nsresult rv;
171 PRInt32 prefDPI;
172 nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID, &rv));
173 if (NS_SUCCEEDED(rv) && prefs) {
174 rv = prefs->GetIntPref("layout.css.dpi", &prefDPI);
175 if (NS_FAILED(rv)) {
176 prefDPI = -1;
180 #if defined(MOZ_ENABLE_GTK2)
181 GdkScreen *screen = gdk_screen_get_default();
182 gtk_settings_get_for_screen(screen); // Make sure init is run so we have a resolution
183 PRInt32 OSVal = PRInt32(round(gdk_screen_get_resolution(screen)));
185 if (prefDPI == 0) // Force the use of the OS dpi
186 dpi = OSVal;
187 else // Otherwise, the minimum dpi is 96dpi
188 dpi = PR_MAX(OSVal, 96);
190 #elif defined(XP_WIN)
191 // XXX we should really look at the widget if !dc but it is currently always null
192 HDC dc = GetPrintHDC();
193 if (dc) {
194 PRInt32 OSVal = GetDeviceCaps(dc, LOGPIXELSY);
196 dpi = 144;
197 mPrintingScale = float(OSVal)/dpi;
198 dotsArePixels = PR_FALSE;
199 } else {
200 dc = GetDC((HWND)nsnull);
202 PRInt32 OSVal = GetDeviceCaps(dc, LOGPIXELSY);
204 ReleaseDC((HWND)nsnull, dc);
206 if (OSVal != 0)
207 dpi = OSVal;
210 #elif defined(XP_OS2)
211 // get a printer DC if available, otherwise create a new (memory) DC
212 HDC dc = GetPrintHDC();
213 PRBool doCloseDC = PR_FALSE;
214 if (dc <= 0) { // test for NULLHANDLE/DEV_ERROR or HDC_ERROR
215 // create DC compatible with the screen
216 dc = DevOpenDC((HAB)1, OD_MEMORY,"*",0L, NULL, NULLHANDLE);
217 doCloseDC = PR_TRUE;
219 if (dc > 0) {
220 // we do have a DC and we can query the DPI setting from it
221 LONG lDPI;
222 if (DevQueryCaps(dc, CAPS_VERTICAL_FONT_RES, 1, &lDPI))
223 dpi = lDPI;
224 if (doCloseDC)
225 DevCloseDC(dc);
227 if (dpi < 0) // something didn't work before, fall back to hardcoded DPI value
228 dpi = 96;
229 #elif defined(XP_MACOSX)
231 // we probably want to actually get a real DPI here?
232 dpi = 96;
234 #elif defined(MOZ_WIDGET_QT)
235 // TODO: get real DPI here with Qt methods
236 dpi = 96;
237 #else
238 #error undefined platform dpi
239 #endif
241 if (prefDPI > 0 && !mPrintingSurface)
242 dpi = prefDPI;
245 NS_ASSERTION(dpi != -1, "no dpi set");
247 if (dotsArePixels) {
248 // First figure out the closest multiple of 96, which is the number of
249 // dev pixels per CSS pixel. Then, divide that into AppUnitsPerCSSPixel()
250 // to get the number of app units per dev pixel. The PR_MAXes are to
251 // make sure we don't end up dividing by zero.
252 PRUint32 roundedDPIScaleFactor = (dpi + 48)/96;
253 #ifdef MOZ_WIDGET_GTK2
254 // be more conservative about activating scaling on GTK2, since the dpi
255 // information is more likely to be wrong
256 roundedDPIScaleFactor = dpi/96;
257 #endif
258 mAppUnitsPerDevNotScaledPixel =
259 PR_MAX(1, AppUnitsPerCSSPixel() / PR_MAX(1, roundedDPIScaleFactor));
260 } else {
261 /* set mAppUnitsPerDevPixel so we're using exactly 72 dpi, even
262 * though that means we have a non-integer number of device "pixels"
263 * per CSS pixel
265 mAppUnitsPerDevNotScaledPixel = (AppUnitsPerCSSPixel() * 96) / dpi;
268 mAppUnitsPerInch = NSIntPixelsToAppUnits(dpi, mAppUnitsPerDevNotScaledPixel);
270 UpdateScaledAppUnits();
272 return NS_OK;
275 NS_IMETHODIMP
276 nsThebesDeviceContext::Init(nsNativeWidget aWidget)
278 mWidget = aWidget;
280 SetDPI();
283 #if defined(MOZ_ENABLE_GTK2) && defined(MOZ_X11)
284 if (getenv ("MOZ_X_SYNC")) {
285 PR_LOG (gThebesGFXLog, PR_LOG_DEBUG, ("+++ Enabling XSynchronize\n"));
286 XSynchronize (gdk_x11_get_default_xdisplay(), True);
287 XSetErrorHandler(x11_error_handler);
290 #endif
292 mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
294 return NS_OK;
297 NS_IMETHODIMP
298 nsThebesDeviceContext::CreateRenderingContext(nsIView *aView,
299 nsIRenderingContext *&aContext)
301 // This is currently only called by the caret code
302 NS_ENSURE_ARG_POINTER(aView);
303 NS_PRECONDITION(aView->HasWidget(), "View has no widget!");
305 nsCOMPtr<nsIWidget> widget;
306 widget = aView->GetWidget();
308 return CreateRenderingContext(widget, aContext);
311 NS_IMETHODIMP
312 nsThebesDeviceContext::CreateRenderingContext(nsIWidget *aWidget,
313 nsIRenderingContext *&aContext)
315 nsresult rv;
317 aContext = nsnull;
318 nsCOMPtr<nsIRenderingContext> pContext;
319 rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
320 if (NS_SUCCEEDED(rv)) {
321 nsRefPtr<gfxASurface> surface(aWidget->GetThebesSurface());
322 if (surface)
323 rv = pContext->Init(this, surface);
324 else
325 rv = NS_ERROR_FAILURE;
327 if (NS_SUCCEEDED(rv)) {
328 aContext = pContext;
329 NS_ADDREF(aContext);
333 return rv;
336 NS_IMETHODIMP
337 nsThebesDeviceContext::CreateRenderingContext(nsIRenderingContext *&aContext)
339 nsresult rv = NS_OK;
341 aContext = nsnull;
342 nsCOMPtr<nsIRenderingContext> pContext;
343 rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
344 if (NS_SUCCEEDED(rv)) {
345 if (mPrintingSurface)
346 rv = pContext->Init(this, mPrintingSurface);
347 else
348 rv = NS_ERROR_FAILURE;
350 if (NS_SUCCEEDED(rv)) {
351 pContext->Scale(mPrintingScale, mPrintingScale);
352 aContext = pContext;
353 NS_ADDREF(aContext);
357 return rv;
360 NS_IMETHODIMP
361 nsThebesDeviceContext::CreateRenderingContextInstance(nsIRenderingContext *&aContext)
363 nsCOMPtr<nsIRenderingContext> renderingContext = new nsThebesRenderingContext();
364 if (!renderingContext)
365 return NS_ERROR_OUT_OF_MEMORY;
367 aContext = renderingContext;
368 NS_ADDREF(aContext);
370 return NS_OK;
373 NS_IMETHODIMP
374 nsThebesDeviceContext::SupportsNativeWidgets(PRBool &aSupportsWidgets)
376 aSupportsWidgets = PR_TRUE;
377 return NS_OK;
380 NS_IMETHODIMP
381 nsThebesDeviceContext::ClearCachedSystemFonts()
383 //clear our cache of stored system fonts
384 if (gSystemFonts) {
385 delete gSystemFonts;
386 gSystemFonts = nsnull;
388 return NS_OK;
391 NS_IMETHODIMP
392 nsThebesDeviceContext::GetSystemFont(nsSystemFontID aID, nsFont *aFont) const
394 if (!gSystemFonts) {
395 #ifdef MOZ_ENABLE_GTK2
396 gSystemFonts = new nsSystemFontsGTK2();
397 #elif XP_WIN
398 gSystemFonts = new nsSystemFontsWin();
399 #elif XP_OS2
400 gSystemFonts = new nsSystemFontsOS2();
401 #elif defined(XP_BEOS)
402 gSystemFonts = new nsSystemFontsBeOS();
403 #elif XP_MACOSX
404 gSystemFonts = new nsSystemFontsMac();
405 #elif defined(MOZ_WIDGET_QT)
406 gSystemFonts = new nsSystemFontsQt();
407 #else
408 #error Need to know how to create gSystemFonts, fix me!
409 #endif
412 nsString fontName;
413 gfxFontStyle fontStyle;
414 nsresult rv = gSystemFonts->GetSystemFont(aID, &fontName, &fontStyle);
415 NS_ENSURE_SUCCESS(rv, rv);
417 aFont->name = fontName;
418 aFont->style = fontStyle.style;
419 aFont->systemFont = fontStyle.systemFont;
420 aFont->variant = NS_FONT_VARIANT_NORMAL;
421 aFont->familyNameQuirks = fontStyle.familyNameQuirks;
422 aFont->weight = fontStyle.weight;
423 aFont->decorations = NS_FONT_DECORATION_NONE;
424 aFont->size = NSFloatPixelsToAppUnits(fontStyle.size, UnscaledAppUnitsPerDevPixel());
425 //aFont->langGroup = fontStyle.langGroup;
426 aFont->sizeAdjust = fontStyle.sizeAdjust;
428 return rv;
431 NS_IMETHODIMP
432 nsThebesDeviceContext::CheckFontExistence(const nsString& aFaceName)
434 return NS_OK;
437 NS_IMETHODIMP
438 nsThebesDeviceContext::GetDepth(PRUint32& aDepth)
440 nsCOMPtr<nsIScreen> primaryScreen;
441 if (mDepth == 0) {
442 mScreenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
443 primaryScreen->GetColorDepth(reinterpret_cast<PRInt32 *>(&mDepth));
446 aDepth = mDepth;
447 return NS_OK;
450 NS_IMETHODIMP
451 nsThebesDeviceContext::GetPaletteInfo(nsPaletteInfo& aPaletteInfo)
453 aPaletteInfo.isPaletteDevice = PR_FALSE;
454 aPaletteInfo.sizePalette = 0;
455 aPaletteInfo.numReserved = 0;
456 aPaletteInfo.palette = nsnull;
457 return NS_OK;
461 NS_IMETHODIMP
462 nsThebesDeviceContext::ConvertPixel(nscolor aColor, PRUint32 & aPixel)
464 aPixel = aColor;
465 return NS_OK;
468 NS_IMETHODIMP
469 nsThebesDeviceContext::GetDeviceSurfaceDimensions(nscoord &aWidth, nscoord &aHeight)
471 if (mPrintingSurface) {
472 // we have a printer device
473 aWidth = mWidth;
474 aHeight = mHeight;
475 } else {
476 nsRect area;
477 ComputeFullAreaUsingScreen(&area);
478 aWidth = area.width;
479 aHeight = area.height;
482 return NS_OK;
485 NS_IMETHODIMP
486 nsThebesDeviceContext::GetRect(nsRect &aRect)
488 if (mPrintingSurface) {
489 // we have a printer device
490 aRect.x = 0;
491 aRect.y = 0;
492 aRect.width = mWidth;
493 aRect.height = mHeight;
494 } else
495 ComputeFullAreaUsingScreen ( &aRect );
497 return NS_OK;
500 NS_IMETHODIMP
501 nsThebesDeviceContext::GetClientRect(nsRect &aRect)
503 if (mPrintingSurface) {
504 // we have a printer device
505 aRect.x = 0;
506 aRect.y = 0;
507 aRect.width = mWidth;
508 aRect.height = mHeight;
510 else
511 ComputeClientRectUsingScreen(&aRect);
513 return NS_OK;
516 NS_IMETHODIMP
517 nsThebesDeviceContext::PrepareNativeWidget(nsIWidget* aWidget, void** aOut)
519 *aOut = nsnull;
520 return NS_OK;
525 * below methods are for printing
527 NS_IMETHODIMP
528 nsThebesDeviceContext::InitForPrinting(nsIDeviceContextSpec *aDevice)
530 NS_ENSURE_ARG_POINTER(aDevice);
532 mDeviceContextSpec = aDevice;
534 nsresult rv = aDevice->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface));
535 if (NS_FAILED(rv))
536 return NS_ERROR_FAILURE;
538 Init(nsnull);
540 CalcPrintingSize();
542 return NS_OK;
546 NS_IMETHODIMP
547 nsThebesDeviceContext::PrepareDocument(PRUnichar * aTitle,
548 PRUnichar* aPrintToFileName)
550 return NS_OK;
554 NS_IMETHODIMP
555 nsThebesDeviceContext::BeginDocument(PRUnichar* aTitle,
556 PRUnichar* aPrintToFileName,
557 PRInt32 aStartPage,
558 PRInt32 aEndPage)
560 static const PRUnichar kEmpty[] = { '\0' };
561 nsresult rv;
563 rv = mPrintingSurface->BeginPrinting(nsDependentString(aTitle ? aTitle : kEmpty),
564 nsDependentString(aPrintToFileName ? aPrintToFileName : kEmpty));
566 if (NS_SUCCEEDED(rv) && mDeviceContextSpec)
567 rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName, aStartPage, aEndPage);
569 return rv;
573 NS_IMETHODIMP
574 nsThebesDeviceContext::EndDocument(void)
576 nsresult rv = NS_OK;
578 if (mPrintingSurface) {
579 rv = mPrintingSurface->EndPrinting();
580 if (NS_SUCCEEDED(rv))
581 mPrintingSurface->Finish();
584 if (mDeviceContextSpec)
585 mDeviceContextSpec->EndDocument();
587 return rv;
591 NS_IMETHODIMP
592 nsThebesDeviceContext::AbortDocument(void)
594 nsresult rv = mPrintingSurface->AbortPrinting();
596 if (mDeviceContextSpec)
597 mDeviceContextSpec->EndDocument();
599 return rv;
603 NS_IMETHODIMP
604 nsThebesDeviceContext::BeginPage(void)
606 nsresult rv = NS_OK;
608 if (mDeviceContextSpec)
609 rv = mDeviceContextSpec->BeginPage();
611 if (NS_FAILED(rv)) return rv;
613 /* We need to get a new surface for each page on the Mac */
614 #ifdef XP_MACOSX
615 mDeviceContextSpec->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface));
616 #endif
617 rv = mPrintingSurface->BeginPage();
619 return rv;
622 NS_IMETHODIMP
623 nsThebesDeviceContext::EndPage(void)
625 nsresult rv = mPrintingSurface->EndPage();
627 /* We need to release the CGContextRef in the surface here, plus it's
628 not something you would want anyway, as these CGContextRefs are only good
629 for one page. */
630 #ifdef XP_MACOSX
631 mPrintingSurface = nsnull;
632 #endif
634 if (mDeviceContextSpec)
635 mDeviceContextSpec->EndPage();
637 return rv;
640 /** End printing methods **/
642 void
643 nsThebesDeviceContext::ComputeClientRectUsingScreen(nsRect* outRect)
645 // we always need to recompute the clientRect
646 // because the window may have moved onto a different screen. In the single
647 // monitor case, we only need to do the computation if we haven't done it
648 // once already, and remember that we have because we're assured it won't change.
649 nsCOMPtr<nsIScreen> screen;
650 FindScreen (getter_AddRefs(screen));
651 if (screen) {
652 PRInt32 x, y, width, height;
653 screen->GetAvailRect(&x, &y, &width, &height);
655 // convert to device units
656 outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
657 outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
658 outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
659 outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
663 void
664 nsThebesDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect)
666 // if we have more than one screen, we always need to recompute the clientRect
667 // because the window may have moved onto a different screen. In the single
668 // monitor case, we only need to do the computation if we haven't done it
669 // once already, and remember that we have because we're assured it won't change.
670 nsCOMPtr<nsIScreen> screen;
671 FindScreen ( getter_AddRefs(screen) );
672 if ( screen ) {
673 PRInt32 x, y, width, height;
674 screen->GetRect ( &x, &y, &width, &height );
676 // convert to device units
677 outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
678 outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
679 outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
680 outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
682 mWidth = outRect->width;
683 mHeight = outRect->height;
690 // FindScreen
692 // Determines which screen intersects the largest area of the given surface.
694 void
695 nsThebesDeviceContext::FindScreen(nsIScreen** outScreen)
697 if (mWidget)
698 mScreenManager->ScreenForNativeWidget(mWidget, outScreen);
699 else
700 mScreenManager->GetPrimaryScreen(outScreen);
703 void
704 nsThebesDeviceContext::CalcPrintingSize()
706 if (!mPrintingSurface)
707 return;
709 PRBool inPoints = PR_TRUE;
711 gfxSize size;
712 switch (mPrintingSurface->GetType()) {
713 case gfxASurface::SurfaceTypeImage:
714 inPoints = PR_FALSE;
715 size = reinterpret_cast<gfxImageSurface*>(mPrintingSurface.get())->GetSize();
716 break;
718 #if defined(MOZ_ENABLE_GTK2) || defined(XP_WIN) || defined(XP_OS2)
719 case gfxASurface::SurfaceTypePDF:
720 inPoints = PR_TRUE;
721 size = reinterpret_cast<gfxPDFSurface*>(mPrintingSurface.get())->GetSize();
722 break;
723 #endif
725 #ifdef MOZ_ENABLE_GTK2
726 case gfxASurface::SurfaceTypePS:
727 inPoints = PR_TRUE;
728 size = reinterpret_cast<gfxPSSurface*>(mPrintingSurface.get())->GetSize();
729 break;
730 #endif
732 #ifdef XP_MACOSX
733 case gfxASurface::SurfaceTypeQuartz:
734 inPoints = PR_TRUE; // this is really only true when we're printing
735 size = reinterpret_cast<gfxQuartzSurface*>(mPrintingSurface.get())->GetSize();
736 break;
737 #endif
739 #ifdef XP_WIN
740 case gfxASurface::SurfaceTypeWin32:
741 case gfxASurface::SurfaceTypeWin32Printing:
743 inPoints = PR_FALSE;
744 HDC dc = GetPrintHDC();
745 if (!dc)
746 dc = GetDC((HWND)mWidget);
747 size.width = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, HORZRES)/mPrintingScale, AppUnitsPerDevPixel());
748 size.height = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, VERTRES)/mPrintingScale, AppUnitsPerDevPixel());
749 mDepth = (PRUint32)::GetDeviceCaps(dc, BITSPIXEL);
750 if (dc != (HDC)GetPrintHDC())
751 ReleaseDC((HWND)mWidget, dc);
752 break;
754 #endif
756 #ifdef XP_OS2
757 case gfxASurface::SurfaceTypeOS2:
759 inPoints = PR_FALSE;
760 // we already set the size in the surface constructor we set for
761 // printing, so just get those values here
762 size = reinterpret_cast<gfxOS2Surface*>(mPrintingSurface.get())->GetSize();
763 // as they are in pixels we need to scale them to app units
764 size.width = NSFloatPixelsToAppUnits(size.width, AppUnitsPerDevPixel());
765 size.height = NSFloatPixelsToAppUnits(size.height, AppUnitsPerDevPixel());
766 // still need to get the depth from the device context
767 HDC dc = GetPrintHDC();
768 LONG value;
769 if (DevQueryCaps(dc, CAPS_COLOR_BITCOUNT, 1, &value))
770 mDepth = value;
771 else
772 mDepth = 8; // default to 8bpp, should be enough for printers
773 break;
775 #endif
776 default:
777 NS_ASSERTION(0, "trying to print to unknown surface type");
780 if (inPoints) {
781 mWidth = NSToCoordRound(float(size.width) * AppUnitsPerInch() / 72);
782 mHeight = NSToCoordRound(float(size.height) * AppUnitsPerInch() / 72);
783 } else {
784 mWidth = NSToIntRound(size.width);
785 mHeight = NSToIntRound(size.height);
789 PRBool nsThebesDeviceContext::CheckDPIChange() {
790 PRInt32 oldDevPixels = mAppUnitsPerDevNotScaledPixel;
791 PRInt32 oldInches = mAppUnitsPerInch;
793 SetDPI();
795 return oldDevPixels != mAppUnitsPerDevNotScaledPixel ||
796 oldInches != mAppUnitsPerInch;
799 PRBool
800 nsThebesDeviceContext::SetPixelScale(float aScale)
802 if (aScale <= 0) {
803 NS_NOTREACHED("Invalid pixel scale value");
804 return PR_FALSE;
806 PRInt32 oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
807 mPixelScale = aScale;
808 UpdateScaledAppUnits();
809 return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel;
812 void
813 nsThebesDeviceContext::UpdateScaledAppUnits()
815 mAppUnitsPerDevPixel = PR_MAX(1, PRInt32(float(mAppUnitsPerDevNotScaledPixel) / mPixelScale));
818 #if defined(XP_WIN) || defined(XP_OS2)
820 nsThebesDeviceContext::GetPrintHDC()
822 if (mPrintingSurface) {
823 switch (mPrintingSurface->GetType()) {
824 #ifdef XP_WIN
825 case gfxASurface::SurfaceTypeWin32:
826 case gfxASurface::SurfaceTypeWin32Printing:
827 return reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
828 #endif
830 #ifdef XP_OS2
831 case gfxASurface::SurfaceTypeOS2:
832 return GpiQueryDevice(reinterpret_cast<gfxOS2Surface*>(mPrintingSurface.get())->GetPS());
833 #endif
835 default:
836 NS_ASSERTION(0, "invalid surface type in GetPrintHDC");
837 break;
841 return nsnull;
843 #endif