Back to index

lightning-sunbird  0.9+nobinonly
nsXPrintContext.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; 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  *   Roland Mainz <roland.mainz@nrubsig.org>
00024  *   Leon Sha <leon.sha@sun.com>
00025  *   Julien Lafon <julien.lafon@gmail.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /* Note: Sun Workshop 6 may have problems when mixing <string,h> 
00042  * and X includes. This was fixed by recent Xsun patches which 
00043  * are part of the "recommended patches" for Solaris. 
00044  * See bug 88703...
00045  */
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <errno.h>
00049 #include <string.h> /* for strerror & memset */
00050 
00051 #ifdef MOZ_LOGGING
00052 #define FORCE_PR_LOG 1 /* Allow logging in the release build */
00053 #endif /* MOZ_LOGGING */
00054 #include "prlog.h"
00055 
00056 #include "imgScaler.h"
00057 #include "nsXPrintContext.h"
00058 #include "nsDeviceContextXP.h"
00059 #include "xprintutil.h"
00060 #include "prenv.h" /* for PR_GetEnv */
00061 #include "prprf.h"
00062 #include "plstr.h"
00063 #include "nsPrintfCString.h"
00064 #include "nsIServiceManager.h" 
00065 #include "nsIEnvironment.h"
00066  
00067 /* NS_XPRINT_RGB_DITHER: Macro to check whether we should dither or not.
00068  * In theory we only have to look at the visual and depth ("TrueColor" with 
00069  * enougth bits for the colors or GrayScale/StaticGray with enougth bits for
00070  * the grayscale shades).
00071  * In real life some Xprt DDX do not have the GrayScale/StaticGray visuals and
00072  * we emulate grayscale support with a PseudoColor visual+grayscale palette
00073  * (that's why we test for |mIsGrayscale| explicitly)...
00074  */
00075 #define NS_XPRINT_RGB_DITHER \
00076     (((mDepth >  12 && mVisual->c_class==TrueColor)  || \
00077       (mDepth >=  7 && mVisual->c_class==GrayScale)  || \
00078       (mDepth >=  7 && mVisual->c_class==StaticGray) || \
00079       (mIsGrayscale == PR_TRUE)) ?(XLIB_RGB_DITHER_NONE):(XLIB_RGB_DITHER_MAX))
00080 
00081 #ifdef PR_LOGGING 
00082 /* DEBUG: use 
00083  * % export NSPR_LOG_MODULES=nsXPrintContext:5 
00084  * to see these debug messages... 
00085  */
00086 static PRLogModuleInfo *nsXPrintContextLM = PR_NewLogModule("nsXPrintContext");
00087 #endif /* PR_LOGGING */
00088 
00089 PR_BEGIN_EXTERN_C
00090 static 
00091 int xerror_handler( Display *display, XErrorEvent *ev )
00092 {
00093     /* this should _never_ be happen... but if this happens - debug mode or not - scream !!! */
00094     char errmsg[80];
00095     XGetErrorText(display, ev->error_code, errmsg, sizeof(errmsg));
00096     fprintf(stderr, "nsGfxXprintModule: Warning (X Error) -  %s\n", errmsg);
00097     return 0;
00098 }
00099 PR_END_EXTERN_C
00100 
00104 nsXPrintContext::nsXPrintContext() :
00105   mXlibRgbHandle(nsnull),
00106   mPDisplay(nsnull),
00107   mScreen(nsnull),
00108   mVisual(nsnull),
00109   mDrawable(None),
00110   mGC(nsnull),
00111   mDepth(0),
00112   mPContext(None),
00113   mJobStarted(PR_FALSE),
00114   mIsGrayscale(PR_FALSE), /* default is color output */
00115   mIsAPrinter(PR_TRUE),   /* default destination is printer */
00116   mPrintFile(nsnull),
00117   mXpuPrintToFileHandle(nsnull),
00118   mPrintXResolution(0L),
00119   mPrintYResolution(0L),
00120   mContext(nsnull)
00121 {
00122   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::nsXPrintContext()\n"));
00123 }
00124 
00128 nsXPrintContext::~nsXPrintContext()
00129 {
00130   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::~nsXPrintContext()\n"));
00131  
00132   if (mPDisplay)
00133   {
00134     if (mJobStarted)
00135     {
00136       /* Clean-up if noone else did it yet... */
00137       AbortDocument();
00138     }
00139 
00140     if (mGC)
00141     {
00142       mGC->Release();
00143       mGC = nsnull;
00144     }
00145        
00146     if (mXlibRgbHandle)
00147     {
00148       xxlib_rgb_destroy_handle(mXlibRgbHandle);
00149       mXlibRgbHandle = nsnull;
00150     }
00151     
00152     XPU_TRACE(XpuClosePrinterDisplay(mPDisplay, mPContext));           
00153     mPDisplay = nsnull;
00154     mPContext = None;
00155   }
00156   
00157   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::~nsXPrintContext() done.\n"));
00158 }
00159 
00160 NS_IMPL_ISUPPORTS1(nsXPrintContext, nsIDrawingSurfaceXlib)
00161 
00162 
00163 static nsresult
00164 AlertBrokenXprt(Display *pdpy)
00165 {
00166   /* Check for broken Xprt
00167    * Xfree86 Xprt is the only known broken version of Xprt (see bug 120211
00168    * for a list of tested&working Xprt servers) ...
00169    * XXX: We should look at XVendorRelease(), too - but there is no feedback
00170    * from XFree86.org when this issue will be fixed... ;-(
00171    */
00172   if (!(strstr(XServerVendor(pdpy), "XFree86") /*&& XVendorRelease(pdpy) < 45000000L*/))
00173     return NS_OK;
00174 
00175   /* Bad version found... log the issue and show the dialog and warn the user... */
00176   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG,
00177          ("nsXPrintContext::AlertBrokenXprt: vendor: '%s', release=%ld\n",
00178           XServerVendor(pdpy), (long)XVendorRelease(pdpy)));
00179 
00180   /* Dialog disabled ? */
00181   if (PR_GetEnv("MOZILLA_XPRINT_DISABLE_BROKEN_XFREE86_WARNING") != nsnull)
00182     return NS_OK;
00183    
00184   return NS_ERROR_GFX_PRINTER_XPRINT_BROKEN_XPRT;
00185 }
00186 
00187 NS_IMETHODIMP 
00188 nsXPrintContext::Init(nsDeviceContextXp *dc, nsIDeviceContextSpecXp *aSpec)
00189 {
00190   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::Init()\n"));
00191   nsresult rv = NS_ERROR_FAILURE;
00192 
00193  
00194   unsigned short      width,
00195                       height;
00196   XRectangle          rect;
00197   const char         *colorspace; 
00198   XpuColorspaceList   cslist;
00199   int                 cscount;
00200   XpuColorspaceRec   *cs;
00201   VisualID            csvid;
00202   int                 cs_class;
00203 
00204   if (NS_FAILED(XPU_TRACE(rv = SetupPrintContext(aSpec))))
00205     return rv;
00206 
00207   mScreen = XpGetScreenOfContext(mPDisplay, mPContext);
00208   mScreenNumber = XScreenNumberOfScreen(mScreen);
00209 
00210   /* Convert colorspace name into visualid */
00211   aSpec->GetColorspace(&colorspace);
00212   cslist = XpuGetColorspaceList(mPDisplay, mPContext, &cscount);
00213   if (!cslist) {
00214     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuGetColorspaceList() failed.\n"));
00215     return NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED;
00216   }
00217   cs = XpuFindColorspaceByName(cslist, cscount, colorspace);
00218   if (!cs) {
00219     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuFindColorspaceByName() failed.\n"));
00220     XpuFreeColorspaceList(cslist);
00221     return NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED;
00222   }
00223   csvid    = cs->visualinfo.visualid;
00224   cs_class = cs->visualinfo.c_class;
00225   XpuFreeColorspaceList(cslist);
00226 
00227   XlibRgbArgs xargs;
00228   memset(&xargs, 0, sizeof(xargs));
00229   xargs.handle_name           = nsnull;
00230   xargs.disallow_image_tiling = True; /* XlibRGB's "Image tiling"-hack is 
00231                                        * incompatible to Xprint API */
00232   
00233   if (mIsGrayscale)
00234   {
00235     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("printing grayscale\n"));
00236 
00237     /* This is compliciated: Older versions of Xprt do not always have 
00238      * Grayscale/StaticGray visual for a chosen printer so we only use
00239      * the selected visual when it really represents gray color values.
00240      * If the selected visual does not match that requirement we jump
00241      * into an "emulation" codepath which tries to find a visual which
00242      * matches the requirement for grayscale or b/w output */
00243     if ((cs_class | GrayScale) == GrayScale)
00244     {
00245       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("using selected gray visual\n"));
00246       xargs.xtemplate_mask     = VisualIDMask;
00247       xargs.xtemplate.visualid = csvid;
00248       mXlibRgbHandle = xxlib_rgb_create_handle(mPDisplay, mScreen, &xargs);
00249     }
00250     else
00251     { 
00252       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("using fallback codepath\n"));
00253       /* 1st attempt using GrayScale */
00254       xargs.xtemplate.c_class = StaticGray;
00255       xargs.xtemplate.depth   = 8;
00256       xargs.xtemplate_mask    = VisualClassMask|VisualDepthMask;
00257       mXlibRgbHandle = xxlib_rgb_create_handle(mPDisplay, mScreen, &xargs);             
00258 
00259       if (!mXlibRgbHandle)
00260       { 
00261         /* 2nd attempt using GrayScale */
00262         xargs.xtemplate.c_class = GrayScale;
00263         xargs.xtemplate.depth   = 8;
00264         xargs.xtemplate_mask    = VisualClassMask|VisualDepthMask;
00265         mXlibRgbHandle = xxlib_rgb_create_handle(mPDisplay, mScreen, &xargs);             
00266         if (!mXlibRgbHandle)
00267         {
00268           /* Last attempt: Emulate StaticGray via Pseudocolor colormap */
00269           xargs.xtemplate_mask  = 0L;
00270           xargs.xtemplate.depth = 0;
00271           xargs.pseudogray      = True;
00272           mXlibRgbHandle = xxlib_rgb_create_handle(mPDisplay, mScreen, &xargs);
00273         }
00274 
00275         if (!mXlibRgbHandle)
00276         {
00277           PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("trying black/white\n"));
00278 
00279           /* Last attempt using StaticGray 1bit (b/w printer) */
00280           xargs.xtemplate.c_class = StaticGray;
00281           xargs.xtemplate.depth   = 1;
00282           xargs.xtemplate_mask    = VisualClassMask|VisualDepthMask;
00283           xargs.pseudogray        = False;
00284           mXlibRgbHandle = xxlib_rgb_create_handle(mPDisplay, mScreen, &xargs);
00285         }
00286       }
00287     }  
00288   }
00289   else
00290   {
00291     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("printing color\n"));
00292     xargs.xtemplate_mask     = VisualIDMask;
00293     xargs.xtemplate.visualid = csvid;
00294     mXlibRgbHandle = xxlib_rgb_create_handle(mPDisplay, mScreen, &xargs);
00295   }
00296   
00297   /* No XlibRgb handle ? Either we do not have a matching visual or no memory... */
00298   if (!mXlibRgbHandle)
00299     return NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED;
00300 
00301   XpGetPageDimensions(mPDisplay, mPContext, &width, &height, &rect);
00302 
00303   rv = SetupWindow(rect.x, rect.y, rect.width, rect.height);
00304   if (NS_FAILED(rv))
00305     return rv;
00306 
00307   XMapWindow(mPDisplay, mDrawable); 
00308   
00309   mContext = dc;
00310     
00311   /* Set error handler and sync
00312    * ToDo: unset handler after all is done - what about handler "stacking" ?
00313    */
00314   (void)XSetErrorHandler(xerror_handler);
00315 
00316   /* only run unbuffered X11 connection on demand (for debugging/testing) */
00317   if( PR_GetEnv("MOZILLA_XPRINT_EXPERIMENTAL_SYNCHRONIZE") != nsnull )
00318   {
00319     XSynchronize(mPDisplay, True);
00320   }  
00321   
00322   return NS_OK;
00323 }
00324 
00325 NS_IMETHODIMP
00326 nsXPrintContext::GetDimensions(PRUint32 *aWidth, PRUint32 *aHeight)
00327 {
00328   *aWidth = mWidth;
00329   *aHeight = mHeight;
00330   return NS_OK;
00331 }
00332 
00333 NS_IMETHODIMP
00334 nsXPrintContext::IsOffscreen(PRBool *aOffScreen)
00335 {
00336   *aOffScreen = PR_FALSE;
00337   return NS_OK;
00338 }
00339 
00340 NS_IMETHODIMP
00341 nsXPrintContext::IsPixelAddressable(PRBool *aAddressable)
00342 {
00343   *aAddressable = PR_FALSE;
00344   return NS_OK;
00345 }
00346 
00347 NS_IMETHODIMP
00348 nsXPrintContext::GetPixelFormat(nsPixelFormat *aFormat)
00349 {
00350   *aFormat = mPixFormat;
00351   return NS_OK;
00352 }
00353 
00354 PRUint8 
00355 nsXPrintContext::GetShiftForMask(unsigned long val)
00356 {
00357   PRUint8 cur_bit = 0;
00358   // walk through the number, looking for the first 1
00359   while (cur_bit < (sizeof(unsigned long) * 8)) {
00360     if ((val >> cur_bit) & 0x1) {
00361       return cur_bit;
00362     }
00363     cur_bit++;
00364   }
00365   return cur_bit;
00366 }
00367 
00368 PRUint8 
00369 nsXPrintContext::ConvertMaskToCount(unsigned long val)
00370 {
00371   PRUint8 retval = 0;
00372   PRUint8 cur_bit = 0;
00373   // walk through the number, incrementing the value if
00374   // the bit in question is set.
00375   while (cur_bit < (sizeof(unsigned long) * 8)) {
00376     if ((val >> cur_bit) & 0x1) {
00377       retval++;
00378     }
00379     cur_bit++;
00380   }
00381   return retval;
00382 }
00383 
00384 
00385 nsresult
00386 nsXPrintContext::SetupWindow(int x, int y, int width, int height)
00387 {
00388   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG,
00389          ("nsXPrintContext::SetupWindow: x=%d y=%d width=%d height=%d\n",
00390          x, y, width, height));
00391 
00392   Window                 parent_win;
00393   XVisualInfo           *visual_info;
00394   XSetWindowAttributes   xattributes;
00395   long                   xattributes_mask;
00396   unsigned long          background,
00397                          foreground;
00398   
00399   mWidth  = width;
00400   mHeight = height;
00401 
00402   visual_info = xxlib_rgb_get_visual_info(mXlibRgbHandle);
00403   mVisual     = xxlib_rgb_get_visual(mXlibRgbHandle);
00404   mDepth      = xxlib_rgb_get_depth(mXlibRgbHandle);
00405   
00406   mPixFormat.mRedMask    = visual_info->red_mask;
00407   mPixFormat.mGreenMask  = visual_info->green_mask;
00408   mPixFormat.mBlueMask   = visual_info->blue_mask;
00409   mPixFormat.mAlphaMask  = 0;
00410   mPixFormat.mRedCount   = ConvertMaskToCount(visual_info->red_mask);
00411   mPixFormat.mGreenCount = ConvertMaskToCount(visual_info->green_mask);
00412   mPixFormat.mBlueCount  = ConvertMaskToCount(visual_info->blue_mask);
00413   mPixFormat.mAlphaCount = 0;
00414   mPixFormat.mRedShift   = GetShiftForMask(visual_info->red_mask);
00415   mPixFormat.mGreenShift = GetShiftForMask(visual_info->green_mask);
00416   mPixFormat.mBlueShift  = GetShiftForMask(visual_info->blue_mask);
00417   mPixFormat.mAlphaShift = 0;
00418 
00419   background = xxlib_rgb_xpixel_from_rgb(mXlibRgbHandle, NS_TO_XXLIB_RGB(NS_RGB(0xFF, 0xFF, 0xFF))); /* white */
00420   foreground = xxlib_rgb_xpixel_from_rgb(mXlibRgbHandle, NS_TO_XXLIB_RGB(NS_RGB(0x00, 0x00, 0x00))); /* black */
00421   parent_win = XRootWindow(mPDisplay, mScreenNumber);                                         
00422                                              
00423   xattributes.background_pixel = background;
00424   xattributes.border_pixel     = foreground;
00425   xattributes.colormap         = xxlib_rgb_get_cmap(mXlibRgbHandle);
00426   xattributes_mask             = CWBorderPixel | CWBackPixel;
00427   if( xattributes.colormap != None )
00428   {
00429     xattributes_mask |= CWColormap;
00430 
00431     /* XXX: Why do we need this ? See bug 80562 ("Xprint does not support any
00432      * other visuals than Xprt's default one..").*/
00433     if (mDepth > 12)
00434     {
00435       XInstallColormap(mPDisplay, xattributes.colormap);
00436     }  
00437   }
00438 
00439   mDrawable = (Drawable)XCreateWindow(mPDisplay, parent_win, x, y,
00440                                       width, height, 0,
00441                                       mDepth, InputOutput, mVisual, xattributes_mask,
00442                                       &xattributes);
00443 
00444   /* %p would be better instead of %lx for pointers - but does PR_LOG() support that ? */
00445   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG,
00446          ("nsXPrintContext::SetupWindow: mVisual->visualid=%x, mVisual->c_class=%x, mDepth=%d, mScreenNumber=%d, colormap=%lx, mDrawable=%lx\n",
00447          (int)mVisual->visualid, (int)mVisual->c_class, (int)mDepth, (int)mScreenNumber, (long)xattributes.colormap, (long)mDrawable));
00448          
00449   return NS_OK;
00450 }
00451 
00452 
00453 nsresult nsXPrintContext::SetMediumSize(const char *aPaperName)
00454 {
00455   nsresult                rv = NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED;
00456   XpuMediumSourceSizeList mlist;
00457   int                     mlist_count;
00458   int                     i;
00459   char                   *paper_name,
00460                          *alloc_paper_name; /* for free() ... */
00461   paper_name = alloc_paper_name = strdup(aPaperName);
00462   if (!paper_name)
00463     return NS_ERROR_OUT_OF_MEMORY;
00464   
00465   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("SetMediumSize: Requested page '%s'\n", paper_name));
00466 
00467   mlist = XpuGetMediumSourceSizeList(mPDisplay, mPContext, &mlist_count);
00468   if( !mlist )
00469   {
00470     return NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED;
00471   }
00472 
00473   XpuMediumSourceSizeRec *match = nsnull;
00474 
00475 #ifdef PR_LOGGING 
00476   /* Print page sizes for the log... */
00477   for( i = 0 ; i < mlist_count ; i++ )
00478   {
00479     XpuMediumSourceSizeRec *curr = &mlist[i];
00480     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("got '%s'/'%s'\t%d %f %f %f %f\n", 
00481            XPU_NULLXSTR(curr->tray_name), curr->medium_name, curr->mbool, 
00482            curr->ma1, curr->ma2, curr->ma3, curr->ma4));
00483   }
00484 #endif /* PR_LOGGING */
00485 
00486   char *s;
00487   
00488   /* Did we get a tray name and paper name (e.g. "manual/din-a4") ? */
00489   if ((s = strchr(paper_name, '/')) != nsnull)
00490   {
00491     const char *tray_name;
00492     *s = '\0';
00493     tray_name  = paper_name;
00494     paper_name = s+1;
00495     
00496     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("SetMediumSize: searching for '%s'/'%s'\n", tray_name, paper_name));
00497     match = XpuFindMediumSourceSizeByName(mlist, mlist_count, tray_name, paper_name);
00498   }
00499   else
00500   {
00501     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("SetMediumSize: searching for '%s'\n", paper_name));
00502     match = XpuFindMediumSourceSizeByName(mlist, mlist_count, nsnull, paper_name);
00503   }
00504   
00505   /* Found a match ? */
00506   if (match)
00507   {
00508     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG,
00509            ("match '%s'/'%s' !\n", XPU_NULLXSTR(match->tray_name), match->medium_name));
00510            
00511     /* Set document's paper size */
00512     if( XpuSetDocMediumSourceSize(mPDisplay, mPContext, match) == 1 )
00513       rv = NS_OK;  
00514   }
00515   
00516   XpuFreeMediumSourceSizeList(mlist);
00517   free(alloc_paper_name);
00518   
00519   return rv;
00520 }
00521 
00522 nsresult nsXPrintContext::SetOrientation(int landscape)
00523 {
00524   const char         *orientation;
00525   XpuOrientationList  list;
00526   int                 list_count;
00527   XpuOrientationRec  *match;
00528 
00529   /* which orientation ? */
00530   switch( landscape )
00531   {
00532     case 1 /* NS_LANDSCAPE */: orientation = "landscape"; break;
00533     case 0 /* NS_PORTRAIT */:  orientation = "portrait";  break;
00534     default:  
00535       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
00536              ("Unsupported orientation %d.\n", landscape));  
00537       return NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED;
00538   }
00539   
00540   /* Print the used orientation to the log... */
00541   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("orientation=%s\n", orientation));    
00542 
00543   /* Get list of supported orientations */
00544   list = XpuGetOrientationList(mPDisplay, mPContext, &list_count);
00545   if( !list )
00546   {
00547     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuGetOrientationList() failure.\n"));  
00548     return NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED;
00549   }
00550 
00551 #ifdef PR_LOGGING 
00552   int i;
00553   /* Print orientations for the log... */
00554   for( i = 0 ; i < list_count ; i++ )
00555   {
00556     XpuOrientationRec *curr = &list[i];
00557     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("got orientation='%s'\n", curr->orientation));
00558   }
00559 #endif /* PR_LOGGING */
00560 
00561   /* Find requested orientation */
00562   match = XpuFindOrientationByName(list, list_count, orientation);
00563   if (!match)
00564   {
00565     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuFindOrientationByName() failure.\n"));  
00566     XpuFreeOrientationList(list);
00567     return NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED;
00568   }
00569 
00570   /* Set orientation */
00571   if (XpuSetDocOrientation(mPDisplay, mPContext, match) != 1)
00572   {
00573     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuSetDocOrientation() failure.\n"));  
00574     
00575     /* We have a "match" in the list of supported orientations but we are not
00576      * allowed to set it... Well - if this happens and we only have ONE entry
00577      * in this list then we can safely assume that this is the only choice...
00578      * (please correct me if I am wrong) 
00579      */
00580     if (list_count != 1)
00581     {
00582       /* ... otherwise we have a problem... */
00583       XpuFreeOrientationList(list);
00584       return NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED;
00585     }
00586   }
00587   
00588   XpuFreeOrientationList(list);
00589 
00590   return NS_OK;
00591 }
00592 
00593 nsresult nsXPrintContext::SetPlexMode(const char *plexname)
00594 {
00595   XpuPlexList  list;
00596   int          list_count;
00597   XpuPlexRec  *match;
00598 
00599   /* Print the used plex name to the log... */
00600   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("plexname=%s\n", plexname));    
00601 
00602   /* Get list of supported plex modes */
00603   list = XpuGetPlexList(mPDisplay, mPContext, &list_count);
00604   if( !list )
00605   {
00606     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuGetPlexList() failure.\n"));  
00607     return NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED;
00608   }
00609 
00610 #ifdef PR_LOGGING 
00611   int i;
00612   /* Print plex modes for the log... */
00613   for( i = 0 ; i < list_count ; i++ )
00614   {
00615     XpuPlexRec *curr = &list[i];
00616     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("got plex='%s'\n", curr->plex));
00617   }
00618 #endif /* PR_LOGGING */
00619 
00620   /* Find requested plex mode */
00621   match = XpuFindPlexByName(list, list_count, plexname);
00622   if (!match)
00623   {
00624     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuFindPlexByName() failure.\n"));  
00625     XpuFreePlexList(list);
00626     return NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED;
00627   }
00628 
00629   /* Set plex */
00630   if (XpuSetDocPlex(mPDisplay, mPContext, match) != 1)
00631   {
00632     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuSetDocPlex() failure.\n"));  
00633     
00634     /* We have a "match" in the list of supported plex modes but we are not
00635      * allowed to set it... Well - if this happens and we only have ONE entry
00636      * in this list then we can safely assume that this is the only choice...
00637      * (please correct me if I am wrong) 
00638      */
00639     if (list_count != 1)
00640     {
00641       /* ... otherwise we have a problem... */
00642       XpuFreePlexList(list);
00643       return NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED;
00644     }
00645   }
00646   
00647   XpuFreePlexList(list);
00648 
00649   return NS_OK;
00650 }
00651 
00652 
00653 nsresult
00654 nsXPrintContext::SetupPrintContext(nsIDeviceContextSpecXp *aSpec)
00655 {
00656   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::SetupPrintContext()\n"));
00657   
00658   float        top, bottom, left, right;
00659   int          landscape;
00660   int          num_copies;
00661   const char  *printername;
00662   nsresult     rv;
00663 
00664   nsCOMPtr<nsIEnvironment> uEnv = do_GetService("@mozilla.org/process/environment;1", &rv);
00665   if (NS_FAILED(rv))
00666     return rv;
00667 
00668   // Get the Attributes
00669   aSpec->GetToPrinter(mIsAPrinter);
00670   aSpec->GetGrayscale(mIsGrayscale);
00671   aSpec->GetTopMargin(top);
00672   aSpec->GetBottomMargin(bottom);
00673   aSpec->GetLeftMargin(left);
00674   aSpec->GetRightMargin(right);
00675   aSpec->GetLandscape(landscape);
00676   aSpec->GetCopies(num_copies);
00677   
00678   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
00679          ("nsXPrintContext::SetupPrintContext: borders top=%f, bottom=%f, left=%f, right=%f\n", 
00680          top, bottom, left, right));
00681 
00682   /* get destination printer (we need this when printing to file as
00683    * the printer DDX in Xprt generates the data...) 
00684    */
00685   aSpec->GetPrinterName(&printername);
00686   
00687   /* Are we "printing" to a file instead to the print queue ? */
00688   if (!mIsAPrinter) 
00689   {
00690     /* ToDo: Guess a matching file extension of user did not set one - Xprint 
00691      * currrently may use %s.ps, %s.pcl, %s.xwd, %s.pdf etc.
00692      * Best idea would be to ask a "datatyping" service (like CDE's datatyping 
00693      * functions) what to-do...
00694      */
00695     aSpec->GetPath(&mPrintFile);
00696 
00697     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("print to file '%s'\n", XPU_NULLXSTR(mPrintFile)));
00698     
00699     if(!mPrintFile || !*mPrintFile)
00700       return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
00701   }
00702 
00703   /* workaround for crash in XCloseDisplay() on Solaris 2.7 Xserver - when 
00704    * shared memory transport is used XCloseDisplay() tries to free() the 
00705    * shared memory segment - causing heap corruption and/or SEGV.
00706    */
00707   uEnv->Set(NS_LITERAL_STRING("XSUNTRANSPORT"), NS_LITERAL_STRING("xxx"));
00708      
00709   /* Get printer, either by "name" (foobar) or "name@display" (foobar@gaja:5) */
00710   if( XpuGetPrinter(printername, &mPDisplay, &mPContext) != 1 )
00711     return NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
00712 
00713   /* Remember the last used printer as new "default" printer as long this
00714    * Mozilla instance is running */
00715   uEnv->Set(NS_LITERAL_STRING("XPRINTER"), NS_ConvertUTF8toUCS2(printername));
00716 
00717   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
00718          ("nsXPrintContext::SetupPrintContext: name='%s', display='%s', vendor='%s', release=%ld\n",
00719           printername,
00720           XDisplayString(mPDisplay), 
00721           XServerVendor(mPDisplay),
00722           (long)XVendorRelease(mPDisplay)));
00723           
00724   if (NS_FAILED(rv = AlertBrokenXprt(mPDisplay)))
00725     return rv;
00726     
00727   if( XpQueryExtension(mPDisplay, &mXpEventBase, &mXpErrorBase) == False )
00728     return NS_ERROR_UNEXPECTED;
00729     
00730 #ifdef XPRINT_DEBUG_SOMETIMES_USEFULL
00731   dumpXpAttributes(mPDisplay, mPContext);
00732 #endif /* XPRINT_DEBUG_SOMETIMES_USEFULL */
00733   
00734   const char *paper_name      = nsnull,
00735              *plex_name       = nsnull,
00736              *resolution_name = nsnull;
00737   PRBool      downloadfonts   = PR_TRUE;
00738   aSpec->GetPaperName(&paper_name);
00739   aSpec->GetPlexName(&plex_name);
00740   aSpec->GetResolutionName(&resolution_name);
00741   aSpec->GetDownloadFonts(downloadfonts);
00742   
00743   if (NS_FAILED(XPU_TRACE(rv = SetMediumSize(paper_name))))
00744     return rv;
00745   
00746   if (NS_FAILED(XPU_TRACE(rv = SetOrientation(landscape))))
00747     return rv;
00748 
00749   if (NS_FAILED(XPU_TRACE(rv = SetPlexMode(plex_name))))
00750     return rv;
00751     
00752   if (NS_FAILED(XPU_TRACE(rv = SetResolution(resolution_name))))
00753     return rv;
00754    
00755   if (XPU_TRACE(XpuSetDocumentCopies(mPDisplay, mPContext, num_copies)) != 1)
00756     return NS_ERROR_GFX_PRINTER_TOO_MANY_COPIES;
00757 
00758   if (XPU_TRACE(XpuSetEnableFontDownload(mPDisplay, mPContext, downloadfonts)) != 1)
00759     return NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR;
00760         
00761   /* set printer context
00762    * WARNING: after this point it is no longer allows to change job attributes
00763    * only after the XpSetContext() call the alllication is allowed to make 
00764    * assumptions about available fonts - otherwise you may get the wrong 
00765    * ones !!
00766    */
00767   XPU_TRACE(XpSetContext(mPDisplay, mPContext));
00768 
00769 #ifdef XPRINT_DEBUG_SOMETIMES_USEFULL
00770   dumpXpAttributes(mPDisplay, mPContext);
00771 #endif /* XPRINT_DEBUG_SOMETIMES_USEFULL */
00772 
00773   /* Get default printer resolution. May fail if Xprt is misconfigured.*/
00774   if( XpuGetResolution(mPDisplay, mPContext, &mPrintXResolution, &mPrintYResolution) != 1 )
00775     return NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR;
00776 
00777   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG,
00778          ("print resolution %ld%x%ld\n", mPrintXResolution, mPrintYResolution));
00779   
00780   /* We want to get events when Xp(Start|End)(Job|Page) requests are processed... */  
00781   XpSelectInput(mPDisplay, mPContext, XPPrintMask);  
00782 
00783   return NS_OK;
00784 }
00785 
00786 NS_IMETHODIMP
00787 nsXPrintContext::SetResolution(const char *resolution_name)
00788 {
00789   XpuResolutionList list;
00790   int               list_count;
00791   XpuResolutionRec *match;
00792   int               i;
00793   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::SetResolution('resolution_name=%s').\n", resolution_name));  
00794 
00795   list = XpuGetResolutionList(mPDisplay, mPContext, &list_count);
00796   if( !list )
00797     return NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR;
00798 
00799 #ifdef PR_LOGGING 
00800   /* Print resolutions for the log... */
00801   for( i = 0 ; i < list_count ; i++ )
00802   {
00803     XpuResolutionRec *curr = &list[i];
00804     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG,
00805            ("got resolution='%s'/%ldx%ld\n", curr->name, curr->x_dpi, curr->y_dpi));
00806   }
00807 #endif /* PR_LOGGING */
00808 
00809   /* Find requested resolution mode */
00810   match = XpuFindResolutionByName(list, list_count, resolution_name);
00811   if (!match)
00812   {
00813     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuFindResolutionByName() failure.\n"));  
00814     XpuFreeResolutionList(list);
00815     return NS_ERROR_GFX_PRINTER_RESOLUTION_NOT_SUPPORTED;
00816   } 
00817 
00818   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("setting resolution to '%s'/%ldx%ld DPI.\n", 
00819          match->name, match->x_dpi, match->y_dpi));  
00820     
00821   if (XpuSetDocResolution(mPDisplay, mPContext, match) != 1)
00822   {
00823     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuSetDocResolution() failure.\n"));
00824  
00825     /* We have a "match" in the list of supported resolutions but we are not
00826      * allowed to set it... Well - if this happens and we only have ONE entry
00827      * in this list then we can safely assume that this is the only choice...
00828      * (please correct me if I am wrong) 
00829      */
00830     if (list_count != 1)
00831     {
00832       /* ... otherwise we have a problem... */
00833       XpuFreeResolutionList(list);
00834       return NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR;
00835     }
00836   }
00837   
00838   XpuFreeResolutionList(list);
00839   
00840   return NS_OK;
00841 }
00842   
00843 NS_IMETHODIMP
00844 nsXPrintContext::BeginDocument( PRUnichar * aTitle, PRUnichar* aPrintToFileName, PRInt32 aStartPage, PRInt32 aEndPage )
00845 {
00846   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::BeginDocument(aTitle='%s')\n", ((aTitle)?(NS_ConvertUCS2toUTF8(aTitle).get()):("<NULL>"))));
00847   
00848   nsXPIDLCString job_title;
00849        
00850   if (aTitle)
00851   {
00852     /* Note that this is _only_ a _hack_ until bug 73446 
00853      * ("RFE: Need NS_ConvertUCS2ToLocalEncoding() and 
00854      * NS_ConvertLocalEncodingToUCS2()") is implemented...) */
00855     job_title.Assign(NS_ConvertUCS2toUTF8(aTitle));
00856   }
00857   else
00858   {
00859     job_title.AssignLiteral("Document without title");
00860   }
00861  
00862   /* Set the Job Attributes */
00863   XpuSetJobTitle(mPDisplay, mPContext, job_title);
00864   
00865   // Check the output type
00866   if(mIsAPrinter) 
00867   {
00868     XPU_TRACE(XpuStartJobToSpooler(mPDisplay));
00869   } 
00870   else 
00871   {   
00872     if( XPU_TRACE(mXpuPrintToFileHandle = XpuStartJobToFile(mPDisplay, mPContext, mPrintFile)) == nsnull )
00873     {
00874       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
00875              ("nsXPrintContext::BeginDocument(): XpuPrintToFile failure %s/(%d)\n", 
00876              strerror(errno), errno));
00877 
00878       return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
00879     }    
00880   } 
00881 
00882   XPU_TRACE(XpuWaitForPrintNotify(mPDisplay, mXpEventBase, XPStartJobNotify));
00883 
00884   mJobStarted = PR_TRUE;
00885   
00886   return NS_OK;
00887 }  
00888 
00889 NS_IMETHODIMP
00890 nsXPrintContext::BeginPage()
00891 {
00892   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::BeginPage()\n"));
00893    
00894   XPU_TRACE(XpStartPage(mPDisplay, mDrawable));
00895   XPU_TRACE(XpuWaitForPrintNotify(mPDisplay, mXpEventBase, XPStartPageNotify));
00896 
00897   return NS_OK;
00898 }
00899 
00900 NS_IMETHODIMP 
00901 nsXPrintContext::EndPage()
00902 {
00903   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::EndPage()\n"));
00904 
00905   XPU_TRACE(XpEndPage(mPDisplay));
00906   XPU_TRACE(XpuWaitForPrintNotify(mPDisplay, mXpEventBase, XPEndPageNotify));
00907   
00908   return NS_OK;
00909 }
00910 
00911 NS_IMETHODIMP 
00912 nsXPrintContext::EndDocument()
00913 {
00914   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::EndDocument()\n"));
00915 
00916   XPU_TRACE(XpEndJob(mPDisplay));
00917   XPU_TRACE(XpuWaitForPrintNotify(mPDisplay, mXpEventBase, XPEndJobNotify));
00918 
00919   /* Are we printing to a file ? */
00920   if( !mIsAPrinter )
00921   {
00922     NS_ASSERTION(nsnull != mXpuPrintToFileHandle, "mXpuPrintToFileHandle is null.");
00923     
00924     if( XPU_TRACE(XpuWaitForPrintFileChild(mXpuPrintToFileHandle)) == XPGetDocFinished )
00925     {
00926       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuWaitForPrintFileChild returned success.\n"));
00927     }
00928     else
00929     {
00930       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuWaitForPrintFileChild returned failure.\n"));
00931     }
00932     
00933     mXpuPrintToFileHandle = nsnull;
00934   }
00935 
00936   /*
00937    * end of spooled job - get spooler command results
00938    */
00939   const char *results,
00940              *lresults;
00941   results = XpGetOneAttribute(mPDisplay, mPContext, XPJobAttr,
00942                            "xp-spooler-command-results");
00943 
00944   if( results &&
00945       (strlen(results) != 0) )
00946   {
00947     lresults = XpuCompoundTextToXmb(mPDisplay, results);
00948   }
00949   else
00950   {
00951     lresults = NULL;
00952   }
00953   /* present spooler command results
00954    * TODO: Open a dialog and present the message there.
00955    */
00956   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG,
00957          ("Printing complete - spooler command result '%s'/'%s'\n",
00958          results  ? results  : "<no message>",
00959          lresults ? lresults : ""));
00960   if( lresults )
00961     XpuFreeXmbString(lresults);
00962 
00963   if( results )
00964     XFree((void *)results);
00965 
00966   mJobStarted = PR_FALSE;
00967     
00968   return NS_OK;
00969 }
00970 
00971 NS_IMETHODIMP 
00972 nsXPrintContext::AbortDocument()
00973 {
00974   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::AbortDocument()\n"));
00975 
00976   if( mJobStarted )
00977   {
00978     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("canceling...\n"));
00979     XPU_TRACE(XpCancelJob(mPDisplay, True));
00980   }  
00981 
00982   /* Are we printing to a file ? */
00983   if( !mIsAPrinter && mXpuPrintToFileHandle )
00984   {   
00985     if( XPU_TRACE(XpuWaitForPrintFileChild(mXpuPrintToFileHandle)) == XPGetDocFinished )
00986     {
00987       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuWaitForPrintFileChild returned success.\n"));
00988     }
00989     else
00990     {
00991       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("XpuWaitForPrintFileChild returned failure.\n"));
00992     }
00993 
00994     mXpuPrintToFileHandle = nsnull;
00995   }
00996 
00997   mJobStarted = PR_FALSE;
00998 
00999   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("print job aborted.\n"));
01000 
01001   return NS_OK;
01002 }
01003 
01004 static
01005 PRUint8 *ComposeAlphaImage(
01006                PRUint8 *alphaBits, PRInt32  alphaRowBytes, PRUint8 alphaDepth,
01007                PRUint8 *image_bits, PRInt32  row_bytes,
01008                PRInt32 aWidth, PRInt32 aHeight)
01009 {
01010   PRUint8 *composed_bits; /* composed image */
01011   if (!(composed_bits = (PRUint8 *)PR_Malloc(aHeight * row_bytes)))
01012     return nsnull;
01013 
01014 /* unfortunately this code does not work for some strange reason ... */
01015 #ifdef XPRINT_NOT_NOW
01016   XGCValues gcv;
01017   memset(&gcv, 0, sizeof(XGCValues)); /* this may be unneccesary */
01018   XGetGCValues(mPDisplay, *xgc, GCForeground, &gcv);
01019   
01020   /* should be replaced by xxlibrgb_query_color() */
01021   XColor color;
01022   color.pixel = gcv.foreground;
01023   XQueryColor(mPDisplay, xxlib_rgb_get_cmap(mXlibRgbHandle), &color);
01024   
01025   unsigned long background = NS_RGB(color.red>>8, color.green>>8, color.blue>>8);
01026 #else
01027   unsigned long background = NS_RGB(0xFF,0xFF,0xFF); /* white! */
01028 #endif /* XPRINT_NOT_NOW */
01029   long x, y;
01030     
01031   switch(alphaDepth)
01032   {
01033     case 1:
01034     {
01035 #define NS_GET_BIT(rowptr, x) (rowptr[(x)>>3] &  (1<<(7-(x)&0x7)))
01036         unsigned short r = NS_GET_R(background),
01037                        g = NS_GET_R(background),
01038                        b = NS_GET_R(background);
01039                      
01040         for(y = 0 ; y < aHeight ; y++)
01041         {
01042           unsigned char *imageRow  = image_bits    + y * row_bytes;
01043           unsigned char *destRow   = composed_bits + y * row_bytes;
01044           unsigned char *alphaRow  = alphaBits     + y * alphaRowBytes;
01045           for(x = 0 ; x < aWidth ; x++)
01046           {
01047             if(NS_GET_BIT(alphaRow, x))
01048             {
01049               /* copy src color */
01050               destRow[3*x  ] = imageRow[3*x  ];
01051               destRow[3*x+1] = imageRow[3*x+1];
01052               destRow[3*x+2] = imageRow[3*x+2];
01053             }
01054             else
01055             {
01056               /* copy background color (e.g. pixel is "transparent") */
01057               destRow[3*x  ] = r;
01058               destRow[3*x+1] = g;
01059               destRow[3*x+2] = b;
01060             }
01061           }
01062         }        
01063     }  
01064         break;
01065     case 8:
01066     {
01067         unsigned short r = NS_GET_R(background),
01068                        g = NS_GET_R(background),
01069                        b = NS_GET_R(background);
01070         
01071         for(y = 0 ; y < aHeight ; y++)
01072         {
01073           unsigned char *imageRow  = image_bits    + y * row_bytes;
01074           unsigned char *destRow   = composed_bits + y * row_bytes;
01075           unsigned char *alphaRow  = alphaBits     + y * alphaRowBytes;
01076           for(x = 0 ; x < aWidth ; x++)
01077           {
01078             unsigned short alpha = alphaRow[x];
01079             MOZ_BLEND(destRow[3*x  ], r, imageRow[3*x  ], alpha);
01080             MOZ_BLEND(destRow[3*x+1], g, imageRow[3*x+1], alpha);
01081             MOZ_BLEND(destRow[3*x+2], b, imageRow[3*x+2], alpha);
01082           }
01083         }
01084     }  
01085         break;
01086     default:
01087     {
01088         NS_WARNING("alpha depth x not supported");
01089         PR_Free(composed_bits);
01090         return nsnull;
01091     }  
01092         break;
01093   }
01094   
01095   return composed_bits;      
01096 }
01097 
01098 
01099 NS_IMETHODIMP
01100 nsXPrintContext::DrawImage(Drawable aDrawable, xGC *xgc, nsIImage *aImage,
01101                  PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
01102                  PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
01103 {
01104   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
01105          ("nsXPrintContext::DrawImage(%lx, %d/%d/%d/%d - %d/%d/%d/%d)\n",
01106           (long)aDrawable,
01107           (int)aSX, (int)aSY, (int)aSWidth, (int)aSHeight,
01108           (int)aDX, (int)aDY, (int)aDWidth, (int)aDHeight));
01109   
01110   double   scalingFactor;
01111   int      prev_res = 0,
01112            dummy;
01113   long     imageResolution;
01114   PRInt32  aDWidth_scaled,
01115            aDHeight_scaled;
01116   nsresult rv = NS_OK;
01117   
01118   PRInt32 aSrcWidth  = aImage->GetWidth();
01119   PRInt32 aSrcHeight = aImage->GetHeight();
01120   
01121   if( (aSrcWidth == 0) || (aSrcHeight == 0) ||
01122       (aSWidth == 0)   || (aSHeight == 0) ||
01123       (aDWidth == 0)   || (aDHeight == 0) )
01124   {
01125     NS_ASSERTION((aSrcWidth != 0) && (aSrcHeight != 0) &&
01126       (aSWidth != 0)   && (aSHeight != 0) ||
01127       (aDWidth != 0)   && (aDHeight != 0), 
01128       "nsXPrintContext::DrawImage(): Image with zero source||dest width||height supressed\n");
01129     return NS_OK;
01130   }
01131 
01132   /* Get the general scaling factor for this device */
01133   float pixelscale = 1.0;
01134   mContext->GetCanonicalPixelScale(pixelscale);
01135   scalingFactor = 1.0 / pixelscale;
01136 
01137   /* Calculate image scaling factors */
01138   double scale_x = double(aSWidth)  / (double(aDWidth)  * scalingFactor);
01139   double scale_y = double(aSHeight) / (double(aDHeight) * scalingFactor);
01140   
01141   /* Which scaling factor is the "bigger" one ? 
01142    * (XpSetImageResolution() sets one image resolution for both X- and
01143    * Y-axis - therefore we want to get the "best"(=smallest job size) out
01144    * of the scaling factor...).
01145    */
01146   scalingFactor *= PR_MIN(scale_x, scale_y);
01147   
01148   /* Adjust destination size to the match the scaling factor */
01149   imageResolution = long(   double(mPrintXResolution) * scalingFactor);
01150   aDWidth_scaled  = PRInt32(double(aDWidth)           * scalingFactor);
01151   aDHeight_scaled = PRInt32(double(aDHeight)          * scalingFactor);
01152 
01153   /* Check if we scaled the image to zero width/height - if "yes" then use the
01154    * smaller scaling factor and try again ... */
01155   if( (aDWidth_scaled <= 0) || (aDHeight_scaled <= 0) )
01156   {
01157     /* Chose smaller scaling factor (e.g. the reverse of what we're doing above...) */
01158     scalingFactor = 1.0 / pixelscale; /* Revert to original value */
01159     scalingFactor *= PR_MAX(scale_x, scale_y);
01160 
01161     /* Adjust destination size to the match the (new) scaling factor */
01162     imageResolution = long(   double(mPrintXResolution) * scalingFactor);
01163     aDWidth_scaled  = PRInt32(double(aDWidth)           * scalingFactor);
01164     aDHeight_scaled = PRInt32(double(aDHeight)          * scalingFactor);
01165   }
01166 
01167   /* Image scaled to 0 width/height ? */
01168   NS_ASSERTION(!((aDWidth_scaled <= 0) || (aDHeight_scaled <= 0)),
01169                "Image scaled to zero width/height");
01170   if( (aDWidth_scaled <= 0) || (aDHeight_scaled <= 0) )
01171     return NS_OK;
01172 
01173   /* Image scaled to zero-width/height ? */
01174   NS_ASSERTION(imageResolution != 0, "Image resolution must not be 0");
01175   NS_ASSERTION(imageResolution >= 0, "Image resolution must not be negative");
01176   if( imageResolution <= 0 )
01177     return NS_OK;
01178 
01179   /* Set image resolution */
01180   if( XpSetImageResolution(mPDisplay, mPContext, imageResolution, &prev_res) )
01181   {
01182     /* draw image, Xprt will do the main scaling part... */
01183     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
01184            ("Xp scaling res=%d, aSWidth=%d, aSHeight=%d, aDWidth_scaled=%d, aDHeight_scaled=%d\n", 
01185             (int)imageResolution, (int)aSWidth, (int)aSHeight, (int)aDWidth_scaled, (int)aDHeight_scaled));
01186     
01187     if( (aSX != 0) || (aSY != 0) || (aSWidth != aDWidth_scaled) || (aSHeight != aDHeight_scaled) )
01188     {
01189       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("using DrawImageBitsScaled()\n"));
01190       rv = DrawImageBitsScaled(aDrawable, xgc, aImage, aSX, aSY, aSWidth, aSHeight, aDX, aDY, aDWidth_scaled, aDHeight_scaled);
01191     }
01192     else
01193     {
01194       PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("using DrawImage() [shortcut]\n"));
01195       rv = DrawImage(aDrawable, xgc, aImage, aDX, aDY, aDWidth_scaled, aDHeight_scaled);
01196     }
01197     
01198     /* reset image resolution to previous resolution */
01199     (void)XpSetImageResolution(mPDisplay, mPContext, prev_res, &dummy);
01200   }
01201   else /* fallback */
01202   {
01203     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("BAD BAD local scaling... ;-((\n"));
01204     /* reset image resolution to previous value to be sure... */
01205     (void)XpSetImageResolution(mPDisplay, mPContext, prev_res, &dummy);
01206     
01207     /* scale image on our side (bad) */
01208     rv = DrawImageBitsScaled(aDrawable, xgc, aImage, aSX, aSY, aSWidth, aSHeight, aDX, aDY, aDWidth, aDHeight);
01209   }
01210   
01211   return rv;
01212 }  
01213 
01214 // use DeviceContextImpl :: GetCanonicalPixelScale(float &aScale) 
01215 // to get the pixel scale of the device context
01216 nsresult
01217 nsXPrintContext::DrawImageBitsScaled(Drawable aDrawable, xGC *xgc, nsIImage *aImage,
01218                  PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
01219                  PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
01220 {
01221   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
01222          ("nsXPrintContext::DrawImageBitsScaled(%lx, %d/%d/%d/%d - %d/%d/%d/%d)\n",
01223           (long)aDrawable,
01224           (int)aSX, (int)aSY, (int)aSWidth, (int)aSHeight,
01225           (int)aDX, (int)aDY, (int)aDWidth, (int)aDHeight));
01226 
01227   nsresult rv = NS_OK;
01228   
01229   if (aDWidth==0 || aDHeight==0)
01230   {
01231     NS_ASSERTION((aDWidth==0 || aDHeight==0), 
01232                  "nsXPrintContext::DrawImageBitsScaled(): Image with zero dest width||height supressed\n");
01233     return NS_OK;
01234   }
01235   
01236   aImage->LockImagePixels(PR_FALSE);
01237   
01238   PRUint8 *image_bits    = aImage->GetBits();
01239   PRInt32  row_bytes     = aImage->GetLineStride();
01240   PRUint8  imageDepth    = 24; /* R8G8B8 packed. Thanks to "tor" for that hint... */
01241   PRUint8 *alphaBits     = aImage->GetAlphaBits();
01242   PRInt32  alphaRowBytes = aImage->GetAlphaLineStride();
01243   int      alphaDepth    = aImage->GetAlphaDepth();
01244   PRInt32  aSrcWidth     = aImage->GetWidth();
01245   PRInt32  aSrcHeight    = aImage->GetHeight();
01246   PRUint8 *composed_bits = nsnull;
01247 
01248  /* image data might not be available (ex: spacer image) */
01249   if (!image_bits)
01250   {
01251     aImage->UnlockImagePixels(PR_FALSE);
01252     return NS_OK;
01253   }
01254  
01255   // Use client-side alpha image composing - plain X11 can only do 1bit alpha 
01256   // stuff - this method adds 8bit alpha support, too...
01257   if( alphaBits != nsnull )
01258   {
01259     composed_bits = ComposeAlphaImage(alphaBits, alphaRowBytes, alphaDepth,
01260                                       image_bits, row_bytes,
01261                                       aSrcWidth, aSrcHeight);
01262     if (!composed_bits)
01263     {
01264       aImage->UnlockImagePixels(PR_FALSE);
01265       return NS_ERROR_FAILURE;
01266     }
01267 
01268     image_bits = composed_bits;
01269     alphaBits = nsnull; /* ComposeAlphaImage() handled the alpha channel. 
01270                          * Once we enable XPRINT_SERVER_SIDE_ALPHA_COMPOSING 
01271                          * we have to send the alpha data to the server
01272                          * instead of processing them locally (e.g. on 
01273                          * the client-side).
01274                          */
01275   }
01276 
01277 #define ROUNDUP(nbytes, pad) ((((nbytes) + ((pad)-1)) / (pad)) * ((pad)>>3))
01278 
01279   PRInt32  srcimg_bytes_per_line = row_bytes;
01280   PRInt32  dstimg_bytes_per_line = ROUNDUP((imageDepth * aDWidth), 32);
01281   PRUint8 *srcimg_data           = image_bits;
01282   PRUint8 *dstimg_data           = (PRUint8 *)PR_Malloc((aDHeight+1) * dstimg_bytes_per_line); 
01283   if (!dstimg_data)
01284   {
01285     aImage->UnlockImagePixels(PR_FALSE);
01286     return NS_ERROR_FAILURE;
01287   }
01288 
01289   RectStretch(aSWidth, aSHeight,
01290               aDWidth, aDHeight,
01291               0, 0, aDWidth-1, aDHeight-1,
01292               srcimg_data, srcimg_bytes_per_line,
01293               dstimg_data, dstimg_bytes_per_line,
01294               imageDepth);
01295 
01296 #ifdef XPRINT_SERVER_SIDE_ALPHA_COMPOSING
01297 /* ToDo: scale alpha image */
01298 #endif /* XPRINT_SERVER_SIDE_ALPHA_COMPOSING */
01299     
01300   rv = DrawImageBits(aDrawable, xgc, alphaBits, alphaRowBytes, alphaDepth,
01301                      dstimg_data, dstimg_bytes_per_line, 
01302                      aDX, aDY, aDWidth, aDHeight);
01303 
01304   if (dstimg_data)   
01305     PR_Free(dstimg_data);
01306   if (composed_bits) 
01307     PR_Free(composed_bits);
01308   
01309   aImage->UnlockImagePixels(PR_FALSE);
01310 
01311   return rv;
01312 }
01313 
01314 
01315 NS_IMETHODIMP
01316 nsXPrintContext::DrawImage(Drawable aDrawable, xGC *xgc, nsIImage *aImage,
01317                            PRInt32 aX, PRInt32 aY,
01318                            PRInt32 dummy1, PRInt32 dummy2)
01319 {
01320   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::DrawImage(%lx, %d/%d/%d(=dummy)/%d(=dummy))\n",
01321          (long)aDrawable,
01322          (int)aX, (int)aY, (int)dummy1, (int)dummy2));
01323 
01324   aImage->LockImagePixels(PR_FALSE);
01325 
01326   nsresult rv;
01327   PRInt32  width         = aImage->GetWidth();
01328   PRInt32  height        = aImage->GetHeight();
01329   PRUint8 *alphaBits     = aImage->GetAlphaBits();
01330   PRInt32  alphaRowBytes = aImage->GetAlphaLineStride();
01331   PRInt32  alphaDepth    = aImage->GetAlphaDepth();
01332   PRUint8 *image_bits    = aImage->GetBits();
01333   PRUint8 *composed_bits = nsnull;
01334   PRInt32  row_bytes     = aImage->GetLineStride();
01335 
01336   /* image data might not be available (ex: spacer image) */
01337   if (!image_bits)
01338   {
01339     aImage->UnlockImagePixels(PR_FALSE);
01340     return NS_OK;
01341   }
01342   
01343   // Use client-side alpha image composing - plain X11 can only do 1bit alpha
01344   // stuff - this method adds 8bit alpha support, too...
01345   if( alphaBits != nsnull )
01346   {
01347     composed_bits = ComposeAlphaImage(alphaBits, alphaRowBytes, alphaDepth,
01348                                       image_bits, row_bytes,
01349                                       width, height);
01350     if (!composed_bits)
01351     {
01352       aImage->UnlockImagePixels(PR_FALSE);
01353       return NS_ERROR_FAILURE;
01354     }
01355 
01356     image_bits = composed_bits;
01357     alphaBits = nsnull;
01358   }
01359                
01360   rv = DrawImageBits(aDrawable, xgc, alphaBits, alphaRowBytes, alphaDepth,
01361                      image_bits, row_bytes,
01362                      aX, aY, width, height);
01363 
01364   if (composed_bits)
01365     PR_Free(composed_bits);
01366 
01367   aImage->UnlockImagePixels(PR_FALSE);
01368 
01369   return rv;                     
01370 }
01371 
01372                          
01373 // Draw the bitmap, this draw just has destination coordinates
01374 nsresult
01375 nsXPrintContext::DrawImageBits(Drawable aDrawable, xGC *xgc,
01376                                PRUint8 *alphaBits, PRInt32  alphaRowBytes, PRUint8 alphaDepth,
01377                                PRUint8 *image_bits, PRInt32  row_bytes,
01378                                PRInt32 aX, PRInt32 aY,
01379                                PRInt32 aWidth, PRInt32 aHeight)
01380 { 
01381   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::DrawImageBits(%lx, %d/%d/%d/%d)\n",
01382          (long)aDrawable, (int)aX, (int)aY, (int)aWidth, (int)aHeight));
01383 
01384   Pixmap alpha_pixmap  = None;
01385   GC     image_gc;
01386 
01387   if( (aWidth == 0) || (aHeight == 0) )
01388   {
01389     NS_ASSERTION((aWidth != 0) && (aHeight != 0), "Image with zero width||height supressed.");
01390     return NS_OK;
01391   }
01392   
01393 /* server-side alpha image support (1bit) - this does not work yet... */
01394 #ifdef XPRINT_SERVER_SIDE_ALPHA_COMPOSING
01395   // Create gc clip-mask on demand
01396   if( alphaBits != nsnull )
01397   {
01398     XImage    *x_image = nsnull;
01399     GC         gc;
01400     XGCValues  gcv;
01401     
01402     alpha_pixmap = XCreatePixmap(mPDisplay, 
01403                                  aDrawable,
01404                                  aWidth, aHeight, 1); /* ToDo: Check for error */
01405   
01406     /* Make an image out of the alpha-bits created by the image library (ToDo: check for error) */
01407     x_image = XCreateImage(mPDisplay, mVisual,
01408                            1,                 /* visual depth...1 for bitmaps */
01409                            XYPixmap,
01410                            0,                 /* x offset, XXX fix this */
01411                            (char *)alphaBits, /* cast away our sign. */
01412                            aWidth,
01413                            aHeight,
01414                            32,                /* bitmap pad */
01415                            alphaRowBytes);    /* bytes per line */
01416 
01417     x_image->bits_per_pixel = 1;
01418 
01419     /* Image library always places pixels left-to-right MSB to LSB */
01420     x_image->bitmap_bit_order = MSBFirst;
01421 
01422     /* This definition doesn't depend on client byte ordering
01423      * because the image library ensures that the bytes in
01424      * bitmask data are arranged left to right on the screen,
01425      * low to high address in memory. */
01426     x_image->byte_order = MSBFirst;
01427 
01428     // Write into the pixemap that is underneath gdk's alpha_pixmap
01429     // the image we just created.
01430     memset(&gcv, 0, sizeof(XGCValues)); /* this may be unneccesary */
01431     XGetGCValues(mPDisplay, *xgc, GCForeground|GCBackground, &gcv);
01432     gcv.function = GXcopy;
01433     gc = XCreateGC(mPDisplay, alpha_pixmap, GCForeground|GCBackground|GCFunction, &gcv);
01434 
01435     XPutImage(mPDisplay, alpha_pixmap, gc, x_image, 0, 0, 0, 0,
01436               aWidth, aHeight);
01437     XFreeGC(mPDisplay, gc);
01438 
01439     // Now we are done with the temporary image
01440     x_image->data = nsnull; /* Don't free the IL_Pixmap's bits. */
01441     XDestroyImage(x_image);
01442   }
01443 #endif /* XPRINT_SERVER_SIDE_ALPHA_COMPOSING */  
01444   
01445   if( alpha_pixmap != None )
01446   {
01447     /* create copy of GC before start to playing with it... */
01448     XGCValues gcv;  
01449     memset(&gcv, 0, sizeof(XGCValues)); /* this may be unneccesary */
01450     XGetGCValues(mPDisplay, *xgc, GCForeground|GCBackground, &gcv);
01451     gcv.function      = GXcopy;
01452     gcv.clip_mask     = alpha_pixmap;
01453     gcv.clip_x_origin = aX;
01454     gcv.clip_y_origin = aY;
01455 
01456     image_gc = XCreateGC(mPDisplay, aDrawable, 
01457                          (GCForeground|GCBackground|GCFunction|
01458                           GCClipXOrigin|GCClipYOrigin|GCClipMask),
01459                          &gcv);
01460   }
01461   else
01462   {
01463     /* this assumes that xlib_draw_rgb_image()/xlib_draw_gray_image()
01464      * does not change the GC... */
01465     image_gc = *xgc;
01466   }
01467 
01468 
01469   xxlib_draw_xprint_scaled_rgb_image(mXlibRgbHandle,
01470                                      aDrawable,
01471                                      mPrintXResolution, XpGetImageResolution(mPDisplay, mPContext),
01472                                      image_gc,
01473                                      aX, aY, aWidth, aHeight,
01474                                      NS_XPRINT_RGB_DITHER,
01475                                      image_bits, row_bytes);
01476   
01477   if( alpha_pixmap != None ) 
01478   {   
01479     XFreeGC(mPDisplay, image_gc);
01480     XFreePixmap(mPDisplay, alpha_pixmap);
01481   }
01482     
01483   return NS_OK;
01484 }
01485 
01486 NS_IMETHODIMP nsXPrintContext::GetPrintResolution(int &aXres, int &aYres)
01487 {
01488   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
01489          ("nsXPrintContext::GetPrintResolution() res=%ldx%ld, mPContext=%lx\n",
01490           mPrintXResolution, mPrintYResolution,(long)mPContext));
01491   
01492   if(mPContext!=None)
01493   {
01494     aXres = mPrintXResolution;
01495     aYres = mPrintYResolution;
01496     return NS_OK;
01497   }
01498   
01499   aXres = aYres = 0;
01500   return NS_ERROR_FAILURE;    
01501 }
01502 
01503 /* nsEPSObjectXp - a EPSF helper class
01504  * For details on the EPSF spec, see Adobe specification #5002,
01505  * "Encapsulated PostScript File Format Specification". The document
01506  * structuring conventions are described in Specificion #5001, 
01507  * "PostScript Language Document Structuring Conventions Specification".
01508  */
01509 class nsEPSObjectXp {
01510   public:
01514       nsEPSObjectXp(const unsigned char *aData, unsigned long aDataLength) :
01515         mStatus(NS_ERROR_INVALID_ARG),
01516         mData(nsnull),
01517         mDataLength(0UL),
01518         mCurrPos(nsnull),
01519         mBBllx(0.0),
01520         mBBlly(0.0),
01521         mBBurx(0.0),
01522         mBBury(0.0)
01523       {
01524         mData       = NS_REINTERPRET_CAST(const char*, aData);
01525         mDataLength = aDataLength;
01526 
01527         NS_PRECONDITION(aData != nsnull,   "aData == nsnull");
01528         NS_PRECONDITION(aDataLength > 0UL, "No data");    
01529 
01530         Reset();
01531         Parse();
01532       }
01533       
01534       static inline
01535       PRBool IsEPSF(const unsigned char *aData, unsigned long aDataLength)
01536       {
01537         /* First line (assuming a single line of PostScript line is not longer
01538          * than 256 chars) should usually look like "%!PS-Adobe-3.0 EPSF-3.0"
01539          * (version numbers may be different) */
01540         return (PL_strnstr(NS_REINTERPRET_CAST(const char*, aData), " EPSF-", PR_MIN(aDataLength, 256)) != nsnull);
01541       }
01542       
01543 
01549       nsresult GetStatus() { return mStatus; };
01550 
01555       inline void GetBoundingBox(PRFloat64 &aBBllx,
01556                           PRFloat64 &aBBlly,
01557                           PRFloat64 &aBBurx,
01558                           PRFloat64 &aBBury)
01559       {
01560         aBBllx = mBBllx;
01561         aBBlly = mBBlly;
01562         aBBurx = mBBurx;
01563         aBBury = mBBury;
01564       };
01565 
01569       void AppendTo(nsACString& aDestBuffer)
01570       {
01571         nsCAutoString line;
01572         PRBool        inPreview = PR_FALSE;
01573 
01574         Reset();
01575         while (EPSFFgets(line)) {
01576           if (inPreview) {
01577             /* filter out the print-preview section */
01578             if (StringBeginsWith(line, NS_LITERAL_CSTRING("%%EndPreview")))
01579                 inPreview = PR_FALSE;
01580             continue;
01581           }
01582           else if (StringBeginsWith(line, NS_LITERAL_CSTRING("%%BeginPreview:"))){
01583             inPreview = PR_TRUE;
01584             continue;
01585           }
01586 
01587           /* Output the EPSF with this platform's line terminator */
01588           aDestBuffer.Append(line.get(), line.Length());
01589           aDestBuffer.Append(NS_LITERAL_CSTRING("\n"));
01590         }
01591       }
01592   private:
01593       nsresult             mStatus;
01594       const char          *mData;
01595       unsigned long        mDataLength;
01596       const char          *mCurrPos;
01597       PRFloat64            mBBllx,
01598                            mBBlly,
01599                            mBBurx,
01600                            mBBury;
01601 
01602       void Parse()
01603       {
01604         nsCAutoString line;
01605 
01606         Reset();   
01607         while (EPSFFgets(line)) {
01608           if (PR_sscanf(line.get(), "%%%%BoundingBox: %lf %lf %lf %lf",
01609                         &mBBllx, &mBBlly, &mBBurx, &mBBury) == 4) {
01610             mStatus = NS_OK;
01611             return;
01612           }
01613         }
01614         mStatus = NS_ERROR_INVALID_ARG;
01615       }
01616       
01617       inline void Reset()
01618       {
01619         mCurrPos = mData;
01620       }
01621 
01622       PRBool EPSFFgets(nsACString& aBuffer)
01623       {
01624         aBuffer.Truncate();
01625         
01626         if (!mCurrPos)
01627           return PR_FALSE;
01628         
01629         while (1) {
01630           int ch = *mCurrPos++;
01631           if ('\n' == ch) {
01632             /* Eat any following carriage return */
01633             ch = *mCurrPos++;
01634             if ((mCurrPos < (mData + mDataLength)) && ('\r' != ch))
01635               mCurrPos--;
01636             return PR_TRUE;
01637           }
01638           else if ('\r' == ch) {
01639             /* Eat any following line feed */
01640             ch = *mCurrPos++;
01641             if ((mCurrPos < (mData + mDataLength)) && ('\n' != ch))
01642               mCurrPos--;
01643             return PR_TRUE;
01644           }
01645           else if (mCurrPos >= (mData + mDataLength)) {
01646             /* If we read any text before the EOF, return true. */
01647             return !aBuffer.IsEmpty();
01648           }
01649 
01650           /* Normal case */
01651           aBuffer.Append((char)ch);
01652         }
01653       }
01654 };
01655 
01656 NS_IMETHODIMP nsXPrintContext::RenderEPS(Drawable aDrawable,
01657                                          const nsRect& aRect,
01658                                          const unsigned char *aData, unsigned long aDatalen)
01659 {
01660   PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
01661          ("nsXPrintContext::EPS(aData, aDatalen=%d)\n", aDatalen));
01662   
01663   char xp_formats_supported[] = "xp-embedded-formats-supported";
01664   const char *embedded_formats_supported = XpGetOneAttribute(mPDisplay, mPContext, XPPrinterAttr, xp_formats_supported);
01665 
01666   /* Check whether "PostScript Level 2" is supported as embedding format
01667    * (The content of the "xp-embedded-formats-supported" attribute needs
01668    * to be searched in a case-insensitive way since the model-configs
01669    * may use the same word with multiple variants of case
01670    * (e.g. "PostScript" vs. "Postscript" or "PCL" vs. "Pcl" etc.")
01671    * To avoid problems we simply use |PL_strcasestr()| (case-insensitive
01672    * strstr()) instead of |strstr()| here...)
01673    */
01674   if (embedded_formats_supported == NULL)
01675   {
01676     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, ("nsXPrintContext::RenderPostScriptDataFragment(): Embedding data not supported for this DDX/Printer\n"));
01677     return NS_ERROR_FAILURE;    
01678   }
01679 
01680   if( PL_strcasestr(embedded_formats_supported, "PostScript 2") == NULL )
01681   {
01682     PR_LOG(nsXPrintContextLM, PR_LOG_DEBUG, 
01683            ("nsXPrintContext::RenderPostScriptDataFragment(): Embedding data not supported for this DDX/Printer "
01684             "(supported embedding formats are '%s')\n", embedded_formats_supported));
01685     XFree((void *)embedded_formats_supported);
01686     return NS_ERROR_FAILURE;    
01687   }
01688 
01689   /* Temp buffer for EPSF data - this has to live outside the if()/else()
01690    * block below to gurantee that the pointers we get from it are still
01691    * valid when we feed the data to |XpPutDocumentData| */
01692   nsXPIDLCString  aBuffer;
01693   const unsigned char *embedData;
01694   unsigned long        embedDataLength;
01695     
01696   /* If the input is EPSF then we need to do some EPSF-specific handling */
01697   if (nsEPSObjectXp::IsEPSF(aData, aDatalen))
01698   {
01699     PRFloat64 boxLLX, 
01700               boxLLY,
01701               boxURX,
01702               boxURY;
01703 
01704     nsEPSObjectXp epsfData(aData, aDatalen);
01705     /* Non-EPSF data are not supported yet */
01706     if (NS_FAILED(epsfData.GetStatus()))
01707       return NS_ERROR_INVALID_ARG;  
01708 
01709     epsfData.GetBoundingBox(boxLLX, boxLLY, boxURX, boxURY);
01710 
01711     /* Size buffer that all the data in |aData| and context fits into the string */
01712     aBuffer.SetCapacity(aDatalen + 1024); 
01713     aBuffer.Assign("%%BeginDocument: Mozilla EPSF plugin data\n"
01714                    "/b4_Inc_state save def\n"
01715                    "/dict_count countdictstack def\n"
01716                    "/op_count count 1 sub def\n"
01717                    "userdict begin\n"
01718                    "/showpage { } def\n"
01719                    "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
01720                    "10 setmiterlimit [ ] 0 setdash newpath\n"
01721                    "/languagelevel where\n"
01722                    "{pop languagelevel\n"
01723                    "  1 ne\n"
01724                    "  {false setstrokeadjust false setoverprint\n"
01725                    "  } if\n"
01726                    "} if\n");
01727 
01728     /* translate to the lower left corner of the rectangle */
01729     aBuffer.Append(nsPrintfCString(64, "%f %f translate\n", 
01730                    double(aRect.x),
01731                    double(aRect.y + aRect.height)));
01732 
01733     /* Rescale */
01734     aBuffer.Append(nsPrintfCString(64, "%f %f scale\n", 
01735                    double(aRect.width / (boxURX - boxLLX)),
01736                    double(-(aRect.height / (boxURY - boxLLY)))));
01737 
01738     /* Translate to the EPSF origin. Can't use translate() here because
01739      * it takes integers.
01740      */
01741     aBuffer.Append(nsPrintfCString(64, "%f %f translate\n", double(-boxLLX), double(-boxLLY)));
01742 
01743     epsfData.AppendTo(aBuffer);
01744     aBuffer.Append("count op_count sub { pop } repeat\n"
01745                    "countdictstack dict_count sub { end } repeat\n"
01746                    "b4_Inc_state restore\n"
01747                    "%%EndDocument\n");
01748     embedData       = NS_REINTERPRET_CAST(const unsigned char*, aBuffer.get());
01749     embedDataLength = aBuffer.Length();
01750   }
01751   else
01752   {
01753     /* Non-EPSF codepath - pass the data as-is... */
01754     embedData       = aData;
01755     embedDataLength = aDatalen;
01756   }
01757   
01758   /* Note that the embedded PostScript code uses the same resolution and
01759    * coordinate space as currently be used by the DDX (if you do not
01760    * want that simply reset it yourself :) */
01761   const char *type     = "PostScript 2"; /* Format of embedded data 
01762                                           * (older PS DDX may be picky, fixed via
01763                                           * http://xprint.mozdev.org/bugs/show_bug.cgi?id=4023)
01764                                           */
01765   const char *option   = "";             /* PostScript DDX does not support any options yet
01766                                           * (in general |BadValue| will be returned for not
01767                                           * supported options/option values) */
01768 
01769   /* XpPutDocumentData() takes |const| input for all string arguments, only the X11 prototypes do not allow |const| yet */
01770   XpPutDocumentData(mPDisplay, aDrawable, (unsigned char *)embedData, embedDataLength, (char *)type, (char *)option);
01771 
01772   XFree((void *)embedded_formats_supported);
01773   
01774   return NS_OK;
01775 }
01776 
01777