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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is thebes gfx
16 : *
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.
21 : *
22 : * Contributor(s):
23 : * Vladimir Vukicevic <vladimir@pobox.com>
24 : * Stuart Parmenter <pavlov@pavlov.net>
25 : *
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.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsDeviceContext.h"
41 : #include "nsCRT.h"
42 : #include "nsFontMetrics.h"
43 : #include "nsRenderingContext.h"
44 : #include "nsIView.h"
45 : #include "nsIWidget.h"
46 :
47 : #include "mozilla/Attributes.h"
48 : #include "mozilla/Services.h"
49 : #include "mozilla/Preferences.h"
50 : #include "nsIServiceManager.h"
51 : #include "nsILanguageAtomService.h"
52 : #include "nsIObserver.h"
53 : #include "nsIObserverService.h"
54 :
55 : #include "gfxImageSurface.h"
56 :
57 : #if !XP_MACOSX
58 : #include "gfxPDFSurface.h"
59 : #endif
60 :
61 : #ifdef MOZ_ENABLE_GTK2
62 : #include "gfxPSSurface.h"
63 : #elif XP_WIN
64 : #include "gfxWindowsSurface.h"
65 : #elif defined(XP_OS2)
66 : #include "gfxOS2Surface.h"
67 : #elif XP_MACOSX
68 : #include "gfxQuartzSurface.h"
69 : #endif
70 :
71 : using namespace mozilla;
72 : using mozilla::services::GetObserverService;
73 :
74 : class nsFontCache MOZ_FINAL : public nsIObserver
75 : {
76 : public:
77 0 : nsFontCache() { MOZ_COUNT_CTOR(nsFontCache); }
78 0 : ~nsFontCache() { MOZ_COUNT_DTOR(nsFontCache); }
79 :
80 : NS_DECL_ISUPPORTS
81 : NS_DECL_NSIOBSERVER
82 :
83 : void Init(nsDeviceContext* aContext);
84 : void Destroy();
85 :
86 : nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
87 : gfxUserFontSet* aUserFontSet,
88 : nsFontMetrics*& aMetrics);
89 :
90 : void FontMetricsDeleted(const nsFontMetrics* aFontMetrics);
91 : void Compact();
92 : void Flush();
93 :
94 : protected:
95 : nsDeviceContext* mContext; // owner
96 : nsCOMPtr<nsIAtom> mLocaleLanguage;
97 : nsTArray<nsFontMetrics*> mFontMetrics;
98 : };
99 :
100 0 : NS_IMPL_ISUPPORTS1(nsFontCache, nsIObserver)
101 :
102 : // The Init and Destroy methods are necessary because it's not
103 : // safe to call AddObserver from a constructor or RemoveObserver
104 : // from a destructor. That should be fixed.
105 : void
106 0 : nsFontCache::Init(nsDeviceContext* aContext)
107 : {
108 0 : mContext = aContext;
109 : // register as a memory-pressure observer to free font resources
110 : // in low-memory situations.
111 0 : nsCOMPtr<nsIObserverService> obs = GetObserverService();
112 0 : if (obs)
113 0 : obs->AddObserver(this, "memory-pressure", false);
114 :
115 0 : nsCOMPtr<nsILanguageAtomService> langService;
116 0 : langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
117 0 : if (langService) {
118 0 : mLocaleLanguage = langService->GetLocaleLanguage();
119 : }
120 0 : if (!mLocaleLanguage) {
121 0 : mLocaleLanguage = do_GetAtom("x-western");
122 : }
123 0 : }
124 :
125 : void
126 0 : nsFontCache::Destroy()
127 : {
128 0 : nsCOMPtr<nsIObserverService> obs = GetObserverService();
129 0 : if (obs)
130 0 : obs->RemoveObserver(this, "memory-pressure");
131 0 : Flush();
132 0 : }
133 :
134 : NS_IMETHODIMP
135 0 : nsFontCache::Observe(nsISupports*, const char* aTopic, const PRUnichar*)
136 : {
137 0 : if (!nsCRT::strcmp(aTopic, "memory-pressure"))
138 0 : Compact();
139 0 : return NS_OK;
140 : }
141 :
142 : nsresult
143 0 : nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
144 : gfxUserFontSet* aUserFontSet,
145 : nsFontMetrics*& aMetrics)
146 : {
147 0 : if (!aLanguage)
148 0 : aLanguage = mLocaleLanguage;
149 :
150 : // First check our cache
151 : // start from the end, which is where we put the most-recent-used element
152 :
153 : nsFontMetrics* fm;
154 0 : PRInt32 n = mFontMetrics.Length() - 1;
155 0 : for (PRInt32 i = n; i >= 0; --i) {
156 0 : fm = mFontMetrics[i];
157 0 : if (fm->Font().Equals(aFont) && fm->GetUserFontSet() == aUserFontSet &&
158 0 : fm->Language() == aLanguage) {
159 0 : if (i != n) {
160 : // promote it to the end of the cache
161 0 : mFontMetrics.RemoveElementAt(i);
162 0 : mFontMetrics.AppendElement(fm);
163 : }
164 0 : fm->GetThebesFontGroup()->UpdateFontList();
165 0 : NS_ADDREF(aMetrics = fm);
166 0 : return NS_OK;
167 : }
168 : }
169 :
170 : // It's not in the cache. Get font metrics and then cache them.
171 :
172 0 : fm = new nsFontMetrics();
173 0 : NS_ADDREF(fm);
174 0 : nsresult rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet);
175 0 : if (NS_SUCCEEDED(rv)) {
176 : // the mFontMetrics list has the "head" at the end, because append
177 : // is cheaper than insert
178 0 : mFontMetrics.AppendElement(fm);
179 0 : aMetrics = fm;
180 0 : NS_ADDREF(aMetrics);
181 0 : return NS_OK;
182 : }
183 0 : fm->Destroy();
184 0 : NS_RELEASE(fm);
185 :
186 : // One reason why Init() fails is because the system is running out of
187 : // resources. e.g., on Win95/98 only a very limited number of GDI
188 : // objects are available. Compact the cache and try again.
189 :
190 0 : Compact();
191 0 : fm = new nsFontMetrics();
192 0 : NS_ADDREF(fm);
193 0 : rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet);
194 0 : if (NS_SUCCEEDED(rv)) {
195 0 : mFontMetrics.AppendElement(fm);
196 0 : aMetrics = fm;
197 0 : return NS_OK;
198 : }
199 0 : fm->Destroy();
200 0 : NS_RELEASE(fm);
201 :
202 : // could not setup a new one, send an old one (XXX search a "best
203 : // match"?)
204 :
205 0 : n = mFontMetrics.Length() - 1; // could have changed in Compact()
206 0 : if (n >= 0) {
207 0 : aMetrics = mFontMetrics[n];
208 0 : NS_ADDREF(aMetrics);
209 0 : return NS_OK;
210 : }
211 :
212 0 : NS_POSTCONDITION(NS_SUCCEEDED(rv),
213 : "font metrics should not be null - bug 136248");
214 0 : return rv;
215 : }
216 :
217 : void
218 0 : nsFontCache::FontMetricsDeleted(const nsFontMetrics* aFontMetrics)
219 : {
220 0 : mFontMetrics.RemoveElement(aFontMetrics);
221 0 : }
222 :
223 : void
224 0 : nsFontCache::Compact()
225 : {
226 : // Need to loop backward because the running element can be removed on
227 : // the way
228 0 : for (PRInt32 i = mFontMetrics.Length()-1; i >= 0; --i) {
229 0 : nsFontMetrics* fm = mFontMetrics[i];
230 0 : nsFontMetrics* oldfm = fm;
231 : // Destroy() isn't here because we want our device context to be
232 : // notified
233 0 : NS_RELEASE(fm); // this will reset fm to nsnull
234 : // if the font is really gone, it would have called back in
235 : // FontMetricsDeleted() and would have removed itself
236 0 : if (mFontMetrics.IndexOf(oldfm) != mFontMetrics.NoIndex) {
237 : // nope, the font is still there, so let's hold onto it too
238 0 : NS_ADDREF(oldfm);
239 : }
240 : }
241 0 : }
242 :
243 : void
244 0 : nsFontCache::Flush()
245 : {
246 0 : for (PRInt32 i = mFontMetrics.Length()-1; i >= 0; --i) {
247 0 : nsFontMetrics* fm = mFontMetrics[i];
248 : // Destroy() will unhook our device context from the fm so that we
249 : // won't waste time in triggering the notification of
250 : // FontMetricsDeleted() in the subsequent release
251 0 : fm->Destroy();
252 0 : NS_RELEASE(fm);
253 : }
254 0 : mFontMetrics.Clear();
255 0 : }
256 :
257 0 : nsDeviceContext::nsDeviceContext()
258 : : mWidth(0), mHeight(0), mDepth(0),
259 : mAppUnitsPerDevPixel(-1), mAppUnitsPerDevNotScaledPixel(-1),
260 : mAppUnitsPerPhysicalInch(-1),
261 : mPixelScale(1.0f), mPrintingScale(1.0f),
262 0 : mFontCache(nsnull)
263 : {
264 0 : }
265 :
266 : // Note: we use a bare pointer for mFontCache so that nsFontCache
267 : // can be an incomplete type in nsDeviceContext.h.
268 : // Therefore we have to do all the refcounting by hand.
269 0 : nsDeviceContext::~nsDeviceContext()
270 : {
271 0 : if (mFontCache) {
272 0 : mFontCache->Destroy();
273 0 : NS_RELEASE(mFontCache);
274 : }
275 0 : }
276 :
277 : nsresult
278 0 : nsDeviceContext::GetMetricsFor(const nsFont& aFont,
279 : nsIAtom* aLanguage,
280 : gfxUserFontSet* aUserFontSet,
281 : nsFontMetrics*& aMetrics)
282 : {
283 0 : if (!mFontCache) {
284 0 : mFontCache = new nsFontCache();
285 0 : NS_ADDREF(mFontCache);
286 0 : mFontCache->Init(this);
287 : }
288 :
289 0 : return mFontCache->GetMetricsFor(aFont, aLanguage, aUserFontSet, aMetrics);
290 : }
291 :
292 : nsresult
293 0 : nsDeviceContext::FlushFontCache(void)
294 : {
295 0 : if (mFontCache)
296 0 : mFontCache->Flush();
297 0 : return NS_OK;
298 : }
299 :
300 : nsresult
301 0 : nsDeviceContext::FontMetricsDeleted(const nsFontMetrics* aFontMetrics)
302 : {
303 0 : if (mFontCache) {
304 0 : mFontCache->FontMetricsDeleted(aFontMetrics);
305 : }
306 0 : return NS_OK;
307 : }
308 :
309 : bool
310 0 : nsDeviceContext::IsPrinterSurface()
311 : {
312 0 : return(mPrintingSurface != NULL);
313 : }
314 :
315 : void
316 0 : nsDeviceContext::SetDPI()
317 : {
318 0 : float dpi = -1.0f;
319 :
320 : // PostScript, PDF and Mac (when printing) all use 72 dpi
321 : // Use a printing DC to determine the other dpi values
322 0 : if (mPrintingSurface) {
323 0 : switch (mPrintingSurface->GetType()) {
324 : case gfxASurface::SurfaceTypePDF:
325 : case gfxASurface::SurfaceTypePS:
326 : case gfxASurface::SurfaceTypeQuartz:
327 0 : dpi = 72.0f;
328 0 : break;
329 : #ifdef XP_WIN
330 : case gfxASurface::SurfaceTypeWin32:
331 : case gfxASurface::SurfaceTypeWin32Printing: {
332 : HDC dc = reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
333 : PRInt32 OSVal = GetDeviceCaps(dc, LOGPIXELSY);
334 : dpi = 144.0f;
335 : mPrintingScale = float(OSVal) / dpi;
336 : break;
337 : }
338 : #endif
339 : #ifdef XP_OS2
340 : case gfxASurface::SurfaceTypeOS2: {
341 : LONG lDPI;
342 : HDC dc = GpiQueryDevice(reinterpret_cast<gfxOS2Surface*>(mPrintingSurface.get())->GetPS());
343 : if (DevQueryCaps(dc, CAPS_VERTICAL_FONT_RES, 1, &lDPI))
344 : dpi = lDPI;
345 : break;
346 : }
347 : #endif
348 : default:
349 0 : NS_NOTREACHED("Unexpected printing surface type");
350 0 : break;
351 : }
352 :
353 : mAppUnitsPerDevNotScaledPixel =
354 0 : NS_lround((AppUnitsPerCSSPixel() * 96) / dpi);
355 : } else {
356 : // A value of -1 means use the maximum of 96 and the system DPI.
357 : // A value of 0 means use the system DPI. A positive value is used as the DPI.
358 : // This sets the physical size of a device pixel and thus controls the
359 : // interpretation of physical units.
360 0 : PRInt32 prefDPI = Preferences::GetInt("layout.css.dpi", -1);
361 :
362 0 : if (prefDPI > 0) {
363 0 : dpi = prefDPI;
364 0 : } else if (mWidget) {
365 0 : dpi = mWidget->GetDPI();
366 :
367 0 : if (prefDPI < 0) {
368 0 : dpi = NS_MAX(96.0f, dpi);
369 : }
370 : } else {
371 0 : dpi = 96.0f;
372 : }
373 :
374 : // The number of device pixels per CSS pixel. A value <= 0 means choose
375 : // automatically based on the DPI. A positive value is used as-is. This effectively
376 : // controls the size of a CSS "px".
377 0 : float devPixelsPerCSSPixel = -1.0;
378 :
379 0 : nsAdoptingCString prefString = Preferences::GetCString("layout.css.devPixelsPerPx");
380 0 : if (!prefString.IsEmpty()) {
381 0 : devPixelsPerCSSPixel = static_cast<float>(atof(prefString));
382 : }
383 :
384 0 : if (devPixelsPerCSSPixel <= 0) {
385 0 : if (mWidget) {
386 0 : devPixelsPerCSSPixel = mWidget->GetDefaultScale();
387 : } else {
388 0 : devPixelsPerCSSPixel = 1.0;
389 : }
390 : }
391 :
392 : mAppUnitsPerDevNotScaledPixel =
393 0 : NS_MAX(1, NS_lround(AppUnitsPerCSSPixel() / devPixelsPerCSSPixel));
394 : }
395 :
396 0 : NS_ASSERTION(dpi != -1.0, "no dpi set");
397 :
398 0 : mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevNotScaledPixel);
399 0 : UpdateScaledAppUnits();
400 0 : }
401 :
402 : nsresult
403 0 : nsDeviceContext::Init(nsIWidget *aWidget)
404 : {
405 0 : if (mScreenManager && mWidget == aWidget)
406 0 : return NS_OK;
407 :
408 0 : mWidget = aWidget;
409 0 : SetDPI();
410 :
411 0 : if (mScreenManager)
412 0 : return NS_OK;
413 :
414 0 : mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
415 :
416 0 : return NS_OK;
417 : }
418 :
419 : nsresult
420 0 : nsDeviceContext::CreateRenderingContext(nsRenderingContext *&aContext)
421 : {
422 0 : NS_ABORT_IF_FALSE(mPrintingSurface, "only call for printing dcs");
423 :
424 0 : nsRefPtr<nsRenderingContext> pContext = new nsRenderingContext();
425 :
426 0 : pContext->Init(this, mPrintingSurface);
427 0 : pContext->Scale(mPrintingScale, mPrintingScale);
428 0 : aContext = pContext;
429 0 : NS_ADDREF(aContext);
430 :
431 0 : return NS_OK;
432 : }
433 :
434 : nsresult
435 0 : nsDeviceContext::GetDepth(PRUint32& aDepth)
436 : {
437 0 : if (mDepth == 0) {
438 0 : nsCOMPtr<nsIScreen> primaryScreen;
439 0 : mScreenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
440 0 : primaryScreen->GetColorDepth(reinterpret_cast<PRInt32 *>(&mDepth));
441 : }
442 :
443 0 : aDepth = mDepth;
444 0 : return NS_OK;
445 : }
446 :
447 : nsresult
448 0 : nsDeviceContext::GetDeviceSurfaceDimensions(nscoord &aWidth, nscoord &aHeight)
449 : {
450 0 : if (mPrintingSurface) {
451 : // we have a printer device
452 0 : aWidth = mWidth;
453 0 : aHeight = mHeight;
454 : } else {
455 0 : nsRect area;
456 0 : ComputeFullAreaUsingScreen(&area);
457 0 : aWidth = area.width;
458 0 : aHeight = area.height;
459 : }
460 :
461 0 : return NS_OK;
462 : }
463 :
464 : nsresult
465 0 : nsDeviceContext::GetRect(nsRect &aRect)
466 : {
467 0 : if (mPrintingSurface) {
468 : // we have a printer device
469 0 : aRect.x = 0;
470 0 : aRect.y = 0;
471 0 : aRect.width = mWidth;
472 0 : aRect.height = mHeight;
473 : } else
474 0 : ComputeFullAreaUsingScreen ( &aRect );
475 :
476 0 : return NS_OK;
477 : }
478 :
479 : nsresult
480 0 : nsDeviceContext::GetClientRect(nsRect &aRect)
481 : {
482 0 : if (mPrintingSurface) {
483 : // we have a printer device
484 0 : aRect.x = 0;
485 0 : aRect.y = 0;
486 0 : aRect.width = mWidth;
487 0 : aRect.height = mHeight;
488 : }
489 : else
490 0 : ComputeClientRectUsingScreen(&aRect);
491 :
492 0 : return NS_OK;
493 : }
494 :
495 : nsresult
496 0 : nsDeviceContext::InitForPrinting(nsIDeviceContextSpec *aDevice)
497 : {
498 0 : NS_ENSURE_ARG_POINTER(aDevice);
499 :
500 0 : mDeviceContextSpec = aDevice;
501 :
502 0 : nsresult rv = aDevice->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface));
503 0 : if (NS_FAILED(rv))
504 0 : return NS_ERROR_FAILURE;
505 :
506 0 : Init(nsnull);
507 :
508 0 : CalcPrintingSize();
509 :
510 0 : return NS_OK;
511 : }
512 :
513 : nsresult
514 0 : nsDeviceContext::BeginDocument(PRUnichar* aTitle,
515 : PRUnichar* aPrintToFileName,
516 : PRInt32 aStartPage,
517 : PRInt32 aEndPage)
518 : {
519 : static const PRUnichar kEmpty[] = { '\0' };
520 : nsresult rv;
521 :
522 0 : rv = mPrintingSurface->BeginPrinting(nsDependentString(aTitle ? aTitle : kEmpty),
523 0 : nsDependentString(aPrintToFileName ? aPrintToFileName : kEmpty));
524 :
525 0 : if (NS_SUCCEEDED(rv) && mDeviceContextSpec)
526 0 : rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName, aStartPage, aEndPage);
527 :
528 0 : return rv;
529 : }
530 :
531 :
532 : nsresult
533 0 : nsDeviceContext::EndDocument(void)
534 : {
535 0 : nsresult rv = NS_OK;
536 :
537 0 : if (mPrintingSurface) {
538 0 : rv = mPrintingSurface->EndPrinting();
539 0 : if (NS_SUCCEEDED(rv))
540 0 : mPrintingSurface->Finish();
541 : }
542 :
543 0 : if (mDeviceContextSpec)
544 0 : mDeviceContextSpec->EndDocument();
545 :
546 0 : return rv;
547 : }
548 :
549 :
550 : nsresult
551 0 : nsDeviceContext::AbortDocument(void)
552 : {
553 0 : nsresult rv = mPrintingSurface->AbortPrinting();
554 :
555 0 : if (mDeviceContextSpec)
556 0 : mDeviceContextSpec->EndDocument();
557 :
558 0 : return rv;
559 : }
560 :
561 :
562 : nsresult
563 0 : nsDeviceContext::BeginPage(void)
564 : {
565 0 : nsresult rv = NS_OK;
566 :
567 0 : if (mDeviceContextSpec)
568 0 : rv = mDeviceContextSpec->BeginPage();
569 :
570 0 : if (NS_FAILED(rv)) return rv;
571 :
572 : #ifdef XP_MACOSX
573 : // We need to get a new surface for each page on the Mac, as the
574 : // CGContextRefs are only good for one page.
575 : // And we don't null it out in EndPage because mPrintingSurface needs
576 : // to be available also in-between EndPage/BeginPage (bug 665218).
577 : mDeviceContextSpec->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface));
578 : #endif
579 :
580 0 : rv = mPrintingSurface->BeginPage();
581 :
582 0 : return rv;
583 : }
584 :
585 : nsresult
586 0 : nsDeviceContext::EndPage(void)
587 : {
588 0 : nsresult rv = mPrintingSurface->EndPage();
589 :
590 0 : if (mDeviceContextSpec)
591 0 : mDeviceContextSpec->EndPage();
592 :
593 0 : return rv;
594 : }
595 :
596 : void
597 0 : nsDeviceContext::ComputeClientRectUsingScreen(nsRect* outRect)
598 : {
599 : // we always need to recompute the clientRect
600 : // because the window may have moved onto a different screen. In the single
601 : // monitor case, we only need to do the computation if we haven't done it
602 : // once already, and remember that we have because we're assured it won't change.
603 0 : nsCOMPtr<nsIScreen> screen;
604 0 : FindScreen (getter_AddRefs(screen));
605 0 : if (screen) {
606 : PRInt32 x, y, width, height;
607 0 : screen->GetAvailRect(&x, &y, &width, &height);
608 :
609 : // convert to device units
610 0 : outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
611 0 : outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
612 0 : outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
613 0 : outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
614 : }
615 0 : }
616 :
617 : void
618 0 : nsDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect)
619 : {
620 : // if we have more than one screen, we always need to recompute the clientRect
621 : // because the window may have moved onto a different screen. In the single
622 : // monitor case, we only need to do the computation if we haven't done it
623 : // once already, and remember that we have because we're assured it won't change.
624 0 : nsCOMPtr<nsIScreen> screen;
625 0 : FindScreen ( getter_AddRefs(screen) );
626 0 : if ( screen ) {
627 : PRInt32 x, y, width, height;
628 0 : screen->GetRect ( &x, &y, &width, &height );
629 :
630 : // convert to device units
631 0 : outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
632 0 : outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
633 0 : outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
634 0 : outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
635 :
636 0 : mWidth = outRect->width;
637 0 : mHeight = outRect->height;
638 : }
639 0 : }
640 :
641 : //
642 : // FindScreen
643 : //
644 : // Determines which screen intersects the largest area of the given surface.
645 : //
646 : void
647 0 : nsDeviceContext::FindScreen(nsIScreen** outScreen)
648 : {
649 0 : if (mWidget && mWidget->GetNativeData(NS_NATIVE_WINDOW))
650 0 : mScreenManager->ScreenForNativeWidget(mWidget->GetNativeData(NS_NATIVE_WINDOW),
651 0 : outScreen);
652 : else
653 0 : mScreenManager->GetPrimaryScreen(outScreen);
654 0 : }
655 :
656 : void
657 0 : nsDeviceContext::CalcPrintingSize()
658 : {
659 0 : if (!mPrintingSurface)
660 0 : return;
661 :
662 0 : bool inPoints = true;
663 :
664 0 : gfxSize size(0, 0);
665 0 : switch (mPrintingSurface->GetType()) {
666 : case gfxASurface::SurfaceTypeImage:
667 0 : inPoints = false;
668 0 : size = reinterpret_cast<gfxImageSurface*>(mPrintingSurface.get())->GetSize();
669 0 : break;
670 :
671 : #if defined(MOZ_PDF_PRINTING)
672 : case gfxASurface::SurfaceTypePDF:
673 0 : inPoints = true;
674 0 : size = reinterpret_cast<gfxPDFSurface*>(mPrintingSurface.get())->GetSize();
675 0 : break;
676 : #endif
677 :
678 : #ifdef MOZ_ENABLE_GTK2
679 : case gfxASurface::SurfaceTypePS:
680 0 : inPoints = true;
681 0 : size = reinterpret_cast<gfxPSSurface*>(mPrintingSurface.get())->GetSize();
682 0 : break;
683 : #endif
684 :
685 : #ifdef XP_MACOSX
686 : case gfxASurface::SurfaceTypeQuartz:
687 : inPoints = true; // this is really only true when we're printing
688 : size = reinterpret_cast<gfxQuartzSurface*>(mPrintingSurface.get())->GetSize();
689 : break;
690 : #endif
691 :
692 : #ifdef XP_WIN
693 : case gfxASurface::SurfaceTypeWin32:
694 : case gfxASurface::SurfaceTypeWin32Printing:
695 : {
696 : inPoints = false;
697 : HDC dc = reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
698 : if (!dc)
699 : dc = GetDC((HWND)mWidget->GetNativeData(NS_NATIVE_WIDGET));
700 : size.width = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, HORZRES)/mPrintingScale, AppUnitsPerDevPixel());
701 : size.height = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, VERTRES)/mPrintingScale, AppUnitsPerDevPixel());
702 : mDepth = (PRUint32)::GetDeviceCaps(dc, BITSPIXEL);
703 : if (dc != reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC())
704 : ReleaseDC((HWND)mWidget->GetNativeData(NS_NATIVE_WIDGET), dc);
705 : break;
706 : }
707 : #endif
708 :
709 : #ifdef XP_OS2
710 : case gfxASurface::SurfaceTypeOS2:
711 : {
712 : inPoints = false;
713 : // we already set the size in the surface constructor we set for
714 : // printing, so just get those values here
715 : size = reinterpret_cast<gfxOS2Surface*>(mPrintingSurface.get())->GetSize();
716 : // as they are in pixels we need to scale them to app units
717 : size.width = NSFloatPixelsToAppUnits(size.width, AppUnitsPerDevPixel());
718 : size.height = NSFloatPixelsToAppUnits(size.height, AppUnitsPerDevPixel());
719 : // still need to get the depth from the device context
720 : HDC dc = GpiQueryDevice(reinterpret_cast<gfxOS2Surface*>(mPrintingSurface.get())->GetPS());
721 : LONG value;
722 : if (DevQueryCaps(dc, CAPS_COLOR_BITCOUNT, 1, &value))
723 : mDepth = value;
724 : else
725 : mDepth = 8; // default to 8bpp, should be enough for printers
726 : break;
727 : }
728 : #endif
729 : default:
730 0 : NS_ERROR("trying to print to unknown surface type");
731 : }
732 :
733 0 : if (inPoints) {
734 : // For printing, CSS inches and physical inches are identical
735 : // so it doesn't matter which we use here
736 0 : mWidth = NSToCoordRound(float(size.width) * AppUnitsPerPhysicalInch() / 72);
737 0 : mHeight = NSToCoordRound(float(size.height) * AppUnitsPerPhysicalInch() / 72);
738 : } else {
739 0 : mWidth = NSToIntRound(size.width);
740 0 : mHeight = NSToIntRound(size.height);
741 : }
742 : }
743 :
744 0 : bool nsDeviceContext::CheckDPIChange() {
745 0 : PRInt32 oldDevPixels = mAppUnitsPerDevNotScaledPixel;
746 0 : PRInt32 oldInches = mAppUnitsPerPhysicalInch;
747 :
748 0 : SetDPI();
749 :
750 : return oldDevPixels != mAppUnitsPerDevNotScaledPixel ||
751 0 : oldInches != mAppUnitsPerPhysicalInch;
752 : }
753 :
754 : bool
755 0 : nsDeviceContext::SetPixelScale(float aScale)
756 : {
757 0 : if (aScale <= 0) {
758 0 : NS_NOTREACHED("Invalid pixel scale value");
759 0 : return false;
760 : }
761 0 : PRUint32 oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
762 0 : mPixelScale = aScale;
763 0 : UpdateScaledAppUnits();
764 0 : return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel;
765 : }
766 :
767 : void
768 0 : nsDeviceContext::UpdateScaledAppUnits()
769 : {
770 : mAppUnitsPerDevPixel =
771 0 : NS_MAX(1, NSToIntRound(float(mAppUnitsPerDevNotScaledPixel) / mPixelScale));
772 0 : }
|