home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 …ember: Reference Library / Apple Developer Reference Library (December 1999) (Disk 1).iso / pc / technical documentation / macintosh technotes and q&as / technotes / tn / samplecode.sit.hqx / Sample Code / PrintingLibrary.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-22  |  49.7 KB  |  1,910 lines

  1. /*
  2.     File:        PrintingLibrary.c
  3.  
  4.     Contains:    Graphics library for printing QuickDraw GX data.
  5.                 
  6.                 This library supports the basic job, format, dialog, and
  7.                 spooling functions of the QuickDraw GX Printing Manager. It
  8.                 provides an abstraction layer to handle printing through the
  9.                 QuickDraw GX and classic QuickDraw printing architectures,
  10.                 depending on which environment is available when the library
  11.                 is initialized. Only the basic features of QuickDraw GX
  12.                 printing are supported; i.e., the library does not handle
  13.                 application message overrides, custom dialog panels, or custom
  14.                 page formatting.
  15.                 
  16.                 For classic QuickDraw printing, the library uses QuickTime
  17.                 compression and decompression to image QuickDraw GX data. The
  18.                 basic technique is to encapsulate the QuickDraw GX image in a
  19.                 compressed data format using the object flattening functions
  20.                 from QuickDraw GX. Once the compressed image data is created,
  21.                 it may be passed to the QuickDraw GX codec and drawn using the
  22.                 QuickTime image compression functions or embedded within a
  23.                 QuickDraw picture and drawn using the DrawPicture function. In
  24.                 either case, the compressed data is passed to the the
  25.                 low-level QuickDraw drawing routines through the StdPix
  26.                 bottleneck routine. StdPix decompresses the data using the
  27.                 QuickDraw GX codec and passes the decompressed data to the
  28.                 bitsProc bottleneck routine when rendering the image.
  29.  
  30.                 LaserWriter drivers starting with version 8.3 recognize
  31.                 compressed data that may be drawn using QuickTime, like
  32.                 QuickDraw GX flattened objects. For version 8.4.3, the
  33.                 LaserWriter driver has been modified to render the QuickDraw
  34.                 GX data at the device resolution of the printer. When
  35.                 despooling, the printer driver changes the resolution of the
  36.                 offscreen drawing port and uses the QuicDraw GX codec to
  37.                 rasterize the compressed data. The QuickDraw printer drivers
  38.                 from Apple render the compressed data during spooling and use
  39.                 the resolution of the active graphics port. The library uses
  40.                 the device resolution commands of the PrGeneral routine to
  41.                 improve the quality of their printed images as described in
  42.                 “Meet PrGeneral, the Trap That Makes the Most of the Printing
  43.                 Manager,” in develop 3 (July 1990).
  44.  
  45.     Written by:    Daniel Lipton
  46.  
  47.     Copyright:    © 1997 by Apple Computer, Inc., all rights reserved.
  48.  
  49.     Writers:
  50.  
  51.         (DIL)    Daniel Lipton
  52.         (IK)    Ingrid Kelly
  53.  
  54.     Change History (most recent first):
  55.  
  56.          <1>      6/1/97    IK        First created.
  57. */
  58.  
  59. #include <CodeFragments.h>
  60. #include <Gestalt.h>
  61. #include <Resources.h>
  62. #include <TextUtils.h>
  63.  
  64. #include "CodecLibrary.h"
  65. #include "PrintingLibrary.h"
  66. #include "GetShapeLocalBounds.h"
  67.  
  68. /* ---------------------------------------------------------------------------
  69.     Function prototypes
  70.   --------------------------------------------------------------------------- */
  71.  
  72. static gxRectangle    *ShortRectToFixed(const Rect *shortRect, gxRectangle *fixedRect);
  73. static Rect            *FixedRectToShort(const gxRectangle *fixedRect, Rect *shortRect);
  74. static OSErr        QDInitPrinting(void);
  75. static OSErr        QDPrOpen(void);
  76. static void            QDPrClose(void);
  77. static OSErr        QDPrGetMaxResolution(short *maxDPI);
  78. static OSErr        QDPrSetResolution(THPrint prRecHdl, short iXRsl, short iYRsl);
  79. pascal void            QDIdleProc(void);
  80. static OSErr        QDCommandPeriod(void);
  81.  
  82. static OSErr        ReplaceCollectionItem(
  83.                             Collection        collectionRef,
  84.                             OSType            collectionType,
  85.                             long            collectionID,
  86.                             long            collectionSize,
  87.                             void            *newData,
  88.                             long            *oldDataSize,
  89.                             void            **oldDataPtr);
  90.  
  91. static OSErr        SetViewportContext(gxprJobHdl gxprJob, long numViewPorts, gxViewPort *viewPortList);
  92. static OSErr        RestoreViewportContext(gxprJobHdl gxprJob);
  93. static Boolean        TestMappingIdentity(gxMapping *mapping);
  94. static void            GXPrViewPortFilter(gxShape toFilter, gxViewPort portOrder, long refCon);
  95.  
  96. /* ===========================================================================
  97.     Global variables
  98.   =========================================================================== */
  99.  
  100. static PrintingArchitecture        gPrintingArchitecture = kAnyPrArch;
  101. static PrintingOptions            gPrintingOptions = kNilOptions;
  102.  
  103. static gxUserViewPortFilterUPP    gGXUserViewPortFilterUPP = nil;
  104. static long                        gPrOpenCount = 0;
  105.  
  106. /* ===========================================================================
  107.     Public functions
  108.   =========================================================================== */
  109.  
  110. /* ---------------------------------------------------------------------------
  111.     GXPrInitPrinting
  112.   --------------------------------------------------------------------------- */
  113.  
  114. OSErr GXPrInitPrinting(void)
  115. {
  116.     long    theFeature;
  117.     OSErr    error;
  118.  
  119.     /*    Before making any calls, check if the Printing Manager is available. */
  120.  
  121.     if ( Gestalt(gestaltGXPrintingMgrVersion, &theFeature) != noErr )
  122.         gPrintingArchitecture = kQDPrArch;
  123.     else
  124.         gPrintingArchitecture = kGXPrArch;
  125.  
  126. #ifdef powerc
  127.     /*    This is a sanity check to see if the GXPrintingLib shared library is
  128.         installed. If the application is "weak" linked to the library, the
  129.         Process Manager will launch it even if the library is missing,
  130.         although the Code Fragment Manager will not resolve the addresses of
  131.         the functions in the library. If the application calls any of these
  132.         functions, it will crash.
  133.  
  134.         The application should check if any of the Printing Manager functions
  135.         cannot be resolved and exit gracefully if the library is missing. Note
  136.         that the check could be performed against any function the application
  137.         calls in the library. GXInitPrinting is often the first function that
  138.         is called from the library, so it is convenient.
  139.     */
  140.     if ( (UInt32)GXInitPrinting == kUnresolvedCFragSymbolAddress )
  141.         gPrintingArchitecture = kQDPrArch;
  142. #endif
  143.  
  144.     if ( gPrintingArchitecture == kGXPrArch )
  145.         error = GXInitPrinting();
  146.     else
  147.     {
  148.         gGXUserViewPortFilterUPP = NewgxUserViewPortFilterProc(GXPrViewPortFilter);
  149.         error = QDInitPrinting();
  150.     }
  151.  
  152.     return error;
  153. }
  154.  
  155. /* ---------------------------------------------------------------------------
  156.     GXPrExitPrinting
  157.   --------------------------------------------------------------------------- */
  158.  
  159. OSErr GXPrExitPrinting(void)
  160. {
  161.     OSErr    error;
  162.  
  163.     if ( gPrintingArchitecture == kGXPrArch )
  164.         error = GXExitPrinting();
  165.     else
  166.     {
  167.         if ( gGXUserViewPortFilterUPP != nil )
  168.         {
  169.             DisposeRoutineDescriptor(gGXUserViewPortFilterUPP);
  170.             gGXUserViewPortFilterUPP = nil;
  171.         }
  172.         error = noErr;
  173.     }
  174.  
  175.     return error;
  176. }
  177.  
  178. /* ---------------------------------------------------------------------------
  179.     GXPrGetPrintingArchitecture
  180.   --------------------------------------------------------------------------- */
  181.  
  182. PrintingArchitecture GXPrGetPrintingArchitecture(void)
  183. {
  184.     return gPrintingArchitecture;
  185. }
  186.  
  187. /* ---------------------------------------------------------------------------
  188.     GXPrGetPrintingOptions
  189.   --------------------------------------------------------------------------- */
  190.  
  191. PrintingOptions GXPrGetPrintingOptions(void)
  192. {
  193.     return gPrintingOptions;
  194. }
  195.  
  196. /* ---------------------------------------------------------------------------
  197.     GXPrSetPrintingOptions
  198.   --------------------------------------------------------------------------- */
  199.  
  200. void GXPrSetPrintingOptions(PrintingOptions options)
  201. {
  202.     gPrintingOptions = options;
  203. }
  204.  
  205. /* ---------------------------------------------------------------------------
  206.     GXPrGetJobError
  207.   --------------------------------------------------------------------------- */
  208.  
  209. OSErr GXPrGetJobError(gxprJobHdl gxprJob)
  210. {
  211.     OSErr    error;
  212.  
  213.     if ( gxprJob == nil )
  214.         return paramErr;
  215.  
  216.     error = (*gxprJob)->error;
  217.     (*gxprJob)->error = noErr;
  218.  
  219.     return error;
  220. }
  221.  
  222. /* ---------------------------------------------------------------------------
  223.     GXPrSetJobError
  224.   --------------------------------------------------------------------------- */
  225.  
  226. void GXPrSetJobError(gxprJobHdl gxprJob, OSErr error)
  227. {
  228.     if ( gxprJob == nil )
  229.         return;
  230.  
  231.     (*gxprJob)->error = error;
  232.     GXSetJobError((*gxprJob)->job, error);
  233. }
  234.  
  235. /* ---------------------------------------------------------------------------
  236.     GXPrNewJob
  237.     This routine returns a default print handle for the current printer driver.
  238.     The printer driver is expected to be closed upon entry, and is therefore
  239.     opened and closed in this routine.
  240.   --------------------------------------------------------------------------- */
  241.  
  242. OSErr GXPrNewJob(gxprJobHdl *gxprJob)
  243. {
  244.     gxprJobHdl    tempJob;
  245.     THPrint        prRecHdl = nil;
  246.     OSErr        error = noErr;
  247.  
  248.     *gxprJob = nil;
  249.  
  250.     tempJob = (gxprJobHdl)NewHandleClear(sizeof(gxprJobRecord));
  251.     if ( tempJob == nil )
  252.     {
  253.         error = MemError();
  254.         goto NewHandleClearFailed;
  255.     }
  256.  
  257.     if ( gPrintingArchitecture == kGXPrArch )
  258.     {
  259.         error = GXNewJob(&(*tempJob)->job);
  260.         if ( error != noErr )
  261.             goto GXNewJobFailed;
  262.     }
  263.     else
  264.     {
  265.         prRecHdl = (THPrint)NewHandle(sizeof(TPrint));
  266.         if ( prRecHdl == nil )
  267.         {
  268.             error = MemError();
  269.             goto NewHandleFailed;
  270.         }
  271.  
  272.         /*    The PrintDefault routine sets the default values for the current
  273.             printer, which are stored in the printer driver’s resource file,
  274.             in the TPrint record, replacing the ones that may already be
  275.             there. It calls the PrValidate function to ensure that the TPrint
  276.             record is compatible with the current version of the printer
  277.             driver.
  278.         */
  279.         error = QDPrOpen();
  280.  
  281.         if ( error == noErr )
  282.         {
  283.             PrintDefault(prRecHdl);
  284.             error = PrError();
  285.         }
  286.  
  287.         /*    Select the maximum resolution of the printer. */
  288.  
  289.         if ( error == noErr && ((**prRecHdl).iPrVersion != 3 ||
  290.             (gPrintingOptions & kUseShapeToQuickDrawPictureConversion) != 0) )
  291.             error = QDPrGetMaxResolution(&(*tempJob)->prResolution);
  292.  
  293.         QDPrClose();
  294.  
  295.         if ( error != noErr )
  296.             goto InitPrintRecordFailed;
  297.  
  298.         (*tempJob)->prRecHdl = prRecHdl;
  299.     }
  300.  
  301.     (*tempJob)->architecture = gPrintingArchitecture;
  302.     (*tempJob)->prResFile = -1;
  303.  
  304.     *gxprJob = tempJob;
  305.  
  306.     goto Completed;
  307.  
  308. InitPrintRecordFailed:
  309.     if ( prRecHdl != nil )
  310.         DisposeHandle((Handle)prRecHdl);
  311.  
  312. NewHandleFailed:
  313. GXNewJobFailed:
  314.     if ( tempJob != nil )
  315.         DisposeHandle((Handle)tempJob);
  316.  
  317. NewHandleClearFailed:
  318. Completed:
  319.     return error;
  320. }
  321.  
  322. /* ---------------------------------------------------------------------------
  323.     GXPrDisposeJob
  324.   --------------------------------------------------------------------------- */
  325.  
  326. OSErr GXPrDisposeJob(gxprJobHdl gxprJob)
  327. {
  328.     OSErr    error = noErr;
  329.  
  330.     if ( gxprJob == nil )
  331.         return paramErr;
  332.  
  333.     if ( (*gxprJob)->job != nil )
  334.         error = GXDisposeJob((*gxprJob)->job);
  335.  
  336.     if ( (*gxprJob)->prRecHdl != nil )
  337.     {
  338.         DisposeHandle((Handle)(*gxprJob)->prRecHdl);
  339.  
  340.         if ( error == noErr )
  341.             error = MemError();
  342.     }
  343.  
  344.     DisposeHandle((Handle)gxprJob);
  345.  
  346.     return error;
  347. }
  348.  
  349. /* ---------------------------------------------------------------------------
  350.     GXPrFlattenJobToFile
  351.     This routine saves a print record handle in resource fork of a file; any
  352.     existing print record resources are deleted and replaced.
  353.   --------------------------------------------------------------------------- */
  354.  
  355. void GXPrFlattenJobToFile(gxprJobHdl gxprJob, FSSpecPtr fileSpec)
  356. {
  357.     Handle        dataHandle;
  358.     ResType        rsrcType;
  359.     short        rsrcID;
  360.     short        resRefNum;
  361.     Handle        tempHandle;
  362.     short        savedRefNum;
  363.  
  364.     if ( gxprJob == nil )
  365.         return;
  366.  
  367.     /*    Save the current resource file reference number. */
  368.  
  369.     savedRefNum = CurResFile();
  370.  
  371.     resRefNum = FSpOpenResFile(fileSpec, fsRdWrPerm);
  372.     if ( resRefNum == -1 )
  373.     {
  374.         (*gxprJob)->error = ResError();
  375.         goto FSpOpenResFileFailed;
  376.     }
  377.  
  378.     if ( (*gxprJob)->architecture == kGXPrArch )
  379.     {
  380.         dataHandle = GXFlattenJobToHdl((*gxprJob)->job, nil);
  381.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  382.         if ( (*gxprJob)->error != noErr )
  383.             goto GXFlattenJobToHdlFailed;
  384.  
  385.         rsrcType = rJobObjectRsrcType;
  386.         rsrcID = rJobObjectRsrcID;
  387.     }
  388.     else
  389.     {
  390.         dataHandle = (Handle)(*gxprJob)->prRecHdl;
  391.  
  392.         rsrcType = rPrintRecordRsrcType;
  393.         rsrcID = rPrintRecordRsrcID;
  394.     }
  395.  
  396.     /*    Delete any existing job object or print record resources. */
  397.  
  398.     UseResFile(resRefNum);
  399.     tempHandle = Get1Resource(rsrcType, rsrcID);
  400.     if ( tempHandle != nil )
  401.     {
  402.         RemoveResource(tempHandle);
  403.         UpdateResFile(resRefNum);
  404.         DisposeHandle(tempHandle);
  405.     }
  406.  
  407.     /*    Add the job object or print record resource. */
  408.  
  409.     if ( (*gxprJob)->error == noErr )
  410.     {
  411.         AddResource(dataHandle, rsrcType, rsrcID, "\p");
  412.         (*gxprJob)->error = ResError();
  413.  
  414.         if ( (*gxprJob)->error == noErr )
  415.         {
  416.             WriteResource(dataHandle);
  417.             UpdateResFile(resRefNum);
  418.             ReleaseResource(dataHandle);
  419.         }
  420.     }
  421.  
  422. GXFlattenJobToHdlFailed:
  423. NewHandleFailed:
  424.     CloseResFile(resRefNum);
  425.     FlushVol(nil, fileSpec->vRefNum);
  426.  
  427.     /*    Switch back to the original resource file. */
  428.  
  429.     UseResFile(savedRefNum);
  430.  
  431. FSpOpenResFileFailed:
  432.     return;
  433. }
  434.  
  435. /* ---------------------------------------------------------------------------
  436.     GXPrUnflattenJobFromFile
  437.     This routine loads the first indexed print record resource from a file. If
  438.     there are no matching resources in the file the function returns
  439.     resNotFound.
  440.   --------------------------------------------------------------------------- */
  441.  
  442. gxprJobHdl GXPrUnflattenJobFromFile(gxprJobHdl gxprJob, FSSpecPtr fileSpec)
  443. {
  444.     Handle        dataHandle;
  445.     ResType        rsrcType;
  446.     short        rsrcID;
  447.     short        resRefNum;
  448.     short        savedRefNum;
  449.     Boolean        changed = false;
  450.  
  451.     if ( gxprJob == nil )
  452.         return nil;
  453.  
  454.     /*    Save the current resource file reference number. */
  455.  
  456.     savedRefNum = CurResFile();
  457.  
  458.     resRefNum = FSpOpenResFile(fileSpec, fsRdWrPerm);
  459.     if ( resRefNum == -1 )
  460.     {
  461.         (*gxprJob)->error = ResError();
  462.         goto FSpOpenResFileFailed;
  463.     }
  464.  
  465.     if ( (*gxprJob)->architecture == kGXPrArch )
  466.     {
  467.         rsrcType = rJobObjectRsrcType;
  468.         rsrcID = rJobObjectRsrcID;
  469.     }
  470.     else
  471.     {
  472.         rsrcType = rPrintRecordRsrcType;
  473.         rsrcID = rPrintRecordRsrcID;
  474.     }
  475.  
  476.     dataHandle = Get1IndResource(rsrcType, rsrcID);
  477.     if ( dataHandle == nil )
  478.     {
  479.         (*gxprJob)->error = ResError();
  480.         goto Get1IndResourceFailed;
  481.     }
  482.     DetachResource(dataHandle);
  483.  
  484.     if ( (*gxprJob)->architecture == kGXPrArch )
  485.     {
  486.         (*gxprJob)->job = GXUnflattenJobFromHdl(nil, dataHandle);
  487.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  488.         if ( (*gxprJob)->error != noErr )
  489.             goto GXUnflattenJobFromHdlFailed;
  490.     }
  491.     else
  492.     {
  493.         (*gxprJob)->prRecHdl = (THPrint)dataHandle;
  494.     }
  495.  
  496.     (void)GXPrUpdateJob(gxprJob);
  497.  
  498. GXUnflattenJobFromHdlFailed:
  499. Get1IndResourceFailed:
  500.     CloseResFile(resRefNum);
  501.     FlushVol(nil, fileSpec->vRefNum);
  502.  
  503.     /*    Switch back to the original resource file. */
  504.  
  505.     UseResFile(savedRefNum);
  506.  
  507. FSpOpenResFileFailed:
  508.     return gxprJob;
  509. }
  510.  
  511. /* ---------------------------------------------------------------------------
  512.     GXPrInstallApplicationOverride
  513.   --------------------------------------------------------------------------- */
  514.  
  515. void GXPrInstallApplicationOverride(gxprJobHdl gxprJob, short messageID, void *override)
  516. {
  517.     if ( gxprJob == nil )
  518.         return;
  519.  
  520.     if ( (*gxprJob)->architecture == kGXPrArch )
  521.     {
  522.         GXInstallApplicationOverride((*gxprJob)->job, messageID, override);
  523.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  524.     }
  525. }
  526.  
  527. /* ---------------------------------------------------------------------------
  528.     GXPrUpdateJob
  529.   --------------------------------------------------------------------------- */
  530.  
  531. Boolean GXPrUpdateJob(gxprJobHdl gxprJob)
  532. {
  533.     Boolean        changed = false;
  534.  
  535.     if ( gxprJob == nil )
  536.         return false;
  537.  
  538.     if ( (*gxprJob)->architecture == kGXPrArch )
  539.     {
  540.         changed = GXUpdateJob((*gxprJob)->job);
  541.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  542.     }
  543.     else
  544.     {
  545.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  546.         OSErr    error;
  547.  
  548.         error = QDPrOpen();
  549.  
  550.         if ( error == noErr )
  551.         {
  552.             /*    With the TPrint record, whether an existing one from the current
  553.                 document or a new one just created, the PrValidate function
  554.                 ensures that the contents of the specified TPrint record are
  555.                 compatible with the current version of the printer driver for the
  556.                 current printer.
  557.             */
  558.             changed = PrValidate(prRecHdl);
  559.             error = PrError();
  560.  
  561.             /*    Select the maximum resolution of the printer. */
  562.  
  563.             if ( error == noErr && ((**prRecHdl).iPrVersion != 3 ||
  564.                 (gPrintingOptions & kUseShapeToQuickDrawPictureConversion) != 0) )
  565.                 error = QDPrGetMaxResolution(&(*gxprJob)->prResolution);
  566.         }
  567.  
  568.         QDPrClose();
  569.  
  570.         (*gxprJob)->error = error;
  571.     }
  572.  
  573.     return changed;
  574. }
  575.  
  576. /* ---------------------------------------------------------------------------
  577.     GXPrNewFormat
  578.   --------------------------------------------------------------------------- */
  579.  
  580. gxprFormatHdl GXPrNewFormat(gxprJobHdl gxprJob)
  581. {
  582.     gxprFormatHdl gxprFormat = nil;
  583.  
  584.     if ( gxprJob == nil )
  585.         return nil;
  586.  
  587.     gxprFormat = (gxprFormatHdl)NewHandleClear(sizeof(gxprFormatRecord));
  588.     if ( gxprFormat == nil )
  589.     {
  590.         (*gxprJob)->error = MemError();
  591.         goto NewHandleClearFailed;
  592.     }
  593.  
  594.     if ( (*gxprJob)->architecture == kGXPrArch )
  595.     {
  596.         (*gxprFormat)->format = GXNewFormat((*gxprJob)->job);
  597.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  598.     }
  599.  
  600.     (*gxprFormat)->gxprJob = gxprJob;
  601.  
  602. NewHandleClearFailed:
  603.     return gxprFormat;
  604. }
  605.  
  606. /* ---------------------------------------------------------------------------
  607.     GXPrDisposeFormat
  608.   --------------------------------------------------------------------------- */
  609.  
  610. void GXPrDisposeFormat(gxprFormatHdl gxprFormat)
  611. {
  612.     if ( gxprFormat == nil )
  613.         return;
  614.  
  615.     if ( (*gxprFormat)->format != nil )
  616.         GXDisposeFormat((*gxprFormat)->format);
  617.  
  618.     DisposeHandle((Handle)gxprFormat);
  619. }
  620.  
  621. /* ---------------------------------------------------------------------------
  622.     GXPrGetFormatJob
  623.   --------------------------------------------------------------------------- */
  624.  
  625. gxprJobHdl GXPrGetFormatJob(gxprFormatHdl gxprFormat)
  626. {
  627.     if ( gxprFormat == nil )
  628.         return nil;
  629.  
  630.     return (*gxprFormat)->gxprJob;
  631. }
  632.  
  633. /* ---------------------------------------------------------------------------
  634.     GXPrGetFormatDimensions
  635.   --------------------------------------------------------------------------- */
  636.  
  637. void GXPrGetFormatDimensions(gxprFormatHdl gxprFormat, gxRectangle *pageSize, gxRectangle *paperSize)
  638. {
  639.     gxprJobHdl    gxprJob;
  640.  
  641.     if ( gxprFormat == nil )
  642.         return;
  643.  
  644.     gxprJob = (*gxprFormat)->gxprJob;
  645.  
  646.     if ( (*gxprJob)->architecture == kGXPrArch )
  647.     {
  648.         GXGetFormatDimensions((*gxprFormat)->format, pageSize, paperSize);
  649.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  650.     }
  651.     else
  652.     {
  653.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  654.         Rect    pageRect;
  655.         Rect    paperRect;
  656.  
  657.         pageRect = (**prRecHdl).prInfo.rPage;
  658.         paperRect = (**prRecHdl).rPaper;
  659.  
  660.         (void)ShortRectToFixed(&pageRect, pageSize);
  661.         (void)ShortRectToFixed(&paperRect, paperSize);
  662.     }
  663. }
  664.  
  665. /* ---------------------------------------------------------------------------
  666.     GXPrGetFormatCollection
  667.   --------------------------------------------------------------------------- */
  668.  
  669. Collection GXPrGetFormatCollection(gxprFormatHdl gxprFormat)
  670. {
  671.     gxprJobHdl    gxprJob;
  672.     Collection    formatCollection = nil;
  673.  
  674.     if ( gxprFormat == nil )
  675.         return nil;
  676.  
  677.     if ( (*gxprFormat)->format == nil )
  678.         return nil;
  679.  
  680.     gxprJob = (*gxprFormat)->gxprJob;
  681.  
  682.     if ( (*gxprJob)->architecture == kGXPrArch )
  683.     {
  684.         formatCollection = GXGetFormatCollection((*gxprFormat)->format);
  685.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  686.     }
  687.  
  688.     return formatCollection;
  689. }
  690.  
  691. /* ---------------------------------------------------------------------------
  692.     GXPrJobDefaultFormatDialog
  693.     This routine displays the standard page format dialog.
  694.   --------------------------------------------------------------------------- */
  695.  
  696. gxDialogResult GXPrJobDefaultFormatDialog(gxprJobHdl gxprJob, gxEditMenuRecord *anEditMenuRec)
  697. {
  698.     gxDialogResult    result = gxCancelSelected;
  699.  
  700.     if ( gxprJob == nil )
  701.         return gxCancelSelected;
  702.  
  703.     if ( (*gxprJob)->architecture == kGXPrArch )
  704.     {
  705.         result = GXJobDefaultFormatDialog((*gxprJob)->job, anEditMenuRec);
  706.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  707.     }
  708.     else
  709.     {
  710.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  711.         Boolean    changed = false;
  712.         OSErr    error;
  713.  
  714.         error = QDPrOpen();
  715.  
  716.         if ( error == noErr )
  717.         {
  718.             (void)PrValidate(prRecHdl);
  719.             error = PrError();
  720.  
  721.             if ( error == noErr )
  722.             {
  723.                 changed = PrStlDialog(prRecHdl);
  724.                 error = PrError();
  725.  
  726.                 if ( changed )
  727.                     result = gxOKSelected;
  728.                 else
  729.                     result = gxCancelSelected;
  730.  
  731.                 if ( error == noErr && result == gxCancelSelected )
  732.                 {
  733.                     PrSetError(iPrAbort);
  734.                     error = iPrAbort;
  735.                 }
  736.             }
  737.         }        
  738.  
  739.         QDPrClose();
  740.  
  741.         (*gxprJob)->error = error;
  742.     }
  743.  
  744.     return result;
  745. }
  746.  
  747. /* ---------------------------------------------------------------------------
  748.     GXPrJobPrintDialog
  749.     This routine displays the standard print dialog.
  750.   --------------------------------------------------------------------------- */
  751.  
  752. gxDialogResult GXPrJobPrintDialog(gxprJobHdl gxprJob, gxEditMenuRecord *anEditMenuRec)
  753. {
  754.     gxDialogResult    result = gxCancelSelected;
  755.  
  756.     if ( gxprJob == nil )
  757.     {
  758.         (*gxprJob)->error = paramErr;
  759.         return gxCancelSelected;
  760.     }
  761.  
  762.     if ( (*gxprJob)->architecture == kGXPrArch )
  763.     {
  764.         gxJob    job = (*gxprJob)->job;
  765.  
  766.         result = GXJobPrintDialog(job, anEditMenuRec);
  767.         (*gxprJob)->error = GXGetJobError(job);
  768.     }
  769.     else
  770.     {
  771.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  772.         Boolean    changed = false;
  773.         OSErr    error;
  774.  
  775.         error = QDPrOpen();
  776.  
  777.         if ( error == noErr )
  778.         {
  779.             (void)PrValidate(prRecHdl);
  780.             error = PrError();
  781.  
  782.             if ( error == noErr )
  783.             {
  784.                 changed = PrJobDialog(prRecHdl);
  785.                 error = PrError();
  786.  
  787.                 if ( changed )
  788.                     result = gxOKSelected;
  789.                 else
  790.                     result = gxCancelSelected;
  791.  
  792.                 if ( error == noErr && result == gxCancelSelected )
  793.                 {
  794.                     PrSetError(iPrAbort);
  795.                     error = iPrAbort;
  796.                 }
  797.             }
  798.         }        
  799.  
  800.         QDPrClose();
  801.  
  802.         (*gxprJob)->error = error;
  803.     }
  804.  
  805.     return result;
  806. }
  807.  
  808. /* ---------------------------------------------------------------------------
  809.     GXPrFormatDialog
  810.     This routine displays the custom page format dialog.
  811.   --------------------------------------------------------------------------- */
  812.  
  813. gxDialogResult GXPrFormatDialog(gxprFormatHdl gxprFormat, gxEditMenuRecord *anEditMenuRec, StringPtr title)
  814. {
  815.     gxprJobHdl        gxprJob;
  816.     gxDialogResult    result = gxCancelSelected;
  817.     Boolean            changed = false;
  818.     OSErr            error;
  819.  
  820.     if ( gxprFormat == nil )
  821.         return gxCancelSelected;
  822.  
  823.     gxprJob = (*gxprFormat)->gxprJob;
  824.  
  825.     if ( (*gxprJob)->architecture == kGXPrArch )
  826.     {
  827.         result = GXFormatDialog((*gxprFormat)->format, anEditMenuRec, title);
  828.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  829.     }
  830.     else
  831.     {
  832.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  833.  
  834.         error = QDPrOpen();
  835.  
  836.         if ( error == noErr )
  837.         {
  838.             (void)PrValidate(prRecHdl);
  839.             error = PrError();
  840.  
  841.             if ( error == noErr )
  842.             {
  843.                 changed = PrStlDialog(prRecHdl);
  844.                 error = PrError();
  845.  
  846.                 if ( changed )
  847.                     result = gxOKSelected;
  848.                 else
  849.                     result = gxCancelSelected;
  850.  
  851.                 if ( error == noErr && result == gxCancelSelected )
  852.                 {
  853.                     PrSetError(iPrAbort);
  854.                     error = iPrAbort;
  855.                 }
  856.             }
  857.         }
  858.         QDPrClose();
  859.  
  860.         (*gxprJob)->error = error;
  861.     }
  862.  
  863.     return result;
  864. }
  865.  
  866. /* ---------------------------------------------------------------------------
  867.     GXPrGetJobPageRange
  868.   --------------------------------------------------------------------------- */
  869.  
  870. void GXPrGetJobPageRange(gxprJobHdl gxprJob, long *firstPage, long *lastPage)
  871. {
  872.     if ( gxprJob == nil )
  873.         return;
  874.  
  875.     if ( (*gxprJob)->architecture == kGXPrArch )
  876.     {
  877.         GXGetJobPageRange((*gxprJob)->job, firstPage, lastPage);
  878.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  879.     }
  880.     else
  881.     {
  882.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  883.  
  884.         *firstPage = (**prRecHdl).prJob.iFstPage;
  885.         *lastPage = (**prRecHdl).prJob.iLstPage;
  886.     }
  887. }
  888.  
  889. /* ---------------------------------------------------------------------------
  890.     GXPrStartJob
  891.   --------------------------------------------------------------------------- */
  892.  
  893. void GXPrStartJob(gxprJobHdl gxprJob, StringPtr docName, long pageCount)
  894. {
  895.     PrIdleUPP    idleUPP = nil;
  896.  
  897.     if ( gxprJob == nil )
  898.         return;
  899.  
  900.     if ( (*gxprJob)->architecture == kGXPrArch )
  901.     {
  902.         GXStartJob((*gxprJob)->job, docName, pageCount);
  903.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  904.     }
  905.     else
  906.     {
  907.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  908.  
  909.         /*    SetUpCursors(kWatchACursor); */
  910.         GetPort(&(*gxprJob)->savedPort);
  911.  
  912.         (*gxprJob)->error = QDPrOpen();
  913.  
  914.         if ( (*gxprJob)->error == noErr )
  915.         {
  916.             /*    Save the current resource file (i.e., the printer driver's)
  917.                 so the driver will not lose its resources upon return from the
  918.                 pIdleProc.
  919.             */
  920.             (*gxprJob)->prResFile = CurResFile();
  921.  
  922.             /*    Install a routine descriptor for the pIdle proc in the print
  923.                 record. Use an intermediate variable to assign this indirectly
  924.                 because NewPrIdleProc may move memory.
  925.             */
  926.             idleUPP = NewPrIdleProc(QDIdleProc);
  927.             (**prRecHdl).prJob.pIdleProc = idleUPP;
  928.  
  929.             /*    Select the maximum resolution of the printer. */
  930.  
  931.             if ( (*gxprJob)->prResolution != 0 )
  932.             {
  933.                 (*gxprJob)->savedHRes = (**prRecHdl).prInfo.iHRes;
  934.                 (*gxprJob)->savedVRes = (**prRecHdl).prInfo.iVRes;
  935.                 (*gxprJob)->error = QDPrSetResolution(prRecHdl, (*gxprJob)->prResolution, (*gxprJob)->prResolution);
  936.             }
  937.  
  938. #if 0
  939.             {
  940.                 long    jobFirst, jobLast;
  941.  
  942.                 /*    DetermineNumberOfPagesinDoc determines the number of pages
  943.                     contained in the document by comparing the size of the document
  944.                     with rPage from the TPrInfo record (Inside Macintosh: Imaging With
  945.                     QuickDraw p.9-46). It returns the number of pages required to
  946.                     print the document for the currently selected printer.
  947.                 */
  948.                 realNumberOfPagesInDoc = DetermineNumberOfPagesinDoc((**prRecHdl).prInfo.rPage);
  949.  
  950.                 /*    Get the number of copies of the document that the user wants
  951.                     printed from iCopies of the TPrJob record (Inside Macintosh:
  952.                     Imaging With QuickDraw p.9-47).
  953.                 */
  954.                 numberOfCopies = (**prRecHdl).prJob.iCopies;
  955.  
  956.                 /*    Determine which pages the user selected to print. If the
  957.                     user specifies a range that is greater than the actual number of
  958.                     pages, then only print those pages that are in the document.
  959.                 */
  960.                 jobFirst = (**prRecHdl).prJob.iFstPage;
  961.                 jobLast = (**prRecHdl).prJob.iLstPage;
  962.  
  963.                 if ( jobFirst < 1 )
  964.                     jobFirst = 1;
  965.                 if ( jobFirst > realNumberOfPagesInDoc )
  966.                     jobFirst = realNumberOfPagesInDoc;
  967.  
  968.                 if ( jobLast < jobFirst )
  969.                     jobLast = jobFirst;
  970.                 if ( jobLast > realNumberOfPagesInDoc )
  971.                     jobLast = realNumberOfPagesInDoc;
  972.             }
  973. #endif
  974.  
  975.             (**prRecHdl).prJob.iFstPage = 1;
  976.             (**prRecHdl).prJob.iLstPage = 9999;
  977.  
  978.             /*    Restore the resource file to the printer driver's. */
  979.  
  980.             UseResFile((*gxprJob)->prResFile);
  981.  
  982.             (*gxprJob)->prPort = PrOpenDoc(prRecHdl, nil, nil);
  983.             (*gxprJob)->error = PrError();
  984.         }
  985.     }
  986. }
  987.  
  988. /* ---------------------------------------------------------------------------
  989.     GXPrStartPage
  990.   --------------------------------------------------------------------------- */
  991.  
  992. void GXPrStartPage(gxprJobHdl gxprJob, long pageNumber, gxprFormatHdl gxprFormat, long numViewPorts, gxViewPort *viewPortList)
  993. {
  994.     if ( gxprJob == nil )
  995.         return;
  996.  
  997.     if ( (*gxprJob)->architecture == kGXPrArch )
  998.     {
  999.         gxFormat    format;
  1000.  
  1001.         if ( gxprFormat != nil )
  1002.             format = (*gxprFormat)->format;
  1003.         else
  1004.             format = GXGetJobFormat((*gxprJob)->job, 1);
  1005.  
  1006.         GXStartPage((*gxprJob)->job, pageNumber, format, numViewPorts, viewPortList);
  1007.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  1008.     }
  1009.     else
  1010.     {
  1011.         SetPort((GrafPtr)(*gxprJob)->prPort);
  1012.  
  1013.         (*gxprJob)->error = SetViewportContext(gxprJob, numViewPorts, viewPortList);
  1014.  
  1015.         if ( (gPrintingOptions & kUseShapeToQuickDrawPictureConversion) == 0 )
  1016.         {
  1017.             PrOpenPage((*gxprJob)->prPort, nil);
  1018.  
  1019.             if ( (*gxprJob)->error == noErr )
  1020.                 (*gxprJob)->error = PrError();
  1021.         }
  1022.     }
  1023. }
  1024.  
  1025. /* ---------------------------------------------------------------------------
  1026.     GXPrDrawPicture
  1027.     This routine converts a shape to a QuickDraw picture containing flattened
  1028.     QuickDraw GX data encoded as QuickTime compressed data. It then
  1029.     calls the DrawPicture function to display the image, which uses the StdPix
  1030.     bottleneck routine to decompress the data and the StdBits bottleneck
  1031.     routine to render the image. 
  1032.   --------------------------------------------------------------------------- */
  1033.  
  1034. void GXPrDrawPicture(gxprJobHdl gxprJob, gxShape theShape, Fixed hScale, Fixed vScale)
  1035. {
  1036.     PicHandle    picture;
  1037.  
  1038.     picture = GXCdShapeToPicture(theShape, nil, ff(1), ff(1), false, true);
  1039.  
  1040.     if ( picture == nil )
  1041.         return;
  1042.  
  1043.     PrOpenPage((*gxprJob)->prPort, nil);
  1044.     (*gxprJob)->error = PrError();
  1045.  
  1046.     /*    Draw the data for the page if there are no errors. */
  1047.  
  1048.     if ( (*gxprJob)->error == noErr )
  1049.     {
  1050.         gxRectangle    bounds;
  1051.         Rect        dstRect;
  1052.         gxRectangle    geometry;
  1053.         gxShape        shape;
  1054.  
  1055.         (void)ShortRectToFixed(&(**picture).picFrame, &bounds);
  1056.         shape = GXNewRectangle(&bounds);
  1057.  
  1058.         GXScaleShape(shape, hScale, vScale, bounds.left, bounds.top);
  1059.         GXGetShapeBounds(shape, 0, &geometry);
  1060.  
  1061.         FixedRectToShort(&geometry, &dstRect);
  1062.         GXDisposeShape(shape);
  1063.  
  1064.         DrawPicture(picture, &dstRect);
  1065.         KillPicture(picture);
  1066.     }
  1067.  
  1068.     PrClosePage((*gxprJob)->prPort);
  1069.  
  1070.     if ( (*gxprJob)->error == noErr )
  1071.         (*gxprJob)->error = PrError();
  1072. }
  1073.  
  1074. /* ---------------------------------------------------------------------------
  1075.     GXPrPrintPage
  1076.   --------------------------------------------------------------------------- */
  1077.  
  1078. void GXPrPrintPage(gxprJobHdl gxprJob, long pageNumber, gxprFormatHdl gxprFormat, gxShape thePage)
  1079. {
  1080.     if ( gxprJob == nil )
  1081.         return;
  1082.  
  1083.     if ( (*gxprJob)->architecture == kGXPrArch )
  1084.     {
  1085.         GXPrintPage((*gxprJob)->job, pageNumber, (*gxprFormat)->format, thePage);
  1086.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  1087.     }
  1088.     else
  1089.     {
  1090.         Fixed    hScale = ff(1);
  1091.         Fixed    vScale = ff(1);
  1092.  
  1093.         if ( (*gxprJob)->prResolution != 0 )
  1094.         {
  1095.             hScale = FixRatio((*gxprJob)->prResolution, (*gxprJob)->savedHRes);
  1096.             vScale = FixRatio((*gxprJob)->prResolution, (*gxprJob)->savedVRes);
  1097.         }
  1098.  
  1099.         SetPort((GrafPtr)(*gxprJob)->prPort);
  1100.  
  1101.         if ( (gPrintingOptions & kUseShapeToQuickDrawPictureConversion) != 0 )
  1102.         {
  1103.             GXPrDrawPicture(gxprJob, thePage, hScale, vScale);
  1104.         }
  1105.         else
  1106.         {
  1107.             PrOpenPage((*gxprJob)->prPort, nil);
  1108.             (*gxprJob)->error = PrError();
  1109.  
  1110.             if ( (*gxprJob)->error == noErr )
  1111.                 GXCdDrawShape(thePage, nil, hScale, vScale, false, true);
  1112.  
  1113.             PrClosePage((*gxprJob)->prPort);
  1114.  
  1115.             if ( (*gxprJob)->error == noErr )
  1116.                 (*gxprJob)->error = PrError();
  1117.         }
  1118.     }
  1119. }
  1120.  
  1121. /* ---------------------------------------------------------------------------
  1122.     GXPrFinishPage
  1123.   --------------------------------------------------------------------------- */
  1124.  
  1125. void GXPrFinishPage(gxprJobHdl gxprJob)
  1126. {
  1127.     if ( gxprJob == nil )
  1128.         return;
  1129.  
  1130.     if ( (*gxprJob)->architecture == kGXPrArch )
  1131.     {
  1132.         GXFinishPage((*gxprJob)->job);
  1133.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  1134.     }
  1135.     else
  1136.     {
  1137.         Fixed    hScale = ff(1);
  1138.         Fixed    vScale = ff(1);
  1139.         OSErr    error;
  1140.  
  1141.         if ( (*gxprJob)->prResolution != 0 )
  1142.         {
  1143.             hScale = FixRatio((*gxprJob)->prResolution, (*gxprJob)->savedHRes);
  1144.             vScale = FixRatio((*gxprJob)->prResolution, (*gxprJob)->savedVRes);
  1145.         }
  1146.  
  1147.         if ( (gPrintingOptions & kUseShapeToQuickDrawPictureConversion) != 0 )
  1148.         {
  1149.             GXPrDrawPicture(gxprJob, (**(*gxprJob)->vpContextHdl).shape, hScale, vScale);
  1150.         }
  1151.         else
  1152.         {
  1153.             GXCdDrawShape((**(*gxprJob)->vpContextHdl).shape, nil, hScale, vScale, false, true);
  1154.  
  1155.             PrClosePage((*gxprJob)->prPort);
  1156.  
  1157.             if ( (*gxprJob)->error == noErr )
  1158.                 (*gxprJob)->error = PrError();
  1159.         }
  1160.  
  1161.         error = RestoreViewportContext(gxprJob);
  1162.  
  1163.         if ( (*gxprJob)->error == noErr )
  1164.             (*gxprJob)->error = error;
  1165.  
  1166.     }
  1167. }
  1168.  
  1169. /* ---------------------------------------------------------------------------
  1170.     GXPrFinishJob
  1171.   --------------------------------------------------------------------------- */
  1172.  
  1173. void GXPrFinishJob(gxprJobHdl gxprJob)
  1174. {
  1175.     TPrStatus     prStatus;
  1176.  
  1177.     if ( gxprJob == nil )
  1178.         return;
  1179.  
  1180.     if ( (*gxprJob)->architecture == kGXPrArch )
  1181.     {
  1182.         GXFinishJob((*gxprJob)->job);
  1183.         (*gxprJob)->error = GXGetJobError((*gxprJob)->job);
  1184.     }
  1185.     else
  1186.     {
  1187.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  1188.  
  1189.         if ( (*gxprJob)->prPort != nil )
  1190.         {
  1191.             PrCloseDoc((*gxprJob)->prPort);
  1192.  
  1193.             if ( (*gxprJob)->error == noErr )
  1194.                 (*gxprJob)->error = PrError();
  1195.         }
  1196.  
  1197.         if ( prRecHdl != nil )
  1198.         {
  1199.             if ( (*gxprJob)->error == noErr && (**prRecHdl).prJob.bJDocLoop == bSpoolLoop )
  1200.                 PrPicFile(prRecHdl, nil, nil, nil, &prStatus);
  1201.         }
  1202.  
  1203.         /*    Restore the resolution of the printer. */
  1204.  
  1205.         if ( (*gxprJob)->prResolution != 0 )
  1206.         {
  1207.             QDPrSetResolution(prRecHdl, (*gxprJob)->savedHRes, (*gxprJob)->savedVRes);
  1208.             (*gxprJob)->savedHRes = 0;
  1209.             (*gxprJob)->savedVRes = 0;
  1210.         }
  1211.  
  1212.         QDPrClose();
  1213.  
  1214.         SetPort((*gxprJob)->savedPort);
  1215.         /*    TearDownCursors(kArrowCursor); */
  1216.  
  1217.         if ( prRecHdl != nil )
  1218.         {
  1219.             PrIdleUPP    idleUPP;
  1220.  
  1221.             if ( (idleUPP = (**prRecHdl).prJob.pIdleProc) != nil )
  1222.                 DisposeRoutineDescriptor((UniversalProcPtr)idleUPP);
  1223.  
  1224.             (**prRecHdl).prJob.pIdleProc = nil;
  1225.         }
  1226.     }
  1227. }
  1228.  
  1229. /* ---------------------------------------------------------------------------
  1230.     GXPrSetJobCopies
  1231.     This routine sets or replaces the information in the copies item of a print
  1232.     job. If the oldDataPtr parameter is not nil, this routine returns the
  1233.     information stored in the old item prior to replacing it with the new
  1234.     information. If the collection item does not exist, it returns nil in the
  1235.     oldDataPtr parameter.
  1236.   --------------------------------------------------------------------------- */
  1237.  
  1238. OSErr GXPrSetJobCopies(gxprJobHdl gxprJob, gxCopiesInfo *newData, gxCopiesInfo **oldDataPtr)
  1239. {
  1240.     long    oldDataSize = sizeof(gxCopiesInfo);
  1241.     OSErr    error = noErr;
  1242.  
  1243.     if ( gxprJob == nil )
  1244.         return paramErr;
  1245.  
  1246.     if ( (*gxprJob)->architecture == kGXPrArch )
  1247.     {
  1248.         Collection    collectionRef;
  1249.  
  1250.         collectionRef = GXGetJobCollection((*gxprJob)->job);
  1251.         error = ReplaceCollectionItem(collectionRef,
  1252.                                       gxCopiesTag,
  1253.                                       gxPrintingTagID,
  1254.                                       sizeof(gxCopiesInfo),
  1255.                                       newData,
  1256.                                       &oldDataSize,
  1257.                                       oldDataPtr);
  1258.     }
  1259.     else
  1260.     {
  1261.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  1262.  
  1263.         if ( oldDataPtr != nil )
  1264.         {
  1265.             /*    Allocate the temporary buffer for the old collection item information. */
  1266.  
  1267.             *oldDataPtr = (gxCopiesInfo *)NewPtrClear(oldDataSize);
  1268.             if ( *oldDataPtr == nil )
  1269.             {
  1270.                 error = MemError();
  1271.                 goto NewPtrClearFailed;
  1272.             }
  1273.  
  1274.             (**oldDataPtr).copies = (**prRecHdl).prJob.iCopies;
  1275.         }
  1276.  
  1277.         /*    Set the new value in the print record. */
  1278.  
  1279.         (**prRecHdl).prJob.iCopies = (*newData).copies;
  1280.     }
  1281.  
  1282. NewPtrClearFailed:
  1283.     (*gxprJob)->error = error;
  1284.     return error;
  1285. }
  1286.  
  1287. /* ---------------------------------------------------------------------------
  1288.     GXPrSetJobFileDestination
  1289.     This routine sets or replaces the information in the file destination item
  1290.     of a print job. If the oldDataPtr parameter is not nil, this routine
  1291.     returns the information stored in the old item prior to replacing it with
  1292.     the new information. If the collection item does not exist, it returns nil
  1293.     in the oldDataPtr parameter.
  1294.   --------------------------------------------------------------------------- */
  1295.  
  1296. OSErr GXPrSetJobFileDestination(gxprJobHdl gxprJob, gxFileDestinationInfo *newData, gxFileDestinationInfo **oldDataPtr)
  1297. {
  1298.     long    oldDataSize = sizeof(gxFileDestinationInfo);
  1299.     OSErr    error = noErr;
  1300.  
  1301.     if ( gxprJob == nil )
  1302.         return paramErr;
  1303.  
  1304.     if ( (*gxprJob)->architecture == kGXPrArch )
  1305.     {
  1306.         Collection    collectionRef;
  1307.  
  1308.         collectionRef = GXGetJobCollection((*gxprJob)->job);
  1309.         error = ReplaceCollectionItem(collectionRef,
  1310.                                       gxFileDestinationTag,
  1311.                                       gxPrintingTagID,
  1312.                                       sizeof(gxFileDestinationInfo),
  1313.                                       newData,
  1314.                                       &oldDataSize,
  1315.                                       oldDataPtr);
  1316.     }
  1317.     else
  1318.     {
  1319.         if ( oldDataPtr != nil )
  1320.         {
  1321.             /*    Allocate the temporary buffer for the old collection item information. */
  1322.  
  1323.             *oldDataPtr = (gxFileDestinationInfo *)NewPtrClear(oldDataSize);
  1324.             if ( *oldDataPtr == nil )
  1325.             {
  1326.                 error = MemError();
  1327.                 goto NewPtrClearFailed;
  1328.             }
  1329.  
  1330.             /*    There is no way to determine or set this information in the QuickDraw
  1331.                 print record, so the printer destination is set by default.
  1332.             */
  1333.             (**oldDataPtr).toFile = false;
  1334.         }
  1335.     }
  1336.  
  1337. NewPtrClearFailed:
  1338.     (*gxprJob)->error = error;
  1339.     return error;
  1340. }
  1341.  
  1342. /* ---------------------------------------------------------------------------
  1343.     GXPrSetJobPageRange
  1344.     This routine sets or replaces the information in the page range item of a
  1345.     print job. If the oldDataPtr parameter is not nil, this routine returns
  1346.     the information stored in the old item prior to replacing it with the new
  1347.     information. If the collection item does not exist, it returns nil in the
  1348.     oldDataPtr parameter. Note that newDataSize is in the parameter list of
  1349.     this function because gxPageRangeInfo is a variable size data structure.
  1350.   --------------------------------------------------------------------------- */
  1351.  
  1352. OSErr GXPrSetJobPageRange(gxprJobHdl gxprJob, long newDataSize, gxPageRangeInfo *newData, long *oldDataSize, gxPageRangeInfo **oldDataPtr)
  1353. {
  1354.     OSErr    error = noErr;
  1355.  
  1356.     if ( gxprJob == nil )
  1357.         return paramErr;
  1358.  
  1359.     if ( (*gxprJob)->architecture == kGXPrArch )
  1360.     {
  1361.         Collection    collectionRef;
  1362.  
  1363.         collectionRef = GXGetJobCollection((*gxprJob)->job);
  1364.         error = ReplaceCollectionItem(collectionRef,
  1365.                                       gxPageRangeTag,
  1366.                                       gxPrintingTagID,
  1367.                                       newDataSize,
  1368.                                       newData,
  1369.                                       oldDataSize,
  1370.                                       oldDataPtr);
  1371.     }
  1372.     else
  1373.     {
  1374.         THPrint    prRecHdl = (*gxprJob)->prRecHdl;
  1375.  
  1376.         if ( oldDataPtr != nil )
  1377.         {
  1378.             /*    Allocate the temporary buffer for the old collection item information. */
  1379.  
  1380.             *oldDataPtr = (gxPageRangeInfo *)NewPtrClear(*oldDataSize);
  1381.             if ( *oldDataPtr == nil )
  1382.             {
  1383.                 error = MemError();
  1384.                 goto NewPtrClearFailed;
  1385.             }
  1386.  
  1387.             (**oldDataPtr).simpleRange.optionChosen = gxDefaultPageRange;
  1388.             (**oldDataPtr).simpleRange.fromPage = (**prRecHdl).prJob.iFstPage;
  1389.             (**oldDataPtr).simpleRange.toPage = (**prRecHdl).prJob.iLstPage;
  1390.             (**oldDataPtr).simpleRange.printAll = false;
  1391.         }
  1392.  
  1393.         /*    Set the new values in the print record. */
  1394.  
  1395.         if ( newData->simpleRange.printAll )
  1396.         {
  1397.             (**prRecHdl).prJob.iFstPage = 1;
  1398.             (**prRecHdl).prJob.iLstPage = iPrPgMax;
  1399.         }
  1400.         else
  1401.         {
  1402.             (**prRecHdl).prJob.iFstPage = (*newData).simpleRange.fromPage;
  1403.             (**prRecHdl).prJob.iLstPage = (*newData).simpleRange.toPage;
  1404.         }
  1405.     }
  1406.  
  1407. NewPtrClearFailed:
  1408.     (*gxprJob)->error = error;
  1409.     return error;
  1410. }
  1411.  
  1412. /* ===========================================================================
  1413.     Private functions
  1414.   =========================================================================== */
  1415.  
  1416. /* ---------------------------------------------------------------------------
  1417.     QuickDraw conversion utility functions
  1418.   --------------------------------------------------------------------------- */
  1419.  
  1420. static gxRectangle *ShortRectToFixed(const Rect *shortRect, gxRectangle *fixedRect)
  1421. {
  1422.     register Fixed *coord;
  1423.  
  1424.     if (shortRect == nil)
  1425.     {
  1426.         GXPostGraphicsError(parameter_is_nil);
  1427.         return nil;
  1428.     }
  1429.  
  1430.     if (fixedRect == nil)
  1431.     {
  1432.         GXPostGraphicsError(parameter_is_nil);
  1433.         return nil;
  1434.     }
  1435.  
  1436.     coord = (Fixed *)fixedRect;
  1437.     *coord++ = IntToFixed(shortRect->left);
  1438.     *coord++ = IntToFixed(shortRect->top);
  1439.     *coord++ = IntToFixed(shortRect->right);
  1440.     *coord = IntToFixed(shortRect->bottom);
  1441.     return fixedRect;
  1442. }
  1443.  
  1444. static Rect *FixedRectToShort(const gxRectangle *fixedRect, Rect *shortRect)
  1445. {
  1446.     register short *coord;
  1447.  
  1448.     if (shortRect == nil)
  1449.     {
  1450.         GXPostGraphicsError(parameter_is_nil);
  1451.         return nil;
  1452.     }
  1453.  
  1454.     if (fixedRect == nil)
  1455.     {
  1456.         GXPostGraphicsError(parameter_is_nil);
  1457.         return nil;
  1458.     }
  1459.  
  1460.     coord = (short *)shortRect;
  1461.     *coord++ = FixedRound(fixedRect->top);
  1462.     *coord++ = FixedRound(fixedRect->left);
  1463.     *coord++ = FixedRound(fixedRect->bottom);
  1464.     *coord = FixedRound(fixedRect->right);
  1465.     return shortRect;
  1466. }
  1467.  
  1468. /* ---------------------------------------------------------------------------
  1469.     QDInitPrinting
  1470.     This routine checks if the QuickDraw printing manager is available to the
  1471.     application.
  1472.   --------------------------------------------------------------------------- */
  1473.  
  1474. static OSErr QDInitPrinting(void)
  1475. {
  1476.     OSErr error = QDPrOpen();
  1477.     QDPrClose();
  1478.  
  1479.     return error;
  1480. }
  1481.  
  1482. /* ---------------------------------------------------------------------------
  1483.     QDPrOpen
  1484.     This routine allows nested calls to PrOpen/PrClose by keeping track of
  1485.     the number of calls that have been made in the global gPrOpenCount.
  1486.   --------------------------------------------------------------------------- */
  1487.  
  1488. static OSErr QDPrOpen(void)
  1489. {
  1490.     OSErr    error = noErr;
  1491.  
  1492.     gPrOpenCount++;
  1493.  
  1494.     if ( gPrOpenCount == 1 )
  1495.     {
  1496.         PrOpen();
  1497.         error = PrError();
  1498.  
  1499.         /*    Here "file not found" really means "no printer chosen." */
  1500.  
  1501.         if ( error == fnfErr )
  1502.             error = noPrinterChosenErr;
  1503.     }
  1504.  
  1505.     return error;
  1506. }
  1507.  
  1508. /* ---------------------------------------------------------------------------
  1509.     QDPrClose
  1510.     This routine allows nested calls to PrOpen/PrClose by keeping track of
  1511.     the number of calls that have been made in the global gPrOpenCount.
  1512.   --------------------------------------------------------------------------- */
  1513.  
  1514. static void QDPrClose(void)
  1515. {
  1516.     if ( gPrOpenCount > 0 )
  1517.         gPrOpenCount--;
  1518.  
  1519.     if ( gPrOpenCount == 0 )
  1520.         PrClose();
  1521. }
  1522.  
  1523. /* ---------------------------------------------------------------------------
  1524.     QDPrGetMaxResolution
  1525.     Find the highest "square" resolution supported by the currently selected
  1526.     printer driver.
  1527.   --------------------------------------------------------------------------- */
  1528.  
  1529. static OSErr QDPrGetMaxResolution(short *maxDPI)
  1530. {
  1531.     OSErr    error = noErr;
  1532.  
  1533.     *maxDPI = 0;
  1534.  
  1535.     {
  1536.         short        resIndex;
  1537.         TGetRslBlk    getResRec;
  1538.  
  1539.         getResRec.iOpCode = getRslDataOp;
  1540.         PrGeneral((Ptr)&getResRec);
  1541.  
  1542.         error = PrError();
  1543.  
  1544.         if ( error == noErr )
  1545.         {
  1546.             error = getResRec.iError;
  1547.         }
  1548.         else if ( error == resNotFound )
  1549.         {
  1550.             /*    If resNotFound is returned by PrError, then the current printer
  1551.                 driver doesn’t support PrGeneral.
  1552.             */
  1553.             PrSetError(noErr);
  1554.         }
  1555.  
  1556.         /*    At this point, we have an array of possible resolutions. After
  1557.             checking for errors, we loop through each resolution range record
  1558.             looking for the highest resolution available, where x and y are equal.
  1559.             This loop makes no assumptions about the order of the resolution
  1560.             records.
  1561.         */
  1562.         if ( error == noErr )
  1563.         {
  1564.             for ( resIndex = 0; resIndex < getResRec.iRslRecCnt; resIndex++ )
  1565.             {
  1566.                 if ( getResRec.rgRslRec[resIndex].iXRsl ==    getResRec.rgRslRec[resIndex].iYRsl &&
  1567.                     getResRec.rgRslRec[resIndex].iXRsl > *maxDPI )
  1568.                     *maxDPI = getResRec.rgRslRec[resIndex].iYRsl;
  1569.             }
  1570.         }
  1571.     }
  1572.  
  1573.     return error;
  1574. }
  1575.  
  1576. /* ---------------------------------------------------------------------------
  1577.     QDPrSetResolution
  1578.     Set the resolution of the currently selected printer driver.
  1579.   --------------------------------------------------------------------------- */
  1580.  
  1581. static OSErr QDPrSetResolution(THPrint prRecHdl, short iXRsl, short iYRsl)
  1582. {
  1583.     OSErr    error = noErr;
  1584.  
  1585.     if ( prRecHdl == nil )
  1586.         return paramErr;
  1587.  
  1588.     {
  1589.         TSetRslBlk    setResRec;
  1590.  
  1591.         if ( iXRsl != 0 && iYRsl != 0 )
  1592.         {
  1593.             setResRec.iOpCode = setRslOp;
  1594.             setResRec.hPrint = prRecHdl;
  1595.             setResRec.iXRsl = iXRsl;
  1596.             setResRec.iYRsl = iYRsl;
  1597.             PrGeneral((Ptr)&setResRec);
  1598.  
  1599.             error = PrError();
  1600.  
  1601.             if ( error == noErr )
  1602.             {
  1603.                 error = setResRec.iError;
  1604.             }
  1605.             else if ( error == resNotFound )
  1606.             {
  1607.                 /*    If resNotFound is returned by PrError, then the current printer
  1608.                     driver doesn’t support PrGeneral.
  1609.                 */
  1610.                 PrSetError(noErr);
  1611.             }
  1612.         }
  1613.     }
  1614.  
  1615.     return error;
  1616. }
  1617.  
  1618. /* ---------------------------------------------------------------------------
  1619.     QDIdleProc
  1620.     This routine is a PrIdleProcPtr that spins the cursor and looks for
  1621.     command-period presses during printing.
  1622.   --------------------------------------------------------------------------- */
  1623.  
  1624. pascal void QDIdleProc(void)
  1625. {
  1626.     OSErr    error;
  1627.  
  1628. //    BumpCursor();
  1629.     error = QDCommandPeriod();
  1630.     if ( error != noErr )
  1631.         PrSetError(error);
  1632. }
  1633.  
  1634. /* ---------------------------------------------------------------------------
  1635.     QDCommandPeriod
  1636.     This routine checks to see if the user has pressed command-period. The
  1637.     Printing Manager does this for us, but a routine like this is helpful to
  1638.     allow users to cancel in the middle of a rendering routine, rather than
  1639.     only Printing Manager operations. If there's a command-period in the event
  1640.     queue, the routine returns iPrAbort just like the Printing Manager;
  1641.     otherwise, it returns noErr.
  1642.   --------------------------------------------------------------------------- */
  1643.  
  1644. static OSErr QDCommandPeriod(void)
  1645. {
  1646.     short            eventMask = keyDownMask | autoKeyMask | mDownMask;
  1647.     EventRecord        event;
  1648.     WindowPtr        window;
  1649.     short            itemHit;
  1650.     Boolean            userCancel = false;
  1651.     
  1652.     if ( WaitNextEvent(eventMask, &event, 0, nil) )
  1653.     {
  1654.         switch ( event.what )
  1655.         {
  1656.             case mouseDown:
  1657.                 if ( IsDialogEvent(&event) )
  1658.                     if ( FindWindow(event.where, &window) == inContent )
  1659.                         if ( window != nil )
  1660.                         {
  1661. //                            if ( ((WindowPeek)window)->windowKind == userKind )
  1662.                                 if ( DialogSelect(&event, (DialogPtr *)&window, &itemHit) )
  1663.                                     userCancel = (itemHit == kStdCancelItemIndex);
  1664.                         }
  1665.                 break;
  1666.  
  1667.             case keyDown:
  1668.             case autoKey:
  1669.                 userCancel = (event.modifiers & cmdKey) && ((event.message & charCodeMask) == '.');
  1670.                 break;
  1671.         }
  1672.     }
  1673.  
  1674.     return ( (userCancel) ? (iPrAbort) : (noErr) );
  1675. }
  1676.  
  1677. /* ---------------------------------------------------------------------------
  1678.     ReplaceCollectionItem
  1679.     This utility routine sets or replaces the information in a collection item.
  1680.     If the oldDataPtr parameter is not nil, this routine returns the
  1681.     information stored in the old item prior to replacing it with the new
  1682.     information. If the collection item does not exist, it returns nil in the
  1683.     oldDataPtr parameter.
  1684.   --------------------------------------------------------------------------- */
  1685.  
  1686. static OSErr ReplaceCollectionItem(
  1687.                 Collection        collectionRef,
  1688.                 OSType            collectionType,
  1689.                 long            collectionID,
  1690.                 long            collectionSize,
  1691.                 void            *newData,
  1692.                 long            *oldDataSize,
  1693.                 void            **oldDataPtr)
  1694. {
  1695.     long    index;
  1696.     OSErr    error = noErr;
  1697.  
  1698.     if ( newData == nil )
  1699.         return paramErr;
  1700.  
  1701.     if ( oldDataPtr != nil )
  1702.     {
  1703.         /*    Determine the size of the collection item. */
  1704.  
  1705.         error = GetCollectionItem(collectionRef,
  1706.                                   collectionType,
  1707.                                   collectionID,
  1708.                                   oldDataSize,
  1709.                                   dontWantData);
  1710.  
  1711.         if ( error == noErr )
  1712.         {
  1713.             /*    Allocate the temporary buffer for the old collection item information. */
  1714.  
  1715.             *oldDataPtr = NewPtrClear(*oldDataSize);
  1716.             if ( *oldDataPtr == nil )
  1717.             {
  1718.                 error = MemError();
  1719.                 goto NewPtrClearFailed;
  1720.             }
  1721.  
  1722.             /*    Obtain a copy of the collection item information. */
  1723.  
  1724.             error = GetCollectionItem(collectionRef,
  1725.                                       collectionType,
  1726.                                       collectionID,
  1727.                                       dontWantSize,
  1728.                                       *oldDataPtr);
  1729.  
  1730.             if ( error != noErr )
  1731.                 goto GetCollectionItemDataFailed;
  1732.         }
  1733.         else
  1734.             *oldDataPtr = nil;
  1735.     }
  1736.  
  1737.     /*    Add or replace the collection item information. */
  1738.  
  1739.     error = AddCollectionItem(collectionRef,
  1740.                               collectionType,
  1741.                               collectionID,
  1742.                               collectionSize,
  1743.                               newData);
  1744.  
  1745.     if ( error == collectionItemLockedErr )
  1746.     {
  1747.         error = GetCollectionItemInfo(collectionRef,
  1748.                                       collectionType,
  1749.                                       collectionID,
  1750.                                       &index,
  1751.                                       dontWantSize,
  1752.                                       dontWantAttributes);
  1753.  
  1754.         if ( error == noErr )
  1755.             error = ReplaceIndexedCollectionItem(collectionRef, index, collectionSize, newData);
  1756.     }
  1757.  
  1758.     goto Completed;
  1759.  
  1760. GetCollectionItemDataFailed:
  1761.     if ( *oldDataPtr != nil )
  1762.     {
  1763.         DisposePtr(*oldDataPtr);
  1764.         *oldDataPtr = nil;
  1765.     }
  1766.  
  1767. NewPtrClearFailed:
  1768. Completed:
  1769.     return error;
  1770. }
  1771.  
  1772. /* ---------------------------------------------------------------------------
  1773.     Viewport filter handling functions
  1774.   --------------------------------------------------------------------------- */
  1775.  
  1776. static OSErr SetViewportContext(gxprJobHdl gxprJob, long numViewPorts, gxViewPort *viewPortList)
  1777. {    gxprViewportContextHdl    context;
  1778.     gxShape                    shape;
  1779.     long                    index;
  1780.     OSErr                    error;
  1781.  
  1782.     if ( gxprJob == nil )
  1783.         return paramErr;
  1784.  
  1785.     context = (gxprViewportContextHdl)NewHandleClear(sizeof(gxShape) + sizeof(long) + sizeof(vpContextRecord) * numViewPorts);
  1786.  
  1787.     shape = GXNewShape(gxPictureType);
  1788.     error = (OSErr)GXGetGraphicsError(nil);
  1789.  
  1790.     if ( error != noErr )
  1791.         goto GXNewShapeFailed;
  1792.  
  1793.     (**context).shape = shape;
  1794.     (**context).vpCount = numViewPorts;
  1795.     (**context).vpContextArray;
  1796.  
  1797.     for ( index = 0; error == noErr && index < numViewPorts; index++ )
  1798.     {
  1799.         (**context).vpContextArray[index].viewport = viewPortList[index];
  1800.         (**context).vpContextArray[index].viewportFilter = GXGetViewPortFilter(viewPortList[index],
  1801.             &(**context).vpContextArray[index].refcon);
  1802.  
  1803.         GXSetViewPortFilter(viewPortList[index], (gxUserViewPortFilter)gGXUserViewPortFilterUPP, (long)shape);
  1804.  
  1805.         error = (OSErr)GXGetGraphicsError(nil);
  1806.     }
  1807.  
  1808.     if ( error == noErr )
  1809.         (*gxprJob)->vpContextHdl = context;
  1810.  
  1811. GXNewShapeFailed:
  1812.     return error;
  1813. }
  1814.  
  1815. static OSErr RestoreViewportContext(gxprJobHdl gxprJob)
  1816. {
  1817.     gxprViewportContextHdl    context;
  1818.     long                    index;
  1819.     OSErr                    error = noErr;
  1820.  
  1821.     if ( gxprJob == nil )
  1822.         return paramErr;
  1823.  
  1824.     context = (*gxprJob)->vpContextHdl;
  1825.     if ( context == nil )
  1826.         return noErr;
  1827.  
  1828.     GXDisposeShape((**context).shape);
  1829.  
  1830.     for ( index = 0; error == noErr && index < (**context).vpCount; index++ )
  1831.     {
  1832.         GXSetViewPortFilter((**context).vpContextArray[index].viewport,
  1833.                             (**context).vpContextArray[index].viewportFilter,
  1834.                             (**context).vpContextArray[index].refcon);
  1835.  
  1836.         error = (OSErr)GXGetGraphicsError(nil);
  1837.     }
  1838.  
  1839.     DisposeHandle((Handle)context);
  1840.     (*gxprJob)->vpContextHdl = nil;
  1841.  
  1842.     return error;
  1843. }
  1844.  
  1845. /* ---------------------------------------------------------------------------
  1846.     GXPrViewPortFilter
  1847.     This filter is used to gather all shapes drawn in the viewports specified
  1848.     in StartPage. The shapes are gathered into a picture which will be passed
  1849.     to PrintPage at FinishPage.
  1850.  
  1851.     If the port has a clip or mapping, then the shape passed in is first
  1852.     inserted into a new picture that has the port's clip and mapping. This
  1853.     picture is then added to the page picture (which is passed in as the
  1854.     refcon).
  1855.   --------------------------------------------------------------------------- */
  1856.  
  1857. static Boolean TestMappingIdentity(gxMapping *mapping)
  1858. {
  1859.     Boolean result;
  1860.     
  1861.     result = (    (mapping->map[0][0] == ff(1)) && (mapping->map[0][1] == ff(0)) && (mapping->map[0][2] == ff(0)) &&
  1862.                 (mapping->map[1][0] == ff(0)) && (mapping->map[1][1] == ff(1)) && (mapping->map[1][2] == ff(0)) &&
  1863.                 (mapping->map[2][0] == ff(0)) && (mapping->map[2][1] == ff(0)) && (mapping->map[2][2] == fract1)
  1864.             ) ? true : false;
  1865.     
  1866.     return result;
  1867. }
  1868.  
  1869. static void GXPrViewPortFilter(gxShape toFilter, gxViewPort portOrder, long refCon)
  1870. {
  1871.     gxShape            printingPicture;
  1872.     gxShape            portClip;
  1873.     gxMapping        portMapping;
  1874.  
  1875.     /*    Add the shape to a picture for printing */
  1876.  
  1877.     printingPicture = (gxShape)refCon;
  1878.     
  1879.     /*    If the portOrder port has no clip or mapping, just add the shape to
  1880.         the printing picture.
  1881.     */
  1882.     portClip = GXGetViewPortClip(portOrder);
  1883.     GXGetViewPortMapping(portOrder, &portMapping);
  1884.     if ( (GXGetShapeType(portClip) == gxFullType) && TestMappingIdentity(&portMapping) )
  1885.     {
  1886.         GXSetPictureParts(printingPicture, 0, 0, 1, &toFilter, nil, nil, nil);    
  1887.     }
  1888.     else
  1889.     {
  1890.         /*    The port had a mapping/clip, so add the shape nested in a picture
  1891.             with the port's mapping and clip.
  1892.         */
  1893.         gxShape nestPicture = GXNewShape(gxPictureType);
  1894.         GXSetShapeClip(nestPicture, portClip);
  1895.         GXSetShapeMapping(nestPicture, &portMapping);
  1896.  
  1897.         /*    Add the toFilter shape to the nest picture. */
  1898.  
  1899.         GXSetPictureParts(nestPicture, 0, 0, 1, &toFilter, nil, nil, nil);
  1900.  
  1901.         /*    Add the nest picture to the page. */
  1902.  
  1903.         GXSetPictureParts(printingPicture, 0, 0, 1, &nestPicture, nil, nil, nil);
  1904.  
  1905.         GXDisposeShape(nestPicture);    
  1906.     }
  1907.  
  1908.     GXDisposeShape(portClip);
  1909. }
  1910.