home *** CD-ROM | disk | FTP | other *** search
- /*
- File: TestPostScriptable.c
-
- Contains: QuickDraw GX to PostScript conversion code.
- File contains routines to test style attributes of shapes
- to see if they are "PostScriptable" that is to say they
- can be rendered by our Proc-Set without simplification by
- gx graphics first.
-
- Version: Technology: Quickdraw GX 1.1.x
-
- Copyright: © 1992-1997 by Apple Computer, Inc., all rights reserved.
- */
-
- #include "GXToPSBuildConfig.h"
- #include <GXGraphics.h>
- #include <GXLayout.h>
- #include "GXGraphicsPriv.h"
- #include <GXEnvironment.h>
- #include "GXToPostScript.h"
- #include "IOUtilities.h"
- #include "RDUtil.h"
- #include "FontHandler.h"
- #include "PublicPostScriptIE.h"
- #include "private.h"
- #include "PSIEResources.h"
- #include "GXErrors.h"
- #include "ShapeUtilities.h"
-
- #ifdef resumeLabel
- #undef resumeLabel
- #endif
- #define resumeLabel(exception)
-
-
- /*******************************
- TestDashPostScriptable:
-
- checks to see if a shape's dash can be rendered by our
- dashing PostScript dashing procedures.
-
- We can't dash if:
- break-dash but dash has more than one contour.
- if advance does not cause consecutive dashes to overlap when fill is even-odd.
- if auto-advance but one contour in parent shape.
- BendDash and ClipDash
-
- *********************************/
- Boolean TestDashPostScriptable(gxShape theShape, gxDashRecord *theDash, gxStyleAttribute theAttributes)
- {
- #pragma unused (theAttributes)
-
- long dashContours;
- long shapeContours;
-
- if (theDash->dash == nil)
- return(true);
-
- dashContours = GXCountShapeContours(theDash->dash);
- shapeContours = GXCountShapeContours(theShape);
-
- if ( (theDash->attributes & gxAutoAdvanceDash) && (shapeContours > 1))
- return(false);
-
-
- if ( (theDash->attributes & gxBreakDash) && (dashContours > 1))
- return(false);
-
-
- if ( theDash->attributes & (gxBendDash | gxClipDash) )
- return(false);
-
-
- if ( GXGetShapeFill(theDash->dash) == gxEvenOddFill ) {
-
- gxRectangle dashBounds;
-
- GXGetShapeBounds(theDash->dash, 0, &dashBounds);
-
- if ( (dashBounds.right - dashBounds.left) > theDash->advance)
- return(false);
-
- }//end if
-
- return(true);
-
- }//TestDashPostScriptable
-
- //<FF>
- /*****************************************************************
-
- TestNonCenterShapeCanBeInset:
-
- Tests to see if a non-center frame shape can be drawn correctly
- simply by insetting the geometry
-
- Shape can be drawn correctly if:
- it is a rectangle
- or
- it is Convex (but we don't have a test for that yet)
- or
- it has a dash, because dashing explicitly works by drawing
- the dash on the inset path for non-center framed shapes.
-
- ******************************************************************/
- Boolean TestNonCenterShapeCanBeInset(gxShape theShape, gxStyle theStyle)
- {
-
- if (GXGetShapeType(theShape) == gxRectangleType)
- return(true);
-
- if (DoesStyleHaveDash(theStyle))
- return(true);
-
- /* If we had a test for convexness, we'd put it here */
-
- return(false);
-
- }//end
-
-
- //<FF>
- /*****************************************************************
-
- MiteredShape:
-
- Routine detects if the miter is applied at any join in the shape.
-
- ******************************************************************/
-
- /* positive for a right turn, negative for a left turn */
- static Fixed JoinDeflect(gxPoint *first, gxPoint *next, gxPoint *last)
- {
- Fixed length, minCross = fract1 >> 14;
- register Fixed dx1 = next->x - first->x, dy1 = next->y - first->y;
- register Fixed dx2 = last->x - next->x, dy2 = last->y - next->y;
- Fract cross, dot;
- if (length = Magnitude(dx1, dy1))
- { dx1 = FractDivide(dx1, length);
- dy1 = FractDivide(dy1, length);
- }
- if (length = Magnitude(dx2, dy2))
- { dx2 = FractDivide(dx2, length);
- dy2 = FractDivide(dy2, length);
- }
- cross = FractMultiply(dx1, dy2) - FractMultiply(dy1, dx2);
- dot = FractMultiply(dx1, dx2) + FractMultiply(dy1, dy2);
- if (dot >= fract1) return cross >> 1;
- if (dot <= -fract1) return cross < 0 ? gxNegativeInfinity : gxPositiveInfinity;
- return FixedDivide(cross, fract1 + dot);
- }
-
-
- Boolean MiteredShape(gxShape source, gxJoinRecord *join, Fixed pen);
- Boolean MiteredShape(gxShape source, gxJoinRecord *join, Fixed pen)
- {
- long attributes = GXGetShapeStyleAttributes(source);
- Boolean pathFlag = GXGetShapeType(source) == gxPathType;
- Boolean closedFlag = GXGetShapeFill(source) != gxOpenFrameFill;
- Boolean mitered = false;
- Fixed miter = join->miter;
- long *srcPtr, *sourcePtr;
- long contour, contours;
-
- if (pen == 0) return false;
-
- GXLockShape(source);
- srcPtr = sourcePtr = (long*)GXGetShapeStructure(source, nil);
- contours = *srcPtr++;
- for (contour = 1; contour <= contours; ++ contour)
- { long count, points = *srcPtr++;
- long controlCount, controlBits, *controlPtr;
- Boolean clockwise = attributes & gxAutoInsetStyle ? GXGetShapeDirection(source, contour) : true;
- gxPoint *first, *next, *last;
-
- if (points < 2 || points == 2 && !closedFlag)
- { if (pathFlag) srcPtr += points + 31 >> 5;
- srcPtr += points << 1;
- continue;
- }
- else if (mitered = points == 2)
- goto done;
-
- /* initialize the control bits */
- if (pathFlag)
- { controlPtr = srcPtr;
- srcPtr += points + 31 >> 5;
- controlBits = *controlPtr++;
- controlCount = 32;
- if (!closedFlag)
- { controlBits <<= 1;
- controlCount -= 1;
- }
- }
-
- /* initialize the points */
- count = points;
- first = (gxPoint *)srcPtr + points - 1;
- next = (gxPoint *)srcPtr;
- last = (gxPoint *)srcPtr + 1;
- srcPtr += points << 1;
- if (!closedFlag)
- { count -= 2;
- first = next;
- next = last;
- last += 1;
- }
-
- while (count--)
- { if (!pathFlag || controlBits >= 0) /* if next is on the curve */
- { Fixed deflect = JoinDeflect(first, next, last);
-
- if ((attributes & (gxInsideFrameStyle | gxOutsideFrameStyle)) == 0) /* center framed */
- { deflect >>= 1;
- if (mitered = deflect > miter || deflect < -miter) goto done;
- }
- else if ((attributes & gxInsideFrameStyle) != 0 ^ pen > 0 ^ clockwise) /* right framed */
- { if (mitered = deflect < -miter) goto done;
- }
- else /* left framed */
- { if (mitered = deflect > miter) goto done;
- }
- }
-
- /* advance control bits */
- if (pathFlag)
- { if (--controlCount == 0)
- { controlBits = *controlPtr++;
- controlCount = 32;
- }
- else
- controlBits <<= 1;
- }
-
- /* advance points */
- first = next;
- next = last;
- last += 1;
-
- if (closedFlag && count == 1)
- last -= points;
- }
- }
- done:
- GXUnlockShape(source);
- return mitered;
- }
-
-
- /***************************************
- TestShapeLaserWriterPolygon:
-
- The translator sometimes puts tags on polygons
- that indicate to use the 7.0 style of stroking
- rather than normal stroking.
-
- *****************************************/
- Boolean TestShapeLaserWriterPolygon(gxShape theShape);
- Boolean TestShapeLaserWriterPolygon(gxShape theShape)
- {
-
- if (GXGetShapeTags(theShape, polw, 1, gxSelectToEnd, nil) > 0)
- return(true);
- else
- return(false);
-
- }//TestShapeLaserWriterPolygon
-
- //<FF>
- /****************************
-
- Function: TestMiterMatters
-
- Returns true if the miter limit
- on a shape matters, thus requiring
- us to call PrimitiveShape because
- there is no way to map gx graphics miters
- into PostScript ones.
-
- If the shape is a secret translator polygon meant to be
- stroked in the 7.0 LaserWriter way, we don't care about miters.
-
- *****************************/
- Boolean TestMiterMatters(gxShape theShape, gxJoinRecord *theJoin, Fixed pen)
- {
- gxShapeType theType = GXGetShapeType(theShape);
- register Boolean mitered;
-
- if (TestShapeLaserWriterPolygon(theShape))
- /* If the shape is to be stroked the way 7.0 LW driver likes to do it then ignore miters */
- mitered = false;
-
- else if ( (theType == gxPathType) || (theType == gxPolygonType) )
- mitered = MiteredShape(theShape, theJoin, pen);
-
- else if (theType == gxRectangleType)
- if (theJoin->miter > fixed1/2)
- mitered = false;
- else
- mitered = true;
-
- else
- mitered = false;
-
- #if DEBUGLEVEL > DEBUGFEEDBACK
- if (mitered)
- dprintf(trace, "Shape needs mitering: %X", theShape);
- #endif
-
- return(mitered);
-
- }//TestMiterMatters
-
-
-
-
- //<FF>
- /******************************
-
- TestLayerPostscriptable:
-
- will return false if:
- 1. negative bold values.
- 2. framed with joins or caps.
- 3. framed with any boldness.
- 4. whitelayer with pattern or dash.
- 5. Level-1 printer with any dash (Can't do pathforall on level-1 text)
-
- *******************************/
- Boolean TestLayerPostscriptable(TIEGlobalsHdl hIEGlobals, gxFaceLayer *theLayer);
- Boolean TestLayerPostscriptable(TIEGlobalsHdl hIEGlobals, gxFaceLayer *theLayer)
- {
- gxStyle outlineStyle = theLayer->outlineStyle;
-
- if (theLayer->boldOutset.x == 1)
- theLayer->boldOutset.x = 0;
-
- if (theLayer->boldOutset.y == 1)
- theLayer->boldOutset.y = 0;
-
-
-
- /* Perspective in layer?? */
-
- if (theLayer->outlineTransform != nil) {
-
- gxMapping outlineMapping;
- GXGetTransformMapping(theLayer->outlineTransform, &outlineMapping);
- if (TestMappingPerspective(&outlineMapping) ) {
-
- #if DEBUGLEVEL > 1
- dprintf(trace, "face layer has perspective transform");
- #endif
- return(false);
-
- }//end if
-
- }//end if
-
-
- /* negative bold values ?? */
-
- if ( (theLayer->boldOutset.x < 0) || (theLayer->boldOutset.y < 0) ) {
-
- #if DEBUGLEVEL > 1
- dprintf(trace, "face layer has negative boldness");
- #endif
- return(false);
-
- }//end if
-
-
- /* framed Layer stuff */
- if ((theLayer->outlineFill == gxFrameFill) || (theLayer->outlineFill == gxClosedFrameFill)) {
-
- /** Level-1, dashed layers generate PostScript errors **/
-
- if ( (outlineStyle != nil) && ( (*hIEGlobals)->params.languageLevel == 1 ) && DoesStyleHaveDash(outlineStyle) ) {
-
- #if DEBUGLEVEL > 1
- dprintf(trace, "face layer has dash and printer is level-1");
- #endif
- return(false);
-
- }//end if
-
-
- /** Framed layer with joins or caps?? **/
-
- if (outlineStyle != nil) {
-
- gxJoinRecord theJoin;
- gxCapRecord theCap;
-
- GXGetStyleJoin(outlineStyle, &theJoin);
- if (theJoin.join != nil) {
-
- GXDisposeShape(theJoin.join);
- #if DEBUGLEVEL > 1
- dprintf(trace, "face layer has join");
- #endif
- return(false);
-
- }//end if
-
- GXGetStyleCap(outlineStyle, &theCap);
- if ((theCap.startCap != nil) || (theCap.endCap != nil)) {
- if (theCap.startCap != nil)
- GXDisposeShape(theCap.startCap);
- if (theCap.endCap != nil)
- GXDisposeShape(theCap.endCap);
-
- #if DEBUGLEVEL > 1
- dprintf(trace, "face layer has cap");
- #endif
- return(false);
-
- }//end if
-
- }//end if
-
-
- /** Framed layer with any boldness **/
-
- if ((theLayer->boldOutset.x != 0) || (theLayer->boldOutset.y != 0)) {
-
- #if DEBUGLEVEL > 1
- dprintf(trace, "face layer has frame fill and boldness");
- #endif
- return(false);
-
- }//end if
-
-
- /** White layer with dash **/
-
- if ((outlineStyle != nil) && (theLayer->flags & gxWhiteLayer) && DoesStyleHaveDash(outlineStyle) ) {
-
- #if DEBUGLEVEL > 1
- dprintf(trace, "face layer is white and has dash");
- #endif
-
- return(false);
-
- }//end if
-
-
- }//end if
-
-
- /* whitelayer with pattern ?? */
-
- if ((theLayer->flags & gxWhiteLayer) && (outlineStyle != nil)) {
-
- if ( DoesStyleHavePattern(outlineStyle) ) {
-
- #if DEBUGLEVEL > 1
- dprintf(trace, "face layer is white and has pattern");
- #endif
-
- return(false);
-
- }//end if
-
- }//end if
-
-
- /* A white layer with any kind of boldness */
-
- if (theLayer->flags & gxWhiteLayer) {
-
- if ((theLayer->boldOutset.x != 0) || (theLayer->boldOutset.y != 0)) {
-
- #if DEBUGLEVEL > 1
- dprintf(trace, "face layer is white with bold");
- #endif
-
- return(false);
-
- }//end if
-
- }//end if
-
-
- /** Passed all of the tests **/
-
- return(true);
-
- }//TestLayerPostscriptable
-
-
- //<FF>
- /******************************
- Routine AnalyzeTextFace:
-
- routine checks the text faces of a
- shape to see if there are any underline
- layers.
-
- Routine also checks for generally non postscriptable
- text faces.
-
-
- This is another one of those routines
- where I have to allocate and dispose of
- all sorts of stuff just to see if a gx graphics
- entity (style in this case) has some
- characteristic.
-
- ********************************/
- OSErr AnalyzeTextFace(TIEGlobalsHdl hIEGlobals, gxShape theShape, Boolean *hasUnderline, Boolean *notPostscriptable)
- {
- OSErr status = noErr;
- Handle hWorkSpace; // the workspace.
- gxTextFace *theFace; // Pointer to a text face.
- gxFaceLayer *theLayer; // Pointer to a layer.
- long nLayers; // Number of layers in the style.
- gxStyle *theStyles; // array of styles for the shape.
- gxStyle aStyle; // a particular style from the shape.
- long nStyles; // How many styles in the shape.
- gxShapeType theType;
- long i, j;
-
- theType = GXGetShapeType(theShape);
-
- check( (theType == gxTextType) || (theType == gxGlyphType) || (theType == gxLayoutType));
-
- aStyle = GXGetShapeStyle(theShape); // get the shape's main style, we may need it.
-
- if (theType == gxTextType) {
-
- nStyles = 1;
- theStyles = &aStyle;
-
- } else {
-
- if (theType == gxGlyphType) {
-
- GXGetGlyphs(theShape, nil, nil, nil, nil, nil, &nStyles, nil, nil);
-
- } else {
-
- GXGetLayout(theShape, nil, &nStyles, nil, nil, nil, nil, nil, nil, nil);
-
- }//end if
-
- status = PSSetWorkSpaceSize(hIEGlobals, nStyles * sizeof(gxStyle));
- nrequire(status, failed_WrkSpace);
-
- hWorkSpace = (*hIEGlobals)->hWorkSpace;
- HLock(hWorkSpace);
- theStyles = (gxStyle*)*hWorkSpace;
-
- if (theType == gxGlyphType)
- GXGetGlyphs(theShape, nil, nil, nil, nil, nil, nil, nil, theStyles);
- else
- GXGetLayout(theShape, nil, nil, nil, theStyles, nil, nil, nil, nil, nil);
-
- }//end if
-
- /** We now have all of the styles for the shape, loop through them to see if there are underlines **/
-
- *hasUnderline = false;
- *notPostscriptable = false;
-
- for (i = 0; i < nStyles; i++) {
-
- if (*theStyles == nil)
- *theStyles = aStyle;
-
- nLayers = GXGetStyleFace(*theStyles, nil);
- if (nLayers > 0) {
-
- status = PSSetWorkSpaceSize(hIEGlobals, sizeof(gxTextFace) + nLayers * sizeof(gxFaceLayer));
- nrequire(status, failed_FaceSpace);
-
- theFace = (gxTextFace*)(*(*hIEGlobals)->hWorkSpace); // Hope gx graphics calls don't move memory.
- GXGetStyleFace(*theStyles, theFace);
-
- theLayer = theFace->faceLayer;
-
- for (j = 0; j < nLayers; ++j) {
-
- if (theLayer->flags & kUnderlineCheckMask) {
-
- *hasUnderline = true;
-
- }//end if
-
-
- /** Check for any non postscriptable layers **/
-
- if (!TestLayerPostscriptable(hIEGlobals, theLayer)) {
-
- *notPostscriptable = true;
-
- }//end if
-
- /** GetFace created styles and transforms **/
-
- if (theLayer->outlineTransform != nil)
- GXDisposeTransform(theLayer->outlineTransform);
-
- if (theLayer->outlineStyle != nil)
- GXDisposeStyle(theLayer->outlineStyle);
-
- ++theLayer;
-
- }//end for
-
- status = PSReleaseWorkSpace(hIEGlobals); // release workspace for this style's face.
- nrequire(status, failed_FaceSpace);
-
- }//end if
-
- ++theStyles;
-
- }//end for
-
- failed_FaceSpace:
-
- if (theType != gxTextType) { // We didn't allocate a style workspace for text shape.
-
- register OSErr saveStatus = PSReleaseWorkSpace(hIEGlobals); // release styles workspace.
- if (status == noErr)
- status = saveStatus;
-
- }//end if
-
- failed_WrkSpace:
-
- ncheck(GXGetGraphicsError(nil));
-
- return(status);
-
- }//AnalyzeTextFace
-
-
-
-
-