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

  1. /*
  2.     File:        CodecLibrary.c
  3.  
  4.     Contains:    Graphics library for QuickTime decompression of QuickDraw GX
  5.                 data.
  6.  
  7.                 This library uses QuickTime compression and decompression to
  8.                 image QuickDraw GX data. The basic technique is to encapsulate
  9.                 the QuickDraw GX image in a compressed data format using the
  10.                 object flattening functions from QuickDraw GX. Once the
  11.                 compressed image data is created, it may be passed to the
  12.                 QuickDraw GX codec and drawn using the QuickTime image
  13.                 compression functions or embedded within a QuickDraw picture
  14.                 and drawn using the DrawPicture function. In either case, the
  15.                 compressed data is passed to the the low-level QuickDraw
  16.                 drawing routines through the StdPix bottleneck routine. StdPix
  17.                 decompresses the data using the QuickDraw GX codec and passes
  18.                 the decompressed data to the bitsProc bottleneck routine when
  19.                 rendering the image.
  20.  
  21.     Written by:    Mike Reed
  22.  
  23.     Copyright:    © 1995-1997 by Apple Computer, Inc., all rights reserved.
  24.  
  25.     Writers:
  26.  
  27.         (jtd)    John Daggett
  28.         (DH)    David Hayward
  29.         (IK)    Ingrid Kelly
  30.  
  31.     Change History (most recent first):
  32.  
  33.          <5>      6/1/97    IK        Modify printing routines for GXGraphics 1.1.6.
  34.          <4>      4/8/97    DH        Minor fix.
  35.          <3>      2/6/97    DH        Added ShapeToPICTWithShape.
  36.          <2>     9/14/95    jtd        Replaced boolean with Boolean.
  37.          <1>     9/14/95    jtd        First checked in.
  38. */
  39.  
  40. #include <Drag.h>
  41. #include <Gestalt.h>
  42. #include <GXGraphics.h>
  43. #include <ImageCompression.h>
  44. #include <Scrap.h>
  45.  
  46. #include "CodecLibrary.h"
  47. #include "StorageLibrary.h"
  48. #include "GetShapeLocalBounds.h"
  49.  
  50. /* ---------------------------------------------------------------------------
  51.     Constants 
  52.   --------------------------------------------------------------------------- */
  53.  
  54. #define LONGALIGN(n)            (((n) + 3) & ~3L)
  55. #define kAtomHeaderSize            (sizeof(Size) + sizeof(OSType))
  56.  
  57. #define    gxForPrintingOnlyAtom    'fpto'
  58. #define    gxEraseBackgroundAtom    'erbg'
  59.  
  60. #define kQuickTimeGestalt        'qtim'
  61.  
  62. /* ---------------------------------------------------------------------------
  63.     Function prototypes 
  64.   --------------------------------------------------------------------------- */
  65.  
  66. static gxRectangle    *ShortRectToFixed(const Rect *shortRect, gxRectangle *fixedRect);
  67. static Rect         *FixedRectToShort(const gxRectangle *fixedRect, Rect *shortRect);
  68. static long            *AppendAtom(long stream[], Size size, OSType tag, const void* data);
  69. pascal OSErr        GXCdSendDataProc(FlavorType theType, void *dragSendRefCon, ItemReference theItem, DragReference theDrag);
  70.  
  71. /* ===========================================================================
  72.     Public functions
  73.   =========================================================================== */
  74.  
  75. /* ---------------------------------------------------------------------------
  76.     GXCdShapeToHandle
  77.     This routine flattens a shape to a handle. For an explanation of the
  78.     parameters, see the comment on GXCdShapeToPicture. This routine is used by
  79.     both GXCdShapeToPicture for embedding shapes in QuickDraw pictures and by
  80.     AddQDGXRecorderFrame for making QuickDraw GX movies.
  81.   --------------------------------------------------------------------------- */
  82.  
  83. Handle GXCdShapeToHandle(gxShape source, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground)
  84. {
  85.     long                atomCount, shapeSize, proxieSize, dataSize, fontListSize;
  86.     Handle                dataHdl, shapeHdl;
  87.     gxFlatFontList*        fontList;
  88.     gxTag                fontListTag;
  89.  
  90.     /*    Flatten the shape into a handle and gather font database statistics. */
  91.  
  92.     shapeHdl = GXStShapeToHandleWithFlags(source, gxFontListFlatten | gxFontGlyphsFlatten |
  93.         gxFontVariationsFlatten);
  94.  
  95.     if (shapeHdl == nil)
  96.         return nil;
  97.  
  98.     if (proxie)
  99.     {
  100.         atomCount = 2;
  101.         proxieSize = LONGALIGN(GetHandleSize((Handle)proxie));
  102.     }
  103.     else
  104.     {
  105.         atomCount = 1;
  106.         proxieSize = 0;
  107.     }
  108.     shapeSize = LONGALIGN(GetHandleSize(shapeHdl));
  109.  
  110.     if (forPrintingOnly)
  111.         ++atomCount;
  112.     if (eraseBackground)
  113.         ++atomCount;
  114.  
  115.     /*    Retrieve the font database information. */
  116.  
  117.     fontListSize = 0;
  118.     fontList = nil;
  119.     GXIgnoreGraphicsWarning(count_out_of_range);
  120.     if (GXGetShapeTags(source, gxFlatFontListItemTag, 1, 1, &fontListTag) > 0)
  121.     {
  122.         fontListSize = GXGetTag(fontListTag, nil, nil);
  123.         if (fontListSize > 0)
  124.         {
  125.             fontList = (gxFlatFontList*)NewPtr(fontListSize);
  126.             if (fontList != nil)
  127.             {
  128.                 GXGetTag(fontListTag, nil, fontList);
  129.                 fontListSize = LONGALIGN(fontListSize);
  130.                 ++atomCount;
  131.             }
  132.             else
  133.                 fontListSize = 0;
  134.         }
  135.     }
  136.     GXPopGraphicsWarning();        /*    count_out_of_range */
  137.  
  138.     dataSize = atomCount * kAtomHeaderSize + shapeSize + proxieSize + fontListSize + sizeof(long);
  139.     dataHdl = NewHandle(dataSize);
  140.     if (dataHdl == nil)
  141.     {
  142.         DisposeHandle(shapeHdl);
  143.         if (fontList)
  144.             DisposePtr((Ptr)fontList);
  145.         return nil;
  146.     }
  147.     
  148.     {
  149.         long* p = (long*)*dataHdl;
  150.  
  151.         if (forPrintingOnly)
  152.             p = AppendAtom(p, 0, gxForPrintingOnlyAtom, nil);
  153.         if (eraseBackground)
  154.             p = AppendAtom(p, 0, gxEraseBackgroundAtom, nil);
  155.         if (proxie)
  156.             p = AppendAtom(p, proxieSize, 'PICT', *proxie);
  157.         if (fontList)
  158.             p = AppendAtom(p, fontListSize, gxFlatFontListItemTag, fontList);
  159.         p = AppendAtom(p, shapeSize, 'qdgx', *shapeHdl);
  160.         *p++ = 0;        /*    end of the atom-list */
  161.  
  162.         DisposeHandle(shapeHdl);
  163.         if (fontList)
  164.             DisposePtr((Ptr)fontList);
  165.     }
  166.     return dataHdl;
  167. }
  168.  
  169. /* ---------------------------------------------------------------------------
  170.     GXCdShapeToPicture
  171.     This routine converts a shape to a QuickDraw picture containing flattened
  172.     QuickDraw GX data encoded as QuickTime compressed data. An application may
  173.     then call the DrawPicture function to display the image, which uses the
  174.     StdPix bottleneck routine to decompress the data and the StdBits bottleneck
  175.     routine to render the image. The routine may be used to create a QuickDraw
  176.     picture prior to entering the printing loop or to convert a QuickDraw GX
  177.     picture shape to the QuickDraw PICT file format. DecompressImage is
  178.     described in detail in Inside Macintosh: QuickTime, pages 3-78 to 3-79.
  179.  
  180.     A proxie of the shape may be included in the compressed data to represent
  181.     the shape when QuickDraw GX is not installed. This routine is called by
  182.     GXCdShapeToScrap and GXCdDragAndDropShape.
  183.  
  184.     theShape            • The shape to be embedded in the QuickDraw picture.
  185.     proxie                • The QuickDraw picture to be used when QuickDraw GX
  186.                         is not available.
  187.     hScale                • The horizontal scaling factor.
  188.     vScale                • The vertical scaling factor.
  189.     forPrintingOnly        • If TRUE, then the decompressor will always look for
  190.                         the proxie and theShape will only be used when
  191.                         printing. Use this setting if theShape might be too
  192.                         large or too slow when drawn from other applications.
  193.                         • If FALSE, then the decompressor will draw theShape
  194.                         unless it gets an error, in which case it will look
  195.                         for a proxie.
  196.     eraseBackground        • If TRUE, the decompressor will always erase the
  197.                         background to WHITE before drawing the shape. This is
  198.                         slower but needed if the shape does not fill its
  199.                         bounding rectangle.
  200.                         • If FALSE, the decompressor will just draw the shape.
  201.                         Use this setting if the shape entirely fills its
  202.                         bounding rectangle.
  203.  
  204.     The shape [and proxie] is embedded by constructing a stream of atoms. Each
  205.     atom begins with a size (long) and a type (OSType), and the data for that
  206.     type. After the last atom, there is a trailing zero (long) to mark the end
  207.     of the stream. For embedded shapes, the type is 'qdgx', and for the proxie
  208.     the type is 'PICT'. Note that the size fields are rounded up to a multiple
  209.     of 4. To alert QuickTime that the data is in this parsable form with a
  210.     possible PICT proxie, we add a 'prxy' extension to the QuickTime image
  211.     description.
  212.  
  213.     Picture of this form will draw the embedded shape (or the proxie if
  214.     QuickDraw GX is not available) when an application calls DrawPicture. This
  215.     replaces the PicComment technique described in QuickDraw GX 1.0 for
  216.     embedding shapes in pictures.
  217.  
  218.     If you want to include a flatFontList tag, be sure that theShape is a
  219.     picture, otherwise QuickDraw GX will not return the tag after
  220.     GXFlattenShape. The flatFontList tag makes certain printing conditions
  221.     more efficient (i.e. font downloading to postscript printers).
  222.   --------------------------------------------------------------------------- */
  223.  
  224. PicHandle GXCdShapeToPicture(gxShape theShape, PicHandle proxie, Fixed hScale, Fixed vScale, Boolean forPrintingOnly, Boolean eraseBackground)
  225. {
  226.     PicHandle                picture;
  227.     ImageDescriptionHandle    descHdl;
  228.     ImageDescriptionPtr        descPtr;
  229.     Handle                    dataHdl;
  230.     gxRectangle                bounds;
  231.     long                    version;
  232.     OSErr                    error;
  233.  
  234.     error = Gestalt(kQuickTimeGestalt, &version);
  235.     if (error != noErr)
  236.         return nil;
  237.  
  238.     /*    Move the shape's topLeft to 0,0 so that it draws neatly inside the
  239.         picture frame.
  240.     */
  241.     {
  242.         gxShape    tempShape = theShape;
  243.  
  244.         GetShapeLocalBounds(tempShape, &bounds);
  245.         if (bounds.left != ff(0) || bounds.top != ff(0))
  246.         {
  247.             tempShape = GXCopyToShape(nil, theShape);
  248.  
  249.             GXSetShapeAttributes(tempShape, GXGetShapeAttributes(tempShape) | gxMapTransformShape);
  250.             GXMoveShape(tempShape, -bounds.left, -bounds.top);
  251.             GetShapeLocalBounds(tempShape, &bounds);
  252.         }
  253.         dataHdl = GXCdShapeToHandle(tempShape, proxie, forPrintingOnly, eraseBackground);
  254.  
  255.         if (tempShape != theShape)
  256.             GXDisposeShape(tempShape);
  257.     }
  258.  
  259.     if (dataHdl == nil)
  260.         return nil;
  261.  
  262.     descHdl = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  263.  
  264.     if (descHdl)
  265.     {
  266.         Rect            srcRect;
  267.         Rect            dstRect;
  268.         CodecInfo        codecInfo;
  269.         long            width;
  270.         long            height;
  271.         RgnHandle        savedClipRgn;
  272.  
  273. //        GXGetShapeLocalBounds(theShape, &bounds);
  274.         FixedRectToShort(&bounds, &srcRect);
  275.  
  276.         {
  277.             OpenCPicParams    openCPicParams;
  278.  
  279.             openCPicParams.srcRect = srcRect;
  280.             openCPicParams.hRes = ff(72);
  281.             openCPicParams.vRes = ff(72);
  282.             openCPicParams.version = -2;
  283.             openCPicParams.reserved1 = 0;
  284.             openCPicParams.reserved2 = 0;
  285.             picture = OpenCPicture(&openCPicParams);
  286.         }
  287.  
  288.         if (picture == nil)
  289.         {
  290.             error = QDError();
  291.             goto OpenCPictureFailed;
  292.         }
  293.  
  294.         savedClipRgn = NewRgn();
  295.         GetClip(savedClipRgn);
  296.         ClipRect(&srcRect);
  297.  
  298.         /*    Retrieve information about a specific compressor or about a
  299.             compressor of a specific type. If you request information about a
  300.             type of compressor, the Image Compression Manager returns
  301.             information about the first compressor it finds of that type. This
  302.             will only be used if the data is decompressed on the host instead
  303.             of the printer.
  304.         */
  305.         error = GetCodecInfo(&codecInfo, 'qdgx', bestFidelityCodec);
  306.         if (error != noErr)
  307.             error = GetCodecInfo(&codecInfo, 'qdgx', anyCodec);
  308.  
  309.         if (error != noErr)
  310.             goto GetCodecInfoFailed;
  311.  
  312.         width = srcRect.right - srcRect.left + 1;
  313.         height = srcRect.bottom - srcRect.top + 1;
  314.  
  315.         if (width > 0 && height > 0)
  316.         {
  317.             descPtr = *descHdl;
  318.             descPtr->idSize = sizeof(ImageDescription);
  319.             descPtr->cType = 'qdgx';
  320.             descPtr->resvd1 = 0;
  321.             descPtr->resvd2 = 0;
  322.             descPtr->version = codecInfo.version;
  323.             descPtr->revisionLevel = codecInfo.revisionLevel;
  324.             descPtr->vendor = codecInfo.vendor;
  325.             descPtr->temporalQuality = codecLosslessQuality;
  326.             descPtr->temporalQuality = codecLosslessQuality;
  327.             descPtr->width = width;
  328.             descPtr->height = height;
  329.             descPtr->hRes = ff(72);
  330.             descPtr->vRes = ff(72);
  331.             descPtr->dataSize = GetHandleSize(dataHdl);
  332.             descPtr->frameCount = 1;
  333.             BlockMove(codecInfo.typeName, descPtr->name, 32);
  334.             descPtr->depth = 32;
  335.             descPtr->clutID = -1;
  336.  
  337.             /*    If there is a PICT proxie, add an image description extension
  338.                 for use by QuickTime when QuickDraw GX is not installed.
  339.             */
  340.             if (proxie)
  341.             {
  342.                 Handle prxyVersionHdl = NewHandle(sizeof(long));
  343.  
  344.                 if (prxyVersionHdl != nil)
  345.                 {
  346.                     *(long*)*prxyVersionHdl = 0;        /*    version number for 'prxy' extension */
  347.                     AddImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  348.                 }
  349.             }
  350.  
  351.             /*    The data in the compressed image handle needs to be locked
  352.                 during the call to the DecompressImage routine. We only unlock the
  353.                 data after we're done with the DecompressImage call.
  354.             */
  355.             HLock(dataHdl);
  356.  
  357.             {
  358.                 gxRectangle    geometry;
  359.                 gxShape        shape;
  360.  
  361.                 shape = GXNewRectangle(&bounds);
  362.  
  363.                 GXScaleShape(shape, hScale, vScale, bounds.left, bounds.top);
  364.                 GXGetShapeBounds(shape, 0, &geometry);
  365.  
  366.                 FixedRectToShort(&geometry, &dstRect);
  367.                 GXDisposeShape(shape);
  368.             }
  369.  
  370.             /*    pascal OSErr DecompressImage(Ptr data, 
  371.                                              ImageDescriptionHandle desc,
  372.                                              PixMapHandle dst, const Rect *srcRect, 
  373.                                              const  Rect *dstRect, short mode, 
  374.                                              RgnHandle mask);
  375.             */
  376.             error = DecompressImage(*dataHdl,
  377.                                   descHdl,
  378.                                   ((CGrafPtr)qd.thePort)->portPixMap,
  379.                                   &srcRect,
  380.                                   &dstRect,
  381.                                   ditherCopy,
  382.                                   nil);
  383.  
  384.             HUnlock((Handle)dataHdl);
  385.         }
  386.  
  387. GetCodecInfoFailed:
  388.         ClosePicture();
  389.  
  390.         SetClip(savedClipRgn);
  391.         DisposeRgn(savedClipRgn);
  392.  
  393.         if (error != noErr && picture)
  394.         {
  395.             KillPicture(picture);
  396.             picture = nil;
  397.         }
  398.  
  399. OpenCPictureFailed:
  400.         if (descHdl)
  401.             DisposeHandle((Handle)descHdl);
  402.     }
  403.     else
  404.         picture = nil;
  405.  
  406.     if (dataHdl)
  407.         DisposeHandle(dataHdl);
  408.  
  409.     return picture;
  410. }
  411.  
  412. /* ---------------------------------------------------------------------------
  413.     GXCdDrawShape
  414.     This routine provides an alternative to the technique described in
  415.     GXCdShapeToPicture to image QuickDraw GX data. It passes the QuickDraw GX
  416.     data directly to the StdPix bottleneck as QuickTime compressed data
  417.     encoded within a PixMap data structure. This may be used from within a
  418.     printing loop as outlined in "Printing Images Faster With Data
  419.     Compression," develop 24 (December 1995).
  420.   --------------------------------------------------------------------------- */
  421.  
  422. void GXCdDrawShape(gxShape theShape, PicHandle proxie, Fixed hScale, Fixed vScale, Boolean forPrintingOnly, Boolean eraseBackground)
  423. {
  424.     ImageDescriptionHandle    descHdl;
  425.     ImageDescriptionPtr        descPtr;
  426.     Handle                    dataHdl;
  427.     Ptr                        dataPtr;
  428.     gxRectangle                bounds;
  429.     long                    version;
  430.     OSErr                    error;
  431.  
  432.     error = Gestalt(kQuickTimeGestalt, &version);
  433.     if (error != noErr)
  434.         return;
  435.  
  436.     /*    Move the shape's topLeft to 0,0 so that it draws neatly inside the
  437.         picture frame.
  438.     */
  439.     {
  440.         gxShape    tempShape = theShape;
  441.  
  442.         GetShapeLocalBounds(tempShape, &bounds);
  443.         if (bounds.left != ff(0) || bounds.top != ff(0))
  444.         {
  445.             tempShape = GXCopyToShape(nil, theShape);
  446.  
  447.             GXSetShapeAttributes(tempShape, GXGetShapeAttributes(tempShape) | gxMapTransformShape);
  448.             GXMoveShape(tempShape, -bounds.left, -bounds.top);
  449.             GetShapeLocalBounds(tempShape, &bounds);
  450.         }
  451.         dataHdl = GXCdShapeToHandle(tempShape, proxie, forPrintingOnly, eraseBackground);
  452.  
  453.         if (tempShape != theShape)
  454.             GXDisposeShape(tempShape);
  455.     }
  456.  
  457.     if (dataHdl == nil)
  458.         return;
  459.  
  460.     descHdl = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  461.  
  462.     if (descHdl)
  463.     {
  464.         Rect            srcRect;
  465.         Rect            dstRect;
  466.         CodecInfo        codecInfo;
  467.         long            width;
  468.         long            height;
  469.  
  470. //        GXGetShapeLocalBounds(theShape, &bounds);
  471.         FixedRectToShort(&bounds, &srcRect);
  472.  
  473.         /*    Retrieve information about a specific compressor or about a
  474.             compressor of a specific type. If you request information about a type
  475.             of compressor, the Image Compression Manager returns information about
  476.             the first compressor it finds of that type. This will only be used if
  477.             the data is decompressed on the host instead of the printer.
  478.         */
  479.         error = GetCodecInfo(&codecInfo, 'qdgx', bestFidelityCodec);
  480.         if (error != noErr)
  481.             error = GetCodecInfo(&codecInfo, 'qdgx', anyCodec);
  482.  
  483.         if (error != noErr)
  484.             goto GetCodecInfoFailed;
  485.  
  486.         width = srcRect.right - srcRect.left + 1;
  487.         height = srcRect.bottom - srcRect.top + 1;
  488.  
  489.         if (width > 0 && height > 0)
  490.         {
  491.             descPtr = *descHdl;
  492.             descPtr->idSize = sizeof(ImageDescription);
  493.             descPtr->cType = 'qdgx';
  494.             descPtr->resvd1 = 0;
  495.             descPtr->resvd2 = 0;
  496.             descPtr->version = codecInfo.version;
  497.             descPtr->revisionLevel = codecInfo.revisionLevel;
  498.             descPtr->vendor = codecInfo.vendor;
  499.             descPtr->temporalQuality = codecLosslessQuality;
  500.             descPtr->temporalQuality = codecLosslessQuality;
  501.             descPtr->width = width;
  502.             descPtr->height = height;
  503.             descPtr->hRes = ff(72);
  504.             descPtr->vRes = ff(72);
  505.             descPtr->dataSize = GetHandleSize(dataHdl);
  506.             descPtr->frameCount = 1;
  507.             BlockMove(codecInfo.typeName, descPtr->name, 32);
  508.             descPtr->depth = 32;
  509.             descPtr->clutID = -1;
  510.  
  511.             /*    If there is a PICT proxie, add an image description extension
  512.                 for use by QuickTime when QuickDraw GX is not installed.
  513.             */
  514.             if (proxie)
  515.             {
  516.                 Handle prxyVersionHdl = NewHandle(sizeof(long));
  517.  
  518.                 if (prxyVersionHdl != nil)
  519.                 {
  520.                     *(long*)*prxyVersionHdl = 0;        /*    version number for 'prxy' extension */
  521.                     AddImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  522.                 }
  523.             }
  524.  
  525.             /*    The data in the compressed image handle needs to be locked
  526.                 during the call to the StdPix routine. We only unlock the data
  527.                 after we're done with the StdPix call.
  528.             */
  529.             HLock(dataHdl);
  530.             dataPtr = StripAddress(*dataHdl);
  531.  
  532.             {
  533.                 gxRectangle    geometry;
  534.                 gxShape        shape;
  535.  
  536.                 shape = GXNewRectangle(&bounds);
  537.  
  538.                 GXScaleShape(shape, hScale, vScale, bounds.left, bounds.top);
  539.                 GXGetShapeBounds(shape, 0, &geometry);
  540.  
  541.                 FixedRectToShort(&geometry, &dstRect);
  542.                 GXDisposeShape(shape);
  543.             }
  544.  
  545.             {
  546.                 PixMapHandle    tempPixMapHdl = NewPixMap();
  547.                 PixMapPtr        tempPixMapPtr;
  548.                 MatrixRecord    matrix;
  549.                 CQDProcs        stdProcs;
  550.                 StdPixProcPtr    pixProcPtr;
  551.  
  552.                 MoveHHi((Handle)tempPixMapHdl);
  553.                 HLock((Handle)tempPixMapHdl);
  554.  
  555.                 tempPixMapPtr = (PixMapPtr)StripAddress(*(Handle)tempPixMapHdl);
  556.  
  557.                 /*    Make a matrix that describes the mapping between the source
  558.                     and destination rectangles.
  559.                 */
  560.                 RectMatrix(&matrix, &srcRect, &dstRect);
  561.  
  562.                 /*    SetCompressedPixMapInfo creates a compressed 'PixMap' structure
  563.                     from an image description record and the compressed image data.
  564.                 */
  565.                 error = SetCompressedPixMapInfo(tempPixMapPtr, descHdl, dataPtr, 0, nil, nil);
  566.  
  567.                 if (error == noErr)
  568.                 {
  569.                     /*    Check for custom QuickDraw bottlenecks in the current grafPort. */
  570.  
  571.                     if ((((CGrafPtr)qd.thePort)->grafProcs) == nil)
  572.                     {
  573.                         /*    Retrieve the standard QuickDraw bottlenecks. */
  574.  
  575.                         SetStdCProcs(&stdProcs);
  576.  
  577.                         /*    The 'newProc1' field is used by QuickTime for the 'StdPix'
  578.                             bottleneck routine.
  579.                         */
  580.                         pixProcPtr = (StdPixProcPtr)stdProcs.newProc1; 
  581.                     }
  582.                     else
  583.                     {
  584.                         /*    Use the custom 'StdPix' bottleneck routine from the grafPort. */
  585.  
  586.                         pixProcPtr = (StdPixProcPtr)((CGrafPtr)qd.thePort)->grafProcs->newProc1;
  587.                     }
  588.  
  589.                     /*    Call the bottleneck routine. The flag bits for the StdPix
  590.                         routine are described in IM QuickTime p.3-139 and the function
  591.                         prototype is:
  592.                         pascal void StdPix (PixMapPtr src, const Rect *srcRect,
  593.                                             MatrixRecordPtr matrix, short mode, 
  594.                                             RgnHandle mask, PixMapPtr matte, 
  595.                                             Rect *matteRect, short flags);
  596.                     */
  597.                     CallStdPixProc(pixProcPtr,
  598.                                    tempPixMapPtr,
  599.                                    &srcRect,
  600.                                    &matrix,
  601.                                    ditherCopy,
  602.                                    nil,
  603.                                    nil,
  604.                                    nil,
  605.                                    callOldBits | callStdBits);
  606.                 }
  607.  
  608.                 HUnlock((Handle)tempPixMapHdl);
  609.                 DisposePixMap(tempPixMapHdl);
  610.             }
  611.  
  612.             HUnlock((Handle)dataHdl);
  613.         }
  614.  
  615. GetCodecInfoFailed:
  616. OpenCPictureFailed:
  617.         if (descHdl)
  618.             DisposeHandle((Handle)descHdl);
  619.     }
  620.  
  621.     if (dataHdl)
  622.         DisposeHandle(dataHdl);
  623. }
  624.  
  625. /* ---------------------------------------------------------------------------
  626.     GXCdShapeToBitmap
  627.     This routine converts a shape to a QuickDraw picture containing a 1-bit
  628.     bitmap of the shape. This is used by ShapeToScrap to create a proxie when
  629.     calling GXCdShapeToPicture. If you want to make the proxie prettier (and
  630.     larger), change the bitmap to 8-bit. However, if you're using this in
  631.     conjunction with GXCdShapeToPicture to place a gxShape on the clipboard,
  632.     1-bit should be enough, since the actual shape will be drawn, rather than
  633.     the proxie (unless forPrintingOnly is true).
  634.   --------------------------------------------------------------------------- */
  635.  
  636. PicHandle GXCdShapeToBitmap(gxShape source)
  637. {
  638.     gxRectangle        bounds;
  639.     gxShape            bitShape;
  640.     gxBitmap        bitmap;
  641.     PicHandle        picture;
  642.     Rect            shortBounds;
  643.  
  644.     GetShapeLocalBounds(source, &bounds);
  645. //    GXGetShapeLocalBounds(source, &bounds);
  646.  
  647.     FixedRectToShort(&bounds, &shortBounds);
  648.     OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top);
  649.  
  650.     bitmap.width = shortBounds.right;
  651.     bitmap.height = shortBounds.bottom;
  652.     bitmap.rowBytes = bitmap.width + 31 >> 5 << 2;
  653.     bitmap.pixelSize = 1;
  654.     bitmap.space = gxIndexedSpace;
  655.     bitmap.set = nil;
  656.     bitmap.profile = nil;
  657.     bitmap.image = NewPtrClear(bitmap.rowBytes * bitmap.height);
  658.     if (bitmap.image == nil)
  659.         return nil;
  660.  
  661.     bitShape = GXNewBitmap(&bitmap, nil);
  662.     if (bitShape != nil)
  663.     {
  664.         gxViewGroup group = GXNewViewGroup();
  665.         gxViewDevice device = GXNewViewDevice(group, bitShape);
  666.         gxViewPort port = GXNewViewPort(group);
  667.         gxTransform trans = GXCloneTransform(GXGetShapeTransform(source));
  668.  
  669.         GXSetShapeAttributes(source, GXGetShapeAttributes(source) | gxMapTransformShape);
  670.         GXMoveShape(source, -bounds.left, -bounds.top);
  671.         GXSetViewPortDither(port, 4);
  672.         GXSetShapeViewPorts(source, 1, &port);
  673.         GXDrawShape(source);
  674.         GXSetShapeTransform(source, trans);
  675.         GXDisposeTransform(trans);
  676.         
  677.         GXDisposeViewGroup(group);    /*    This disposes of the gxViewPort and gxViewDevice. */
  678.         GXDisposeShape(bitShape);
  679.     }
  680.  
  681.     {
  682.         GrafPtr    thePort;
  683.         BitMap    srcBits;
  684.     
  685.         GetPort(&thePort);
  686.         srcBits.baseAddr = bitmap.image;
  687.         srcBits.rowBytes = bitmap.rowBytes;
  688.         srcBits.bounds = shortBounds;
  689.  
  690.         picture = OpenPicture(&shortBounds);
  691.         ClipRect(&shortBounds);
  692.         CopyBits(&srcBits, &thePort->portBits, &shortBounds, &shortBounds, srcOr, nil);
  693.         ClosePicture();
  694.     }
  695.     
  696.     DisposePtr((Ptr)bitmap.image);
  697.     
  698.     return picture;
  699. }
  700.  
  701. /* ---------------------------------------------------------------------------
  702.     GXCdShapeToScrap
  703.     This routine puts a Quickdraw picture on the clipboard containing an
  704.     embedded shape and, if addProxie is true, a 1-bit bitmap of the shape.
  705.     Call this in response to the user choosing "Copy" or "Cut" from the Edit
  706.     menu. For an explanation of the parameters, see the comment on
  707.     GXCdShapeToPicture.
  708.   --------------------------------------------------------------------------- */
  709.  
  710. void GXCdShapeToScrap(gxShape source, Boolean addProxie, Boolean forPrintingOnly, Boolean eraseBackground)
  711. {
  712.     PicHandle    picture;
  713.     PicHandle    proxie = nil;
  714.  
  715.     if ( addProxie )
  716.         proxie = GXCdShapeToBitmap(source);
  717.     picture = GXCdShapeToPicture(source, proxie, ff(1), ff(1), forPrintingOnly, eraseBackground);
  718.  
  719.     if (proxie)
  720.         KillPicture(proxie);
  721.  
  722.     if (picture)
  723.     {
  724.         HLock((Handle)picture);
  725.         ZeroScrap();
  726.         PutScrap(GetHandleSize((Handle)picture), 'PICT', (Ptr)*picture);
  727.         KillPicture(picture);
  728.     }
  729. }
  730.  
  731. /* ---------------------------------------------------------------------------
  732.     GXCdDragAndDropShape
  733.     This routine will take the current mouse-down event and a shape, and handle
  734.     dragging it to the desktop or to another Drag-friendly application. It
  735.     offers to deliver the shape as either 'qdgx' or as a 'PICT' with the shape
  736.     embedded using DecompressShape. To offer other flavors, just add
  737.     additional calls to AddDragItemFlavor below, and add the corresponding
  738.     cases in the switch statement in GXCdSendDataProc.
  739.   --------------------------------------------------------------------------- */
  740.  
  741. void GXCdDragAndDropShape(EventRecord* event, gxShape shape)
  742. {    RgnHandle        hilightRgn;
  743.     gxRectangle        bounds;
  744.     Rect            r;
  745.     DragReference    theDrag;
  746.     DragSendDataUPP    myDragSendDataUPP;
  747.  
  748.     if (NewDrag(&theDrag) == noErr)
  749.     {
  750.         myDragSendDataUPP = NewDragSendDataProc(GXCdSendDataProc);
  751.         SetDragSendProc(theDrag, myDragSendDataUPP, nil);
  752.  
  753.         AddDragItemFlavor(theDrag, (unsigned long)shape, 'qdgx', nil, 0, 0);
  754.         AddDragItemFlavor(theDrag, (unsigned long)shape, 'PICT', nil, 0, 0);
  755.         
  756.         hilightRgn = NewRgn();    
  757.         GXGetShapeDeviceBounds(shape, 0, 0, &bounds);
  758.         FixedRectToShort(&bounds, &r);
  759.         RectRgn(hilightRgn, &r);
  760.         SetDragItemBounds(theDrag, 1, &r);
  761.  
  762.         /*    Change the region from a fill to a frame. */
  763.         {
  764.             RgnHandle tempRgn = NewRgn();
  765.  
  766.             CopyRgn(hilightRgn, tempRgn);
  767.             InsetRgn(tempRgn, 1, 1);
  768.             DiffRgn(hilightRgn, tempRgn, hilightRgn);
  769.             DisposeRgn(tempRgn);
  770.         }
  771.         
  772.         TrackDrag(theDrag, event, hilightRgn);
  773.         DisposeDrag(theDrag);
  774.         DisposeRgn(hilightRgn);
  775.         DisposeRoutineDescriptor(myDragSendDataUPP);
  776.     }
  777. }
  778.  
  779. /* ===========================================================================
  780.     Private functions
  781.   =========================================================================== */
  782.  
  783. /* ---------------------------------------------------------------------------
  784.     QuickDraw conversion utility functions
  785.   --------------------------------------------------------------------------- */
  786.  
  787. static gxRectangle *ShortRectToFixed(const Rect *shortRect, gxRectangle *fixedRect)
  788. {
  789.     register Fixed *coord;
  790.  
  791.     if (shortRect == nil)
  792.     {
  793.         GXPostGraphicsError(parameter_is_nil);
  794.         return nil;
  795.     }
  796.  
  797.     if (fixedRect == nil)
  798.     {
  799.         GXPostGraphicsError(parameter_is_nil);
  800.         return nil;
  801.     }
  802.  
  803.     coord = (Fixed *) fixedRect;
  804.     *coord++ = IntToFixed(shortRect->left);
  805.     *coord++ = IntToFixed(shortRect->top);
  806.     *coord++ = IntToFixed(shortRect->right);
  807.     *coord = IntToFixed(shortRect->bottom);
  808.     return fixedRect;
  809. }
  810.  
  811. static Rect *FixedRectToShort(const gxRectangle *fixedRect, Rect *shortRect)
  812. {
  813.     register short *coord;
  814.  
  815.     if (shortRect == nil)
  816.     {
  817.         GXPostGraphicsError(parameter_is_nil);
  818.         return nil;
  819.     }
  820.  
  821.     if (fixedRect == nil)
  822.     {
  823.         GXPostGraphicsError(parameter_is_nil);
  824.         return nil;
  825.     }
  826.  
  827.     coord = (short *) shortRect;
  828.     *coord++ = FixedRound(fixedRect->top);
  829.     *coord++ = FixedRound(fixedRect->left);
  830.     *coord++ = FixedRound(fixedRect->bottom);
  831.     *coord = FixedRound(fixedRect->right);
  832.     return shortRect;
  833. }
  834.  
  835. /* ---------------------------------------------------------------------------
  836.     AppendAtom
  837.   --------------------------------------------------------------------------- */
  838.  
  839. static long* AppendAtom(long stream[], Size size, OSType tag, const void *data)
  840. {
  841.     *stream++ = size + kAtomHeaderSize;
  842.     *stream++ = tag;
  843.     BlockMove(data, (Ptr)stream, size);
  844.  
  845.     return (long*)((char*)stream + size);
  846. }
  847.  
  848. /* ---------------------------------------------------------------------------
  849.     GXCdSendDataProc
  850.     The ItemReference is the gxShape to be sent. The dragSendRefCon is
  851.     ignored.
  852.   --------------------------------------------------------------------------- */
  853.  
  854. pascal OSErr GXCdSendDataProc(FlavorType theType, void *dragSendRefCon, ItemReference theItem, DragReference theDrag)
  855. {
  856.     gxShape    shape = (gxShape)theItem;
  857.     OSErr    error = noErr;
  858.  
  859.     switch (theType)
  860.     {
  861.         case 'qdgx':
  862.         {
  863.             Handle flat = GXStShapeToHandle(shape);
  864.             if (flat)
  865.             {
  866.                 HLock(flat);
  867.                 error = SetDragItemFlavorData(theDrag, theItem, 'qdgx', *flat, GetHandleSize(flat), 0);
  868.                 DisposeHandle(flat);
  869.             }
  870.             break;
  871.         }
  872.         case 'PICT':
  873.         {
  874.             PicHandle    picture;
  875.             PicHandle    proxie;
  876.  
  877.             proxie = GXCdShapeToBitmap(shape);
  878.             picture = GXCdShapeToPicture(shape, proxie, ff(1), ff(1), false, true);
  879.  
  880.             if (proxie)
  881.                 KillPicture(proxie);
  882.  
  883.             if (picture)
  884.             {
  885.                 HLock((Handle)picture);
  886.                 error = SetDragItemFlavorData(theDrag, theItem, 'PICT', (Ptr)*picture, GetHandleSize((Handle)picture), 0);
  887.                 KillPicture(picture);
  888.             }
  889.             break;
  890.         }
  891.         default:
  892.             error = badDragFlavorErr;
  893.             break;
  894.     }
  895.  
  896.     return error;
  897. }
  898.