Back to index

lightning-sunbird  0.9+nobinonly
nsDeviceContextQt.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Lars Knoll <knoll@kde.org>
00024  *   Zack Rusin <zack@kde.org>
00025  *   John C. Griggs <johng@corel.com>
00026  *   Esben Mose Hansen <esben@despammed.com>
00027  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either the GNU General Public License Version 2 or later (the "GPL"), or
00031  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 #include <math.h>
00044 
00045 #include "nspr.h"
00046 #include "nsIPrefBranch.h"
00047 #include "nsIPrefService.h"
00048 #include "nsIPrefBranch2.h"
00049 #include "nsIServiceManager.h"
00050 #include "nsCRT.h"
00051 #include "nsDeviceContextQt.h"
00052 #include "nsFontMetricsQt.h"
00053 #include "nsFont.h"
00054 #include "nsGfxCIID.h"
00055 #include "nsRenderingContextQt.h"
00056 #include "nsDeviceContextSpecQt.h"
00057 
00058 #ifdef USE_POSTSCRIPT
00059 #include "nsGfxPSCID.h"
00060 #include "nsIDeviceContextPS.h"
00061 #endif /* USE_POSTSCRIPT */
00062 #ifdef USE_XPRINT
00063 #include "nsGfxXPrintCID.h"
00064 #include "nsIDeviceContextXPrint.h"
00065 #endif /* USE_XPRINT */
00066 
00067 #include <qpaintdevicemetrics.h>
00068 #include <qscrollbar.h>
00069 #include <qpalette.h>
00070 #include <qapplication.h>
00071 #include <qstyle.h>
00072 #include <qfontdatabase.h>
00073 #include <qfontmetrics.h>
00074 #include <qwidgetlist.h>
00075 
00076 #include "nsIScreenManager.h"
00077 
00078 #include "qtlog.h"
00079 
00080 #define QCOLOR_TO_NS_RGB(c) \
00081     ((nscolor)NS_RGB(c.red(),c.green(),c.blue()))
00082 
00083 nscoord nsDeviceContextQt::mDpi = 0;
00084 
00085 nsDeviceContextQt::nsDeviceContextQt()
00086   : DeviceContextImpl()
00087 {
00088   mTwipsToPixels = 1.0;
00089   mPixelsToTwips = 1.0;
00090   mDepth = 0 ;
00091   mWidthFloat = 0.0f;
00092   mHeightFloat = 0.0f;
00093   mWidth = -1;
00094   mHeight = -1;
00095 }
00096 
00097 nsDeviceContextQt::~nsDeviceContextQt()
00098 {
00099   nsCOMPtr<nsIPrefBranch2> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
00100   if (pbi) {
00101     pbi->RemoveObserver("layout.css.dpi", this);
00102   }
00103 }
00104 
00105 NS_IMETHODIMP nsDeviceContextQt::Init(nsNativeWidget aNativeWidget)
00106 {
00107   PRBool  bCleanUp = PR_FALSE;
00108   QWidget *pWidget  = nsnull;
00109 
00110   mWidget = (QWidget*)aNativeWidget;
00111 
00112   if (mWidget != nsnull)
00113     pWidget = mWidget;
00114   else {
00115     pWidget = new QWidget();
00116     bCleanUp = PR_TRUE;
00117   }
00118 
00119   nsresult ignore;
00120   nsCOMPtr<nsIScreenManager> sm(do_GetService("@mozilla.org/gfx/screenmanager;1",
00121                                               &ignore));
00122   if (sm) {
00123     nsCOMPtr<nsIScreen> screen;
00124     sm->GetPrimaryScreen(getter_AddRefs(screen));
00125     if (screen) {
00126       PRInt32 x,y,width,height,depth;
00127 
00128       screen->GetAvailRect(&x,&y,&width,&height);
00129       screen->GetPixelDepth(&depth);
00130       mWidthFloat = float(width);
00131       mHeightFloat = float(height);
00132       mDepth = NS_STATIC_CAST(PRUint32,depth);
00133     }
00134   }
00135 
00136   if (!mDpi) {
00137     // Set prefVal the value of the preference "layout.css.dpi"
00138     // or -1 if we can't get it.
00139     // If it's negative, we pretend it's not set.
00140     // If it's 0, it means force use of the operating system's logical resolution.
00141     // If it's positive, we use it as the logical resolution
00142     PRInt32 prefVal = -1;
00143     nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
00144     if (prefBranch) {
00145       nsresult res = prefBranch->GetIntPref("layout.css.dpi",
00146                                             &prefVal);
00147       if (NS_FAILED(res)) {
00148         prefVal = -1;
00149       }
00150       nsCOMPtr<nsIPrefBranch2> pbi(do_QueryInterface(prefBranch));
00151       pbi->AddObserver("layout.css.dpi", this, PR_FALSE);
00152     }
00153 
00154     SetDPI(prefVal);
00155   } else {
00156     SetDPI(mDpi);
00157   }
00158 
00159 #ifdef MOZ_LOGGING
00160   static PRBool once = PR_TRUE;
00161   if (once) {
00162     PR_LOG(gQtLogModule, QT_BASIC, ("GFX: dpi=%d t2p=%g p2t=%g depth=%d\n",
00163            mDpi,mTwipsToPixels,mPixelsToTwips,mDepth));
00164     once = PR_FALSE;
00165   }
00166 #endif
00167 
00168   QStyle &style = pWidget->style();
00169   mScrollbarWidth = mScrollbarHeight = style.pixelMetric(QStyle::PM_ScrollBarExtent);
00170 
00171   DeviceContextImpl::CommonInit();
00172 
00173   if (bCleanUp)
00174     delete pWidget;
00175   return NS_OK;
00176 }
00177 
00178 NS_IMETHODIMP
00179 nsDeviceContextQt::CreateRenderingContext(nsIRenderingContext *&aContext)
00180 {
00181   nsresult rv;
00182   nsDrawingSurfaceQt *surf;
00183   QPaintDevice *pDev = nsnull;
00184 
00185   if (mWidget)
00186     pDev = (QPaintDevice*)mWidget;
00187 
00188   // to call init for this, we need to have a valid nsDrawingSurfaceQt created
00189   nsCOMPtr<nsRenderingContextQt> pContext( new nsRenderingContextQt() );
00190 
00191   // create the nsDrawingSurfaceQt
00192   surf = new nsDrawingSurfaceQt();
00193 
00194   if (surf) {
00195     //Handled by the nsDrawingSurfaceQt
00196     //FIXME: instead of passing it around
00197     //       create it in the nsDrawingSurface init method
00198     QPainter *gc = new QPainter();
00199 
00200     // init the nsDrawingSurfaceQt
00201     if (pDev)
00202       rv = surf->Init(pDev,gc);
00203     else
00204       rv = surf->Init(gc,10,10,0);
00205 
00206     if (NS_SUCCEEDED(rv))
00207       // Init the nsRenderingContextQt
00208       rv = pContext->Init(this,surf);
00209   }
00210   else
00211     rv = NS_ERROR_OUT_OF_MEMORY;
00212 
00213   if (NS_SUCCEEDED(rv)) {
00214     aContext = pContext;
00215     NS_ADDREF(aContext);
00216   }
00217   return rv;
00218 }
00219 
00220 
00221 NS_IMETHODIMP nsDeviceContextQt::CreateRenderingContextInstance(nsIRenderingContext *&aContext)
00222 {
00223   return CreateRenderingContext(aContext);
00224 }
00225 
00226 NS_IMETHODIMP
00227 nsDeviceContextQt::SupportsNativeWidgets(PRBool &aSupportsWidgets)
00228 {
00229   //XXX it is very critical that this not lie!! MMP
00230   // read the comments in the mac code for this
00231   // ##############
00232   aSupportsWidgets = PR_TRUE;
00233 
00234   return NS_OK;
00235 }
00236 
00237 NS_IMETHODIMP nsDeviceContextQt::GetScrollBarDimensions(float &aWidth,
00238                                                         float &aHeight) const
00239 {
00240   float scale;
00241   GetCanonicalPixelScale(scale);
00242   aWidth = mScrollbarWidth * mPixelsToTwips * scale;
00243   aHeight = mScrollbarHeight * mPixelsToTwips * scale;
00244 
00245   return NS_OK;
00246 }
00247 
00248 NS_IMETHODIMP
00249 nsDeviceContextQt::GetSystemFont(nsSystemFontID anID, nsFont *aFont) const
00250 {
00251   nsresult    status      = NS_OK;
00252 
00253   switch (anID) {
00254     case eSystemFont_Caption:
00255     case eSystemFont_Icon:
00256     case eSystemFont_Menu:
00257     case eSystemFont_MessageBox:
00258     case eSystemFont_SmallCaption:
00259     case eSystemFont_StatusBar:
00260     case eSystemFont_Window:                   // css3
00261     case eSystemFont_Document:
00262     case eSystemFont_Workspace:
00263     case eSystemFont_Desktop:
00264     case eSystemFont_Info:
00265     case eSystemFont_Dialog:
00266     case eSystemFont_Button:
00267     case eSystemFont_PullDownMenu:
00268     case eSystemFont_List:
00269     case eSystemFont_Field:
00270     case eSystemFont_Tooltips:
00271     case eSystemFont_Widget:
00272       status = GetSystemFontInfo(aFont);
00273       break;
00274   }
00275   return status;
00276 }
00277 
00278 NS_IMETHODIMP nsDeviceContextQt::CheckFontExistence(const nsString& aFontName)
00279 {
00280   QString family = QString::fromUcs2(aFontName.get());
00281   QStringList families = QFontDatabase().families();
00282   return families.find(family) != families.end();
00283 }
00284 
00285 NS_IMETHODIMP nsDeviceContextQt::GetDeviceSurfaceDimensions(PRInt32 &aWidth,
00286                                                             PRInt32 &aHeight)
00287 {
00288   if (-1 == mWidth)
00289     mWidth =  NSToIntRound(mWidthFloat * mDevUnitsToAppUnits);
00290 
00291   if (-1 == mHeight)
00292     mHeight =  NSToIntRound(mHeightFloat * mDevUnitsToAppUnits);
00293 
00294   aWidth = mWidth;
00295   aHeight = mHeight;
00296 
00297   return NS_OK;
00298 }
00299 
00300 NS_IMETHODIMP nsDeviceContextQt::GetRect(nsRect &aRect)
00301 {
00302   PRInt32 width,height;
00303   nsresult rv;
00304 
00305   rv = GetDeviceSurfaceDimensions(width,height);
00306   aRect.x = 0;
00307   aRect.y = 0;
00308   aRect.width = width;
00309   aRect.height = height;
00310 
00311   return rv;
00312 }
00313 
00314 NS_IMETHODIMP nsDeviceContextQt::GetClientRect(nsRect &aRect)
00315 {
00316   return GetRect(aRect);
00317 }
00318 
00319 NS_IMETHODIMP nsDeviceContextQt::GetDeviceContextFor(nsIDeviceContextSpec *aDevice,
00320                                                      nsIDeviceContext *&aContext)
00321 {
00322   nsresult                 rv;
00323   PrintMethod              method;
00324   nsDeviceContextSpecQt   *spec = NS_STATIC_CAST(nsDeviceContextSpecQt *, aDevice);
00325 
00326   rv = spec->GetPrintMethod(method);
00327   if (NS_FAILED(rv))
00328     return rv;
00329 
00330 #ifdef USE_XPRINT
00331   if (method == pmXprint) { // XPRINT
00332     static NS_DEFINE_CID(kCDeviceContextXp, NS_DEVICECONTEXTXP_CID);
00333     nsCOMPtr<nsIDeviceContextXp> dcxp(do_CreateInstance(kCDeviceContextXp, &rv));
00334     NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create Xp Device context.");
00335     if (NS_FAILED(rv))
00336       return rv;
00337 
00338     rv = dcxp->SetSpec(aDevice);
00339     if (NS_FAILED(rv))
00340       return rv;
00341 
00342     rv = dcxp->InitDeviceContextXP((nsIDeviceContext*)aContext,
00343                                    (nsIDeviceContext*)this);
00344     if (NS_FAILED(rv))
00345       return rv;
00346 
00347     rv = dcxp->QueryInterface(NS_GET_IID(nsIDeviceContext),
00348                               (void **)&aContext);
00349     return rv;
00350   }
00351   else
00352 #endif /* USE_XPRINT */
00353 #ifdef USE_POSTSCRIPT
00354   if (method == pmPostScript) { // PostScript
00355     // default/PS
00356     static NS_DEFINE_CID(kCDeviceContextPS, NS_DEVICECONTEXTPS_CID);
00357 
00358     // Create a Postscript device context
00359     nsCOMPtr<nsIDeviceContextPS> dcps(do_CreateInstance(kCDeviceContextPS, &rv));
00360     NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create PS Device context.");
00361     if (NS_FAILED(rv))
00362       return rv;
00363 
00364     rv = dcps->SetSpec(aDevice);
00365     if (NS_FAILED(rv))
00366       return rv;
00367 
00368     rv = dcps->InitDeviceContextPS((nsIDeviceContext*)aContext,
00369                                    (nsIDeviceContext*)this);
00370     if (NS_FAILED(rv))
00371       return rv;
00372 
00373     rv = dcps->QueryInterface(NS_GET_IID(nsIDeviceContext),
00374                               (void **)&aContext);
00375     return rv;
00376   }
00377 #endif /* USE_POSTSCRIPT */
00378 
00379   NS_WARNING("no print module created.");
00380   return NS_ERROR_UNEXPECTED;
00381 }
00382 
00383 NS_IMETHODIMP nsDeviceContextQt::BeginDocument(PRUnichar * /*aTitle*/,
00384                                                PRUnichar* /*aPrintToFileName*/,
00385                                                PRInt32 /*aStartPage*/,
00386                                                PRInt32 /*aEndPage*/)
00387 {
00388   return NS_OK;
00389 }
00390 
00391 NS_IMETHODIMP nsDeviceContextQt::EndDocument(void)
00392 {
00393   return NS_OK;
00394 }
00395 
00396 NS_IMETHODIMP nsDeviceContextQt::BeginPage(void)
00397 {
00398   return NS_OK;
00399 }
00400 
00401 NS_IMETHODIMP nsDeviceContextQt::EndPage(void)
00402 {
00403   return NS_OK;
00404 }
00405 
00406 NS_IMETHODIMP nsDeviceContextQt::GetDepth(PRUint32& aDepth)
00407 {
00408   aDepth = mDepth;
00409   return NS_OK;
00410 }
00411 
00412 nsresult nsDeviceContextQt::SetDPI(PRInt32 aDpi)
00413 {
00414   // Set OSVal to what the operating system thinks the logical resolution is.
00415   PRInt32 OSVal = 0;
00416 
00417   QWidget *pDev = mWidget;
00418   if (!pDev) {
00419     QWidgetList *wlist = QApplication::allWidgets();
00420     pDev = wlist->first();
00421     qDebug("number of widgets is %d", wlist->count() );
00422     delete wlist;
00423   }
00424 
00425   QPaintDeviceMetrics qPaintMetrics(pDev);
00426   OSVal = qPaintMetrics.logicalDpiX();
00427 
00428 
00429 #ifdef DEBUG
00430   if (!pDev)
00431     qDebug("nsDeviceContextQt::SetDPI called without widget (find cleaner solution)");
00432 #endif
00433 
00434   if (aDpi > 0) {
00435     // If there's a valid pref value for the logical resolution,
00436     // use it.
00437     mDpi = aDpi;
00438   }
00439   else if (aDpi == 0 || OSVal > 96) {
00440     // Either if the pref is 0 (force use of OS value) or the OS
00441     // value is bigger than 96, use the OS value.
00442     mDpi = OSVal;
00443   }
00444   else {
00445     // if we couldn't get the pref or it's negative, and the OS
00446     // value is under 96ppi, then use 96.
00447     mDpi = 96;
00448   }
00449 
00450   int pt2t = 72;
00451 
00452   // make p2t a nice round number - this prevents rounding problems
00453   mPixelsToTwips = float(NSToIntRound(float(NSIntPointsToTwips(pt2t)) / float(aDpi)));
00454   mTwipsToPixels = 1.0f / mPixelsToTwips;
00455 
00456   // XXX need to reflow all documents
00457 
00458   return NS_OK;
00459 }
00460 
00461 NS_IMETHODIMP
00462 nsDeviceContextQt::Observe(nsISupports* aSubject, const char* aTopic,
00463                            const PRUnichar* aData)
00464 {
00465   if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) != 0) {
00466     // Our local observer only handles pref changes.
00467     // Forward everything else to our super class.
00468     return DeviceContextImpl::Observe(aSubject, aTopic, aData);
00469   }
00470 
00471   nsCOMPtr<nsIPrefBranch> prefBranch(do_QueryInterface(aSubject));
00472   NS_ASSERTION(prefBranch,
00473                "All pref change observer subjects implement nsIPrefBranch");
00474   nsCAutoString prefName(NS_LossyConvertUCS2toASCII(aData).get());
00475 
00476   if (prefName.Equals(NS_LITERAL_CSTRING("layout.css.dpi"))) {
00477     PRInt32 dpi;
00478     nsresult rv = prefBranch->GetIntPref(prefName.get(), &dpi);
00479     if (NS_SUCCEEDED(rv))
00480       SetDPI(dpi);
00481     return NS_OK;
00482   } else
00483     return DeviceContextImpl::Observe(aSubject, aTopic, aData);
00484 }
00485 
00486 nsresult
00487 nsDeviceContextQt::GetSystemFontInfo(nsFont* aFont) const
00488 {
00489   nsresult status = NS_OK;
00490   int rawWeight;
00491   QFont theFont = QApplication::font();
00492   QFontInfo theFontInfo(theFont);
00493 
00494   aFont->style       = NS_FONT_STYLE_NORMAL;
00495   aFont->weight      = NS_FONT_WEIGHT_NORMAL;
00496   aFont->decorations = NS_FONT_DECORATION_NONE;
00497   aFont->name.Assign(theFontInfo.family().ucs2());
00498   if (theFontInfo.bold()) {
00499     aFont->weight = NS_FONT_WEIGHT_BOLD;
00500   }
00501   rawWeight = theFontInfo.pixelSize();
00502   aFont->size = NSIntPixelsToTwips(rawWeight,mPixelsToTwips);
00503   if (theFontInfo.italic()) {
00504     aFont->style = NS_FONT_STYLE_ITALIC;
00505   }
00506   if (theFontInfo.underline()) {
00507     aFont->decorations = NS_FONT_DECORATION_UNDERLINE;
00508   }
00509 
00510   return (status);
00511 }