home *** CD-ROM | disk | FTP | other *** search
- /*
- File: FocusLib.cpp
-
- Contains: Library routines for focusing (setting up for drawing into a facet)
-
- Owned by: Jens Alfke
-
- Copyright: © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
-
- */
-
-
- #ifndef _ALTPOINT_
- #include <AltPoint.h>
- #endif
-
- #ifndef _ALTPOLY_
- #include <AltPoly.h>
- #endif
-
- #ifndef _ODDEBUG_
- #include "ODDebug.h"
- #endif
-
- #ifndef SOM_ODFrame_xh
- #include <Frame.xh>
- #endif
-
- #ifndef SOM_ODFacet_xh
- #include <Facet.xh>
- #endif
-
- #ifndef _TEMPOBJ_
- #include <TempObj.h>
- #endif
-
- #ifndef _PLFMDEF_
- #include <PlfmDef.h>
- #endif
-
- #ifndef SOM_ODShape_xh
- #include <Shape.xh>
- #endif
-
- #ifndef SOM_Module_OpenDoc_Polygon_defined
- #include <Polygon.xh>
- #endif
-
- #ifndef SOM_ODTransform_xh
- #include <Trnsform.xh>
- #endif
-
- #ifndef SOM_ODCanvas_xh
- #include <Canvas.xh>
- #endif
-
- #ifndef SOM_ODWindow_xh
- #include <Window.xh>
- #endif
-
- #ifndef SOM_ODFacet_xh
- #include <Facet.xh>
- #endif
-
- #ifndef _FOCUSLIB_
- #include "FocusLib.h"
- #endif
-
- #ifndef __PRINTING__
- #include <Printing.h>
- #endif
-
- #ifndef _ODUTILS_
- #include "ODUtils.h"
- #endif
-
- #ifndef _ODMEMORY_
- #include "ODMemory.h"
- #endif
-
- #include <string.h>
- #include <stdio.h>
-
- #ifndef topLeft
- #define topLeft(r) (((Point *) &(r))[0])
- #endif
-
- #define bDevLaser 3 // copied from "PrPrivate.a"
-
- #define kPostScriptHandle 192 // Picture comment ID
-
-
- #define ALWAYS_PS_CLIP 0 // Set to 1 to always use PS clipping even for rects
- // This aids in debugging the clipping code.
-
-
- //------------------------------------------------------------------------------
- // GetCanvasGeometryMode
- //------------------------------------------------------------------------------
-
- ODGeometryMode
- GetCanvasGeometryMode( Environment *ev, ODCanvas *canvas )
- {
- ODGeometryMode mode = kODLoseGeometry;
- if( !canvas->IsDynamic(ev) ) {
- if( canvas->HasPlatformPrintJob(ev,kODQuickDrawGX) )
- mode = kODPreserveGeometry;
- else if( canvas->HasPlatformPrintJob(ev,kODQuickDraw) ) {
- THPrint job = (THPrint) canvas->GetPlatformPrintJob(ev,kODQuickDraw);
- if( ((**job).prStl.wDev >>8) == bDevLaser )
- mode = kODPreserveGeometry;
- }
- // ????? Should I also treat onscreen canvases as geometric, if GX is installed??
- }
- return mode;
- }
-
-
- //------------------------------------------------------------------------------
- // Begin / EndPostScriptClip
- //------------------------------------------------------------------------------
-
- static void
- NoOpDraw( )
- {
- // Draw something that's guaranteed not to appear anywhere.
- // Needed to sync up QD-emitted PS code with SendPS-emitted code.
- Rect bbox = (**ODQDGlobals.thePort->clipRgn).rgnBBox;
- Point pt;
- pt.h = bbox.left;
- if( pt.h==-32767 )
- pt.h = bbox.right+1;
- pt.v = bbox.top;
- if( pt.v==-32767 )
- pt.v = bbox.bottom+1;
- MoveTo(pt.h-1,pt.v-1);
- Line(0,0);
- }
-
-
- static void
- SendPS( const char str[] )
- {
- OSErr err;
- ODULong len = strlen(str) +1;
- ODHandle h = TempNewHandle(len,&err);
- if( !h )
- h = NewHandle(len); // In emergency use app heap
-
- if( h ) {
- ODBlockMove(str,*h,len-1);
- ((char*)*h)[len-1] = 13; // Append Return char
- PicComment(kPostScriptHandle, len, h);
- DisposeHandle(h);
- } else
- WARN("Couldn't allocate %ld bytes for PicComment",len);
- }
-
-
- void
- ODBeginPostScriptClip( Environment* ev, ODShape *shape )
- {
- /* Since the LaserWriter driver does not understand regions, in order to clip to
- a nonrectangular shape we must convert it to a polygon, then emit PostScript code
- to create a path in the shape of that polygon and clip to it. This involves
- some nonstandard use of the PostScript picture-comments in that we deliberately
- do _not_ use PostScriptBegin and PostScriptEnd comments. The purpose of these is
- to save and restore the state of the printer, and that's exactly what we don't
- want to do here -- we need the new clipping path to be applied to future QD
- drawing. */
-
- SendPS("%%%% ODBeginPostScriptClip");
-
- // First clip to the region (LW driver will just use the bounding box.)
- RgnHandle rgn = shape->GetQDRegion(ev);
- SetClip(rgn);
- NoOpDraw();
-
- if( !shape->IsRectangular(ev) || ALWAYS_PS_CLIP ) {
- // Now emit the polygon as a PostScript path and clip to it:
- ODTempPolygon poly;
- shape->CopyPolygon(ev, &poly);
-
- SendPS("gsave newpath"); // Save graphics state first
-
- float xoff = ODQDGlobals.thePort->portRect.left; // Must emit page coords
- float yoff = ODQDGlobals.thePort->portRect.top;
-
- char buf[128];
- ODContour *cont = poly.FirstContour();
- for( long n=poly.GetNContours(); n>0; n-- ) {
- const ODPoint *v = cont->vertex;
- long m = cont->nVertices;
- if( m>2 ) {
- const char *op = "moveto";
- while( m-- >0 ) {
- sprintf(buf,"%.2f %.2f %s", v->x/65536.0-xoff, v->y/65536.0-yoff, op);
- SendPS(buf);
- op = "lineto";
- v++;
- }
- }
- SendPS("closepath");
- cont = cont->NextContour();
- }
-
- SendPS("clip gsave"); // Driver expects copy of state pushed on stack
-
- } else {
- // Regular rectangular clipping. Just need to emit two gsaves
- // to balance the two grestores that ODEndPostScriptClip will emit:
- SendPS("gsave gsave");
- }
- }
-
-
- void
- ODEndPostScriptClip( )
- {
- NoOpDraw();
- SendPS("currentpoint grestore grestore moveto"); // Preserve current point
- SendPS("%%%% ODEndPostScriptClip");
- }
-
-
- //------------------------------------------------------------------------------
- // FocusState::BeginFocus
- //------------------------------------------------------------------------------
-
- ODBoolean
- FocusState::BeginFocus( Environment* ev, ODFacet *facet, ODBoolean toContent,
- ODBoolean toWindow, ODShape *clipTo )
- {
- GrafPtr port;
- ODPoint offset;
- Point origin;
-
- fPort = kODNULL;
- fOrigin.h = fOrigin.v = 0;
- fClip = kODNULL;
- fPrintingPostScript = kODFalse;
-
- ODBoolean printing = kODFalse;
- if( ! facet->GetCanvas(ev)->IsDynamic(ev) ) {
- if( facet->GetCanvas(ev)->HasPlatformPrintJob(ev, kODQuickDraw) ) {
- printing = kODTrue;
- THPrint printRecord = (THPrint)facet->GetCanvas(ev)->GetPlatformPrintJob(ev,kODQuickDraw);
- short device = (**printRecord).prStl.wDev;
- fPrintingPostScript = ((device >> 8) == bDevLaser);
- } else if( facet->GetCanvas(ev)->HasPlatformPrintJob(ev, kODQuickDrawGX) ) {
- printing = kODTrue;
- fPrintingPostScript = kODFalse;
- /* When GX is installed, QD clipping to regions works in printouts even when
- printing to a PostScript printer. This means our workaround is not
- necessary and we can leave the fPrintingPostScript flag false. */
- }
- }
-
- ODCanvas *canvas = facet->GetCanvas(ev);
-
- TempODShape newClip = kODNULL;
- TempODTransform contentTransform = kODNULL;
-
- if( toWindow && !printing ) {
- port = (GrafPtr) facet->GetWindow(ev)->GetPlatformWindow(ev);
- newClip = facet->AcquireWindowAggregateClipShape(ev, canvas);
- if ( toContent ) {
- contentTransform = facet->AcquireWindowContentTransform(ev, canvas);
- } else {
- contentTransform = facet->AcquireWindowFrameTransform(ev, canvas);
- }
- } else {
- port = facet->GetCanvas(ev)->GetQDPort(ev);
- newClip = facet->AcquireAggregateClipShape(ev, canvas);
- if ( toContent ) {
- contentTransform = facet->AcquireContentTransform(ev, canvas);
- } else {
- contentTransform = facet->AcquireFrameTransform(ev, canvas);
- }
- }
-
- ODBoolean xformNotOffset = ! contentTransform->IsQDOffset(ev);
-
- {
- TempODTransform internal = kODNULL;
- if( toContent ) {
- internal = facet->GetFrame(ev)->AcquireInternalTransform(ev,canvas);
- if( internal->GetType(ev) == kODIdentityXform )
- internal.Release(); // Don't need to worry about it, it's identity
- }
-
- if( internal || clipTo || xformNotOffset ) {
- ODShape *temp = newClip->Copy(ev); // We will be modifying newClip
- newClip.Release();
- newClip = temp;
- }
-
- if( internal ) {
- // When focusing to content, need to apply inverse of
- // frame's internal transform to clipshape:
- newClip->InverseTransform(ev,internal);
- }
- }
-
- if( clipTo )
- newClip->Intersect(ev,clipTo);
-
- contentTransform->GetOffset(ev, &offset);
- origin = offset.AsQDPoint();
- origin.h = -origin.h;
- origin.v = -origin.v;
-
- if( xformNotOffset ) {
- // Transform newClip by the contentTransform if it involves scale/rotate/etc.
- // But first factor out the final offset since SetOrigin will take care of that later.
- ODTransform *temp = contentTransform->Copy(ev); // We will be modifying the xform
- contentTransform.Release();
- contentTransform = temp;
- ODPoint move = origin;
- contentTransform->MoveBy(ev, &move);
- newClip->Transform(ev,contentTransform);
- }
-
- fFocusPort = port;
- fPort = ODQDGlobals.thePort;
- if( port != fPort )
- SetPort(port);
-
- fOrigin = topLeft(ODQDGlobals.thePort->portRect);
- if( origin.h != ODQDGlobals.thePort->portRect.left || origin.v != ODQDGlobals.thePort->portRect.top )
- SetOrigin(origin.h,origin.v);
-
- if( fPrintingPostScript ) {
- ODBeginPostScriptClip(ev, newClip);
- fClip = kODNULL;
- } else {
- fClip = ODQDGlobals.thePort->clipRgn;
- ODQDGlobals.thePort->clipRgn = newClip->CopyQDRegion(ev);
- }
-
- return fPrintingPostScript;
- }
-
-
- //------------------------------------------------------------------------------
- // FocusState::EndFocus
- //------------------------------------------------------------------------------
-
- void
- FocusState::EndFocus( )
- {
- if( fPort ) {
- if( fFocusPort != ODQDGlobals.thePort )
- SetPort(fFocusPort); // In case current port changed since focus
- if( fPrintingPostScript ) {
- ODEndPostScriptClip();
- } else {
- if( fClip ) {
- DisposeRgn(ODQDGlobals.thePort->clipRgn);
- ODQDGlobals.thePort->clipRgn = fClip;
- } else {
- Rect r;
- SetRect(&r,-32767,-32767,32767,32767);
- ClipRect(&r);
- }
- }
- if( fOrigin.h!=ODQDGlobals.thePort->portRect.left || fOrigin.v!=ODQDGlobals.thePort->portRect.top )
- SetOrigin(fOrigin.h, fOrigin.v);
- if( ODQDGlobals.thePort!=fPort )
- SetPort(fPort);
- fPort = kODNULL; // So nothing happens if this is called again
- }
- }
-
-
- //------------------------------------------------------------------------------
- // CFocus
- //------------------------------------------------------------------------------
-
-
- CFocus::CFocus( Environment *ev, ODFacet *facet )
- {
- (void) f.BeginFocus(ev,facet,kODTrue,kODFalse,kODNULL);
- }
-
-
- CFocus::CFocus( Environment *ev, ODFacet *facet, ODShape *clipTo )
- {
- (void) f.BeginFocus(ev,facet,kODTrue,kODFalse,clipTo);
- }
-
-
- CFocus::~CFocus( )
- {
- f.EndFocus();
- }
-
-
- //------------------------------------------------------------------------------
- // CFocusFrame
- //------------------------------------------------------------------------------
-
-
- CFocusFrame::CFocusFrame( Environment *ev, ODFacet *facet )
- {
- (void) f.BeginFocus(ev,facet,kODFalse,kODFalse,kODNULL);
- }
-
-
- CFocusFrame::CFocusFrame( Environment *ev, ODFacet *facet, ODShape *clipTo )
- {
- (void) f.BeginFocus(ev,facet,kODFalse,kODFalse,clipTo);
- }
-
-
- CFocusFrame::~CFocusFrame( )
- {
- f.EndFocus();
- }
-
-
- //------------------------------------------------------------------------------
- // CFocusWindow
- //------------------------------------------------------------------------------
-
-
- CFocusWindow::CFocusWindow( Environment *ev, ODFacet *facet )
- {
- (void) f.BeginFocus(ev,facet,kODTrue,kODTrue,kODNULL);
- }
-
-
- CFocusWindow::CFocusWindow( Environment *ev, ODFacet *facet, ODShape *clipTo )
- {
- (void) f.BeginFocus(ev,facet,kODTrue,kODTrue,clipTo);
- }
-
-
- CFocusWindow::~CFocusWindow( )
- {
- f.EndFocus();
- }
-
-
- //------------------------------------------------------------------------------
- // CFocusWindowFrame
- //------------------------------------------------------------------------------
-
-
- CFocusWindowFrame::CFocusWindowFrame( Environment *ev, ODFacet *facet )
- {
- (void) f.BeginFocus(ev,facet,kODFalse,kODTrue,kODNULL);
- }
-
-
- CFocusWindowFrame::CFocusWindowFrame( Environment *ev, ODFacet *facet, ODShape *clipTo )
- {
- (void) f.BeginFocus(ev,facet,kODFalse,kODTrue,clipTo);
- }
-
-
- CFocusWindowFrame::~CFocusWindowFrame( )
- {
- f.EndFocus();
- }
-
-
- //------------------------------------------------------------------------------
- // BeginFocus and EndFocus
- //------------------------------------------------------------------------------
-
-
- void
- BeginFocus( Environment* ev, FocusState* foc, ODFacet* facet,
- ODBoolean toContent, ODBoolean toWindow, ODShape* clipTo )
- {
- foc->BeginFocus(ev,facet,toContent,toWindow,clipTo);
- }
-
-
- void
- EndFocus( FocusState* foc )
- {
- foc->EndFocus();
- }
-