Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2667 lines
86 KiB

  1. /****************************************************************************
  2. Module Quickdrw: Implementation
  3. *****************************************************************************
  4. This is the interpreter engine for the picture convertor. It uses a
  5. modified CGrafPort structure to hold the intermediate results of a
  6. translation that can later be accessed from the Gdi module. As such,
  7. it provides an input cache for all attributes, with calls made
  8. directly to the Gdi module for primitives.
  9. It is called by the API module and will call the Get module in order
  10. to read individual data or record elements from the data stream.
  11. Module prefix: QD
  12. ****************************************************************************/
  13. #include "headers.c"
  14. #pragma hdrstop
  15. /* C libraries */
  16. #include "string.h"
  17. #include <ctype.h>
  18. /* quickdrw's own interface */
  19. #include "qdopcode.i"
  20. #include "qdcoment.i"
  21. /* imported modules */
  22. #include <math.h>
  23. #include "filesys.h"
  24. #include "getdata.h"
  25. /*********************** Exported Data Initialization ***********************/
  26. /******************************* Private Data *******************************/
  27. /*--- QuickDraw grafPort simulation --- */
  28. #define Version1ID 0x1101
  29. #define Version2ID 0x02FF
  30. /*--- QuickDraw opcode fields --- */
  31. /* -1 is casted to Word to prevent warning in WIN32 compilation */
  32. #define Reserved (Word) -1
  33. #define Variable -1
  34. #define CommentSize -2
  35. #define RgnOrPolyLen -3
  36. #define WordDataLen -4
  37. #define DWordDataLen -5
  38. #define HiByteLen -6
  39. typedef struct
  40. {
  41. Word function;
  42. Integer length;
  43. } opcodeEntry, far * opcodeEntryLPtr;
  44. /* The following opcode table was taken from "Inside Macintosh, Volume V" on
  45. pages V-97 to V-102 and supplemented by System 7 opcodes from "Inside
  46. Macintosh, Volume VI", page 17-20. */
  47. #define LookupTableSize 0xA2
  48. private opcodeEntry opcodeLookup[LookupTableSize] =
  49. {
  50. /* 0x00 */ { NOP, 0 },
  51. /* 0x01 */ { Clip, RgnOrPolyLen },
  52. /* 0x02 */ { BkPat, 8 },
  53. /* 0x03 */ { TxFont, 2 },
  54. /* 0x04 */ { TxFace, 1 },
  55. /* 0x05 */ { TxMode, 2 },
  56. /* 0x06 */ { SpExtra, 4 },
  57. /* 0x07 */ { PnSize, 4 },
  58. /* 0x08 */ { PnMode, 2 },
  59. /* 0x09 */ { PnPat, 8 },
  60. /* 0x0A */ { FillPat, 8 },
  61. /* 0x0B */ { OvSize, 4 },
  62. /* 0x0C */ { Origin, 4 },
  63. /* 0x0D */ { TxSize, 2 },
  64. /* 0x0E */ { FgColor, 4 },
  65. /* 0x0F */ { BkColor, 4 },
  66. /* 0x10 */ { TxRatio, 8 },
  67. /* 0x11 */ { Version, 1 },
  68. /* 0x12 */ { BkPixPat, Variable },
  69. /* 0x13 */ { PnPixPat, Variable },
  70. /* 0x14 */ { FillPixPat, Variable },
  71. /* 0x15 */ { PnLocHFrac, 2 },
  72. /* 0x16 */ { ChExtra, 2 },
  73. /* 0x17 */ { Reserved, 0 },
  74. /* 0x18 */ { Reserved, 0 },
  75. /* 0x19 */ { Reserved, 0 },
  76. /* 0x1A */ { RGBFgCol, 6 },
  77. /* 0x1B */ { RGBBkCol, 6 },
  78. /* 0x1C */ { HiliteMode, 0 },
  79. /* 0x1D */ { HiliteColor, 6 },
  80. /* 0x1E */ { DefHilite, 0 },
  81. /* 0x1F */ { OpColor, 6 },
  82. /* 0x20 */ { Line, 8 },
  83. /* 0x21 */ { LineFrom, 4 },
  84. /* 0x22 */ { ShortLine, 6 },
  85. /* 0x23 */ { ShortLineFrom, 2 },
  86. /* 0x24 */ { Reserved, WordDataLen },
  87. /* 0x25 */ { Reserved, WordDataLen },
  88. /* 0x26 */ { Reserved, WordDataLen },
  89. /* 0x27 */ { Reserved, WordDataLen },
  90. /* 0x28 */ { LongText, Variable },
  91. /* 0x29 */ { DHText, Variable },
  92. /* 0x2A */ { DVText, Variable },
  93. /* 0x2B */ { DHDVText, Variable },
  94. /* 0x2C */ { FontName, WordDataLen },
  95. /* 0x2D */ { LineJustify, WordDataLen },
  96. /* 0x2E */ { Reserved, WordDataLen },
  97. /* 0x2F */ { Reserved, WordDataLen },
  98. /* 0x30 */ { frameRect, 8 },
  99. /* 0x31 */ { paintRect, 8 },
  100. /* 0x32 */ { eraseRect, 8 },
  101. /* 0x33 */ { invertRect, 8 },
  102. /* 0x34 */ { fillRect, 8 },
  103. /* 0x35 */ { Reserved, 8 },
  104. /* 0x36 */ { Reserved, 8 },
  105. /* 0x37 */ { Reserved, 8 },
  106. /* 0x38 */ { frameSameRect, 0 },
  107. /* 0x39 */ { paintSameRect, 0 },
  108. /* 0x3A */ { eraseSameRect, 0 },
  109. /* 0x3B */ { invertSameRect, 0 },
  110. /* 0x3C */ { fillSameRect, 0 },
  111. /* 0x3D */ { Reserved, 0 },
  112. /* 0x3E */ { Reserved, 0 },
  113. /* 0x3F */ { Reserved, 0 },
  114. /* 0x40 */ { frameRRect, 8 },
  115. /* 0x41 */ { paintRRect, 8 },
  116. /* 0x42 */ { eraseRRect, 8 },
  117. /* 0x43 */ { invertRRect, 8 },
  118. /* 0x44 */ { fillRRect, 8 },
  119. /* 0x45 */ { Reserved, 8 },
  120. /* 0x46 */ { Reserved, 8 },
  121. /* 0x47 */ { Reserved, 8 },
  122. /* 0x48 */ { frameSameRRect, 0 },
  123. /* 0x49 */ { paintSameRRect, 0 },
  124. /* 0x4A */ { eraseSameRRect, 0 },
  125. /* 0x4B */ { invertSameRRect, 0 },
  126. /* 0x4C */ { fillSameRRect, 0 },
  127. /* 0x4D */ { Reserved, 0 },
  128. /* 0x4E */ { Reserved, 0 },
  129. /* 0x4F */ { Reserved, 0 },
  130. /* 0x50 */ { frameOval, 8 },
  131. /* 0x51 */ { paintOval, 8 },
  132. /* 0x52 */ { eraseOval, 8 },
  133. /* 0x53 */ { invertOval, 8 },
  134. /* 0x54 */ { fillOval, 8 },
  135. /* 0x55 */ { Reserved, 8 },
  136. /* 0x56 */ { Reserved, 8 },
  137. /* 0x57 */ { Reserved, 8 },
  138. /* 0x58 */ { frameSameOval, 0 },
  139. /* 0x59 */ { paintSameOval, 0 },
  140. /* 0x5A */ { eraseSameOval, 0 },
  141. /* 0x5B */ { invertSameOval, 0 },
  142. /* 0x5C */ { fillSameOval, 0 },
  143. /* 0x5D */ { Reserved, 0 },
  144. /* 0x5E */ { Reserved, 0 },
  145. /* 0x5F */ { Reserved, 0 },
  146. /* 0x60 */ { frameArc, 12 },
  147. /* 0x61 */ { paintArc, 12 },
  148. /* 0x62 */ { eraseArc, 12 },
  149. /* 0x63 */ { invertArc, 12 },
  150. /* 0x64 */ { fillArc, 12 },
  151. /* 0x65 */ { Reserved, 12 },
  152. /* 0x66 */ { Reserved, 12 },
  153. /* 0x67 */ { Reserved, 12 },
  154. /* 0x68 */ { frameSameArc, 4 },
  155. /* 0x69 */ { paintSameArc, 4 },
  156. /* 0x6A */ { eraseSameArc, 4 },
  157. /* 0x6B */ { invertSameArc, 4 },
  158. /* 0x6C */ { fillSameArc, 4 },
  159. /* 0x6D */ { Reserved, 4 },
  160. /* 0x6E */ { Reserved, 4 },
  161. /* 0x6F */ { Reserved, 4 },
  162. /* 0x70 */ { framePoly, RgnOrPolyLen },
  163. /* 0x71 */ { paintPoly, RgnOrPolyLen },
  164. /* 0x72 */ { erasePoly, RgnOrPolyLen },
  165. /* 0x73 */ { invertPoly, RgnOrPolyLen },
  166. /* 0x74 */ { fillPoly, RgnOrPolyLen },
  167. /* 0x75 */ { Reserved, RgnOrPolyLen },
  168. /* 0x76 */ { Reserved, RgnOrPolyLen },
  169. /* 0x77 */ { Reserved, RgnOrPolyLen },
  170. /* 0x78 */ { frameSamePoly, 0 },
  171. /* 0x79 */ { paintSamePoly, 0 },
  172. /* 0x7A */ { eraseSamePoly, 0 },
  173. /* 0x7B */ { invertSamePoly, 0 },
  174. /* 0x7C */ { fillSamePoly, 0 },
  175. /* 0x7D */ { Reserved, 0 },
  176. /* 0x7E */ { Reserved, 0 },
  177. /* 0x7F */ { Reserved, 0 },
  178. /* 0x80 */ { frameRgn, RgnOrPolyLen },
  179. /* 0x81 */ { paintRgn, RgnOrPolyLen },
  180. /* 0x82 */ { eraseRgn, RgnOrPolyLen },
  181. /* 0x83 */ { invertRgn, RgnOrPolyLen },
  182. /* 0x84 */ { fillRgn, RgnOrPolyLen },
  183. /* 0x85 */ { Reserved, RgnOrPolyLen },
  184. /* 0x86 */ { Reserved, RgnOrPolyLen },
  185. /* 0x87 */ { Reserved, RgnOrPolyLen },
  186. /* 0x88 */ { frameSameRgn, 0 },
  187. /* 0x89 */ { paintSameRgn, 0 },
  188. /* 0x8A */ { eraseSameRgn, 0 },
  189. /* 0x8B */ { invertSameRgn, 0 },
  190. /* 0x8C */ { fillSameRgn, 0 },
  191. /* 0x8D */ { Reserved, 0 },
  192. /* 0x8E */ { Reserved, 0 },
  193. /* 0x8F */ { Reserved, 0 },
  194. /* 0x90 */ { BitsRect, Variable },
  195. /* 0x91 */ { BitsRgn, Variable },
  196. /* 0x92 */ { Reserved, WordDataLen },
  197. /* 0x93 */ { Reserved, WordDataLen },
  198. /* 0x94 */ { Reserved, WordDataLen },
  199. /* 0x95 */ { Reserved, WordDataLen },
  200. /* 0x96 */ { Reserved, WordDataLen },
  201. /* 0x97 */ { Reserved, WordDataLen },
  202. /* 0x98 */ { PackBitsRect, Variable },
  203. /* 0x99 */ { PackBitsRgn, Variable },
  204. /* 0x9A */ { DirectBitsRect, WordDataLen },
  205. /* 0x9B */ { DirectBitsRgn, WordDataLen },
  206. /* 0x9C */ { Reserved, WordDataLen },
  207. /* 0x9D */ { Reserved, WordDataLen },
  208. /* 0x9E */ { Reserved, WordDataLen },
  209. /* 0x9F */ { Reserved, WordDataLen },
  210. /* 0xA0 */ { ShortComment, 2 },
  211. /* 0xA1 */ { LongComment, CommentSize }
  212. };
  213. #define RangeTableSize 7
  214. private opcodeEntry opcodeRange[RangeTableSize] =
  215. {
  216. /* 0x00A2 - 0x00AF */ { 0x00AF, WordDataLen },
  217. /* 0x00B0 - 0x00CF */ { 0x00CF, 0 },
  218. /* 0x00D0 - 0x00FE */ { 0x00FE, DWordDataLen },
  219. /* 0x00FF - 0x00FF */ { opEndPic, 0 },
  220. /* 0x0100 - 0x07FF */ { 0x8000, HiByteLen },
  221. /* 0x8000 - 0x80FF */ { 0x80FF, 0 },
  222. /* 0x8100 - 0xFFFF */ { 0xFFFF, DWordDataLen }
  223. };
  224. /*--- EPS Filter PostScript Strings ---*/
  225. #define MAC_PS_TRAILER "pse\rpsb\r"
  226. #define MAC_PS_PREAMBLE "pse\rcurrentpoint\r/picTop exch def\r/picLeft exch def\rpsb\r"
  227. #define SUPERPAINT_TEXTSTARTJUNK "P2_b ["
  228. #define SUPERPAINT_TEXTSTOPJUNK "] sb end\r"
  229. /*--- GrafPort allocation ---*/
  230. #define PARSEPOLY 1
  231. #define SKIPALTPOLY 2
  232. #define USEALTPOLY 3
  233. #define MASKPOLYBITS 0x07
  234. #define FRAMEPOLY 0x01
  235. #define FILLPOLY 0x02
  236. #define CLOSEPOLY 0x04
  237. #define FILLREQUIRED 0x08
  238. #define CHECK4SPLINE 0x10
  239. #define POLYLIST ((sizeof( Integer ) + sizeof( Rect )) / sizeof( Integer ))
  240. #define BBOX 1
  241. private CGrafPort grafPort;
  242. private Integer resolution;
  243. private Boolean skipFontID;
  244. private Integer maxPoints;
  245. private Integer numPoints;
  246. private Integer far * numPointsLPtr;
  247. private Rect polyBBox;
  248. private Point far * polyListLPtr;
  249. private Handle polyHandle;
  250. private Byte polyMode;
  251. private Byte polyParams;
  252. private RGBColor polyFgColor;
  253. private RGBColor polyBkColor;
  254. private Boolean zeroDeltaExpected;
  255. private Boolean textMode;
  256. private Boolean newTextCenter;
  257. private Point textCenter;
  258. private Boolean textClipCheck;
  259. private Real degCos;
  260. private Real degSin;
  261. private Boolean shadedObjectStarted;
  262. private Boolean superPaintFile;
  263. private Boolean badSuperPaintText;
  264. /*--- last Primitive sent ---*/
  265. private Rect saveRect;
  266. private Rect saveRRect;
  267. private Rect saveOval;
  268. private Point saveOvalSize;
  269. private Rect saveArc;
  270. private Integer saveStartAngle;
  271. private Integer saveArcAngle;
  272. /*--- Global allocated contstants ---*/
  273. private Pattern SolidPattern = { 0xFF, 0xFF, 0xFF, 0xFF,
  274. 0xFF, 0xFF, 0xFF, 0xFF };
  275. /*********************** Private Routine Declarations ***********************/
  276. private void ReadHeaderInfo( void );
  277. /* read the fixed size PICT header from the file. This provides information
  278. about the file size (however, it may be invalid and is ignored) and the
  279. picture bounding box, followed by the PICT version information. */
  280. private void ReadPictVersion( void );
  281. /* Read the PICT version number from the data file. If this isn't a
  282. version 1 or 2 file, the routine returns IE_UNSUPP_VERSION error. */
  283. private void ReadOpcode( opcodeEntry far * nextOpcode );
  284. /* Reads the next opcode from the stream, depending on the PICT version */
  285. private void TranslateOpcode( opcodeEntry far * currOpcodeLPtr );
  286. /* read in the remaining data from the stream, based upon the opcode function
  287. and then call the appropriate routine in Gdi module */
  288. private void SkipData( opcodeEntry far * currOpcodeLPtr );
  289. /* skip the data - the opcode won't be translated and Gdi module won't be
  290. called to create anything in the metafile */
  291. private void OpenPort( void );
  292. /* initialize the grafPort */
  293. private void ClosePort( void );
  294. /* close grafPort and de-allocate any memory blocks */
  295. private void NewPolygon( void );
  296. /* initialize the state of the polygon buffer - flush any previous data */
  297. private void AddPolySegment( Point start, Point end );
  298. /* Add the line segment to the polygon buffer */
  299. private void DrawPolyBuffer( void );
  300. /* Draw the polygon definition if the points were read without errors */
  301. private void AdjustTextRotation( Point far * newPt );
  302. /* This will calculate the correct text position if text is rotated */
  303. private Integer EPSComment(Word comment);
  304. /* parse EPS Comment */
  305. private Integer EPSData(Integer state);
  306. /* process EPS Data */
  307. private Boolean EPSBbox(PSBuf far *, Rect far *);
  308. /* parse EPS bounding box description */
  309. private char far* parse_number(char far* ptr, Integer far *iptr);
  310. /* parse numeric string (local to EPSBbox) */
  311. #define IsCharDigit(c) (IsCharAlphaNumeric(c) && !IsCharAlpha(c))
  312. /**************************** Function Implementation ***********************/
  313. void QDConvertPicture( Handle dialogHandle )
  314. /*====================*/
  315. /* create a Windows metafile using the previously set parameters, returning
  316. the converted picture information in the pictResult structure. */
  317. {
  318. opcodeEntry currOpcode;
  319. /* Open the file - if an error occured, return to main */
  320. IOOpenPicture( dialogHandle );
  321. /* Tell Gdi module to open the metafile */
  322. GdiOpenMetafile();
  323. /* initialize the grafPort */
  324. OpenPort();
  325. /* read and validate size, bounding box, and PICT version */
  326. ReadHeaderInfo();
  327. do
  328. {
  329. /* read the next opcode from the data stream */
  330. ReadOpcode( &currOpcode );
  331. /* read the ensuing data and call Gdi module entry points */
  332. TranslateOpcode( &currOpcode );
  333. /* align next memory read to Word boundary in the case of PICT 2 */
  334. if (grafPort.portVersion == 2)
  335. {
  336. IOAlignToWordOffset();
  337. }
  338. /* update the status dialog with current progress */
  339. IOUpdateStatus();
  340. /* break out of loop if end picture opcode is encountered */
  341. } while (currOpcode.function != opEndPic);
  342. /* close grafPort and de-allocate any used memory blocks */
  343. ClosePort();
  344. /* Tell Gdi module that picture is ending - perform wrapup */
  345. GdiCloseMetafile();
  346. /* Close the file */
  347. IOClosePicture();
  348. } /* ReFileToPicture */
  349. void QDGetPort( CGrafPort far * far * port )
  350. /*============*/
  351. /* return handle to grafPort structure */
  352. {
  353. *port = &grafPort;
  354. }
  355. void QDCopyBytes( Byte far * src, Byte far * dest, Integer numBytes )
  356. /*==============*/
  357. /* copy a data from source to destination */
  358. {
  359. /* loop through entire data length */
  360. while (numBytes--)
  361. {
  362. *dest++ = *src++;
  363. }
  364. } /* CopyBytes */
  365. /******************************* Private Routines ***************************/
  366. private void ReadHeaderInfo( void )
  367. /*-------------------------*/
  368. /* read the fixed size PICT header from the file. This provides information
  369. about the file size (however, it may be invalid and is ignored) and the
  370. picture bounding box, followed by the PICT version information. */
  371. {
  372. Word unusedSize;
  373. /* read file size - this value is ignored since it may be totally bogus */
  374. GetWord( &unusedSize );
  375. /* the next rectangle contains the picture bounding box */
  376. GetRect( &grafPort.portRect );
  377. /* Read the next record that indicates a PICT1 or PICT2 version picture */
  378. ReadPictVersion();
  379. /* Call Gdi module and provide bounding box coordinates. Note that these
  380. may have been altered from rectangle specified above if a spatial
  381. resolution other than 72 dpi is used in the picture. */
  382. GdiSetBoundingBox( grafPort.portRect, resolution );
  383. } /* ReadHeaderInfo */
  384. private void ReadPictVersion( void )
  385. /*--------------------------*/
  386. /* Read the PICT version number from the data file. If this isn't a
  387. version 1 or 2 file, the routine returns IE_UNSUPP_VERSION error. */
  388. {
  389. opcodeEntry versionOpcode;
  390. Word versionCheck = 0;
  391. Word opcodeCheck = 0;
  392. /* The following loop was added in order to read PixelPaint files
  393. successfully. Although technically an invalid PICT image, these files
  394. contain a series of NOP opcodes, followed by the version opcode. In
  395. this case, we continue reading until the version opcode (non-zero
  396. value) is encountered, after which the checking continues. */
  397. do
  398. {
  399. /* read the first two bytes from the data stream - for PICT 1 this is
  400. both the opcode and version; for PICT 2 this is the opcode only. */
  401. GetWord( &versionCheck );
  402. } while ((versionCheck == NOP) && (ErGetGlobalError() == ErNoError));
  403. /* determine if a valid version opcode was encountered */
  404. if (versionCheck == Version1ID )
  405. {
  406. /* version 1 == 0x1101 */
  407. grafPort.portVersion = 1;
  408. }
  409. /* check for version 2 opcode which is a Word in length */
  410. else if (versionCheck == Version)
  411. {
  412. /* Since we have only read the opcode, read the next word which should
  413. contain the identifier for PICT 2 data. */
  414. GetWord( &versionCheck );
  415. if (versionCheck == Version2ID)
  416. {
  417. grafPort.portVersion = 2;
  418. /* make sure that the next record is a header opcode. */
  419. GetWord( &opcodeCheck );
  420. if (opcodeCheck == HeaderOp)
  421. {
  422. /* set up a record structure for call to TranslateOpcode(). */
  423. versionOpcode.function = HeaderOp;
  424. versionOpcode.length = 24;
  425. TranslateOpcode( &versionOpcode );
  426. }
  427. else
  428. {
  429. /* Header wasn't followed by correct Header opcode - error. */
  430. ErSetGlobalError( ErBadHeaderSequence );
  431. }
  432. }
  433. else
  434. {
  435. /* if version 2 identifier is invalid, return error state. */
  436. ErSetGlobalError( ErInvalidVersionID );
  437. }
  438. }
  439. else
  440. {
  441. /* if check for version 1 and 2 fails, return error state. */
  442. ErSetGlobalError( ErInvalidVersion );
  443. }
  444. } /* ReadPictVersion */
  445. private void ReadOpcode( opcodeEntry far * nextOpcode )
  446. /*---------------------*/
  447. /* Reads the next opcode from the stream, depending on the PICT version */
  448. {
  449. opcodeEntryLPtr checkEntry;
  450. /* Initialize the function, since we may be reading a version 1 opcode
  451. that is only 1 byte in length. */
  452. nextOpcode->function = 0;
  453. /* Depending on the PICT version, we will read either a single byte
  454. or word for the opcode. */
  455. if (grafPort.portVersion == 1)
  456. {
  457. GetByte( (Byte far *)&nextOpcode->function );
  458. }
  459. else
  460. {
  461. GetWord( &nextOpcode->function );
  462. }
  463. /* check the current error code and force an exit from read loop if
  464. something went wrong. */
  465. if (ErGetGlobalError() != NOERR)
  466. {
  467. nextOpcode->function = opEndPic;
  468. nextOpcode->length = 0;
  469. return;
  470. }
  471. /* Check the opcode function number to determine if we can perform
  472. a direct lookup, or if the opcode is part of the range table. */
  473. if (nextOpcode->function < LookupTableSize )
  474. {
  475. nextOpcode->length = opcodeLookup[nextOpcode->function].length;
  476. }
  477. else
  478. {
  479. /* Walk through the range table to determine the data length of the
  480. ensuing information past the opcode. */
  481. for (checkEntry = opcodeRange;
  482. checkEntry->function < nextOpcode->function;
  483. checkEntry++) ;
  484. nextOpcode->length = checkEntry->length;
  485. }
  486. } /* ReadOpcode */
  487. private void TranslateOpcode( opcodeEntry far * currOpcodeLPtr )
  488. /*--------------------------*/
  489. /* read in the remaining data from the stream, based upon the opcode function
  490. and then call the appropriate routine in Gdi module */
  491. {
  492. Word function = currOpcodeLPtr->function;
  493. /* perform appropriate action based on function code */
  494. switch (function)
  495. {
  496. case NOP:
  497. /* no data follows */
  498. break;
  499. case Clip:
  500. {
  501. Boolean doClip = FALSE;
  502. /* read in clip region into grafPort */
  503. GetRegion( &grafPort.clipRgn );
  504. /* if in textmode, we need avoid clip regions, since they are used
  505. to draw Postscript encoded text *or* bitmap representations.
  506. We allow a clipping region to pass through only if it is being
  507. set to the bounds of the picture image (fix for MacDraw, Canvas,
  508. and SuperPaint images containing rotated text.) */
  509. if (textMode && textClipCheck)
  510. {
  511. Word far * sizeLPtr;
  512. /* the most common case is a sequence of : null clip, text,
  513. non-null clip, bitmap. If first clip == portRect, then
  514. we actually want to set the clip - doClip is set to TRUE. */
  515. sizeLPtr = (Word far *)GlobalLock( grafPort.clipRgn );
  516. doClip = *sizeLPtr == RgnHeaderSize &&
  517. EqualRect( (Rect far *)(sizeLPtr + 1), &grafPort.portRect );
  518. GlobalUnlock( grafPort.clipRgn );
  519. /* perform this check only once after initial picTextBegin */
  520. textClipCheck = FALSE;
  521. }
  522. /* issue the clip only if not in text mode, or a sanctioned clip */
  523. if (!textMode || doClip)
  524. {
  525. /* Call Gdi to set the new clip region */
  526. GdiSelectClipRegion( grafPort.clipRgn );
  527. }
  528. break;
  529. }
  530. case BkPat:
  531. /* flag the pixel map type a Foreground/Background pixel pattern */
  532. /* and read pattern into old data position */
  533. grafPort.bkPixPat.patType = QDOldPat;
  534. GetPattern( &grafPort.bkPixPat.pat1Data );
  535. /* Notify Gdi that background color may have changed */
  536. GdiMarkAsChanged( GdiBkPat );
  537. break;
  538. case TxFont:
  539. /* read text font index */
  540. GetWord( (Word far *)&grafPort.txFont );
  541. /* check if the font name was provided in previous opcode */
  542. if (!skipFontID)
  543. {
  544. /* Make sure that the font name is a null string */
  545. grafPort.txFontName[0] = cNULL;
  546. }
  547. /* Notify Gdi that text font index may have changed */
  548. GdiMarkAsChanged( GdiTxFont );
  549. break;
  550. case TxFace:
  551. /* read font attributes */
  552. GetByte( (Byte far *)&grafPort.txFace );
  553. /* Notify Gdi that text style elements may have changed */
  554. GdiMarkAsChanged( GdiTxFace );
  555. break;
  556. case TxMode:
  557. /* read text transfer mode */
  558. GetWord( (Word far *)&grafPort.txMode );
  559. /* Notify Gdi that text transfer mode may have changed */
  560. GdiMarkAsChanged( GdiTxMode );
  561. break;
  562. case SpExtra:
  563. /* read text space extra */
  564. GetFixed( (Fixed far *)&grafPort.spExtra );
  565. /* Notify Gdi that space extra may have changed */
  566. GdiMarkAsChanged( GdiSpExtra );
  567. break;
  568. case PnSize:
  569. /* read x and y components of pen size */
  570. GetPoint( (Point far *)&grafPort.pnSize );
  571. /* Notify Gdi that pen size may have changed */
  572. GdiMarkAsChanged( GdiPnSize );
  573. break;
  574. case PnMode:
  575. /* read pen transfer mode */
  576. GetWord( (Word far *)&grafPort.pnMode );
  577. /* Notify Gdi that transferm mode may have changed */
  578. GdiMarkAsChanged( GdiPnMode );
  579. break;
  580. case PnPat:
  581. /* flag the pixel map type a Foreground/Background pixel pattern */
  582. /* and read pattern into old data position */
  583. grafPort.pnPixPat.patType = QDOldPat;
  584. GetPattern( &grafPort.pnPixPat.pat1Data );
  585. /* Notify Gdi that pen pattern may have changed */
  586. GdiMarkAsChanged( GdiPnPat );
  587. break;
  588. case FillPat:
  589. /* flag the pixel map type a Foreground/Background pixel pattern */
  590. /* and read pattern into old data position */
  591. grafPort.fillPixPat.patType = QDOldPat;
  592. GetPattern( &grafPort.fillPixPat.pat1Data );
  593. /* Notify Gdi that fill pattern may have changed */
  594. GdiMarkAsChanged( GdiFillPat );
  595. break;
  596. case OvSize:
  597. /* save point in new grafPort field */
  598. GetPoint( &saveOvalSize );
  599. break;
  600. case Origin:
  601. {
  602. Point offset;
  603. /* read the new origin in to the upper-left coordinate space */
  604. GetWord( (Word far *)&offset.x );
  605. GetWord( (Word far *)&offset.y );
  606. /* call gdi module to reset the origin */
  607. GdiOffsetOrigin( offset );
  608. break;
  609. }
  610. case TxSize:
  611. GetWord( (Word far *)&grafPort.txSize );
  612. /* Notify Gdi that text size may have changed */
  613. GdiMarkAsChanged( GdiTxSize );
  614. break;
  615. case FgColor:
  616. GetOctochromeColor( &grafPort.rgbFgColor );
  617. /* Notify Gdi that foreground color may have changed */
  618. GdiMarkAsChanged( GdiFgColor );
  619. break;
  620. case BkColor:
  621. GetOctochromeColor( &grafPort.rgbBkColor );
  622. /* Notify Gdi that background color may have changed */
  623. GdiMarkAsChanged( GdiBkColor );
  624. break;
  625. case TxRatio:
  626. /* save the numerator and denominator in the grafPort */
  627. GetPoint( &grafPort.txNumerator );
  628. GetPoint( &grafPort.txDenominator );
  629. /* Notify Gdi that text ratio may have changed */
  630. GdiMarkAsChanged( GdiTxRatio );
  631. break;
  632. case Version:
  633. /* just skip over the version information */
  634. IOSkipBytes( currOpcodeLPtr->length );
  635. break;
  636. case BkPixPat:
  637. GetPixPattern( &grafPort.bkPixPat );
  638. /* Notify Gdi that background pattern may have changed */
  639. GdiMarkAsChanged( GdiBkPat );
  640. break;
  641. case PnPixPat:
  642. GetPixPattern( &grafPort.pnPixPat );
  643. /* Notify Gdi that pen pattern may have changed */
  644. GdiMarkAsChanged( GdiPnPat );
  645. break;
  646. case FillPixPat:
  647. GetPixPattern( &grafPort.fillPixPat );
  648. /* Notify Gdi that fill pattern may have changed */
  649. GdiMarkAsChanged( GdiFillPat );
  650. break;
  651. case PnLocHFrac:
  652. GetWord( (Word far *)&grafPort.pnLocHFrac );
  653. break;
  654. case ChExtra:
  655. GetWord( (Word far *)&grafPort.chExtra );
  656. /* Notify Gdi that text character extra may have changed */
  657. GdiMarkAsChanged( GdiChExtra );
  658. break;
  659. case RGBFgCol:
  660. GetRGBColor( &grafPort.rgbFgColor );
  661. /* Notify Gdi that foregroudn color may have changed */
  662. GdiMarkAsChanged( GdiFgColor );
  663. break;
  664. case RGBBkCol:
  665. GetRGBColor( &grafPort.rgbBkColor );
  666. /* Notify Gdi that background color may have changed */
  667. GdiMarkAsChanged( GdiBkColor );
  668. break;
  669. case HiliteMode:
  670. /* don't do anything for hilite mode */
  671. break;
  672. case HiliteColor:
  673. {
  674. RGBColor rgbUnused;
  675. GetRGBColor( &rgbUnused );
  676. break;
  677. }
  678. case DefHilite:
  679. /* don't do anything for hilite */
  680. break;
  681. case OpColor:
  682. {
  683. RGBColor rgbUnused;
  684. GetRGBColor( &rgbUnused );
  685. break;
  686. }
  687. case Line:
  688. case LineFrom:
  689. case ShortLine:
  690. case ShortLineFrom:
  691. {
  692. Point newPt;
  693. SignedByte deltaX;
  694. SignedByte deltaY;
  695. /* see if we need to read the updated pen location first */
  696. if (function == ShortLine || function == Line)
  697. {
  698. /* read in the new pen location */
  699. GetCoordinate( &grafPort.pnLoc );
  700. }
  701. /* determine what the next data record contains */
  702. if (function == Line || function == LineFrom)
  703. {
  704. /* get the new coordinate to draw to */
  705. GetCoordinate( &newPt );
  706. }
  707. else /* if (function == ShortLine || function == ShortLineFrom) */
  708. {
  709. /* the the new x and y deltas */
  710. GetByte( &deltaX );
  711. GetByte( &deltaY );
  712. /* calculate the endpoint for call to gdi */
  713. newPt.x = grafPort.pnLoc.x + (Integer)deltaX;
  714. newPt.y = grafPort.pnLoc.y + (Integer)deltaY;
  715. }
  716. /* check if buffering line segments (polygon mode != FALSE) */
  717. if (polyMode)
  718. {
  719. /* add the line segment to the polygon buffer */
  720. AddPolySegment( grafPort.pnLoc, newPt );
  721. }
  722. else
  723. {
  724. /* Call Gdi to draw line */
  725. GdiLineTo( newPt );
  726. }
  727. /* update the new pen location in the grafPort */
  728. grafPort.pnLoc = newPt;
  729. break;
  730. }
  731. case LongText:
  732. {
  733. Str255 txString;
  734. Point location;
  735. /* read the new pen (baseline) location */
  736. GetCoordinate( &grafPort.txLoc );
  737. GetString( (StringLPtr)txString );
  738. /* adjust for any text rotation that may be set */
  739. location = grafPort.txLoc;
  740. AdjustTextRotation( &location );
  741. /* call Gdi to print the text at current pen location */
  742. GdiTextOut( txString, location );
  743. break;
  744. }
  745. case DHText:
  746. case DVText:
  747. case DHDVText:
  748. {
  749. Byte deltaX = 0;
  750. Byte deltaY = 0;
  751. Str255 txString;
  752. Point location;
  753. /* if command is DHText or DHDVText, read horizontal offset */
  754. if (function != DVText)
  755. {
  756. GetByte( &deltaX );
  757. }
  758. /* if command is DVText or DHDVText, then read the vertical offset */
  759. if (function != DHText)
  760. {
  761. GetByte( &deltaY );
  762. }
  763. /* update the current pen postion */
  764. grafPort.txLoc.x += deltaX;
  765. grafPort.txLoc.y += deltaY;
  766. /* now read in the string */
  767. GetString( (StringLPtr)txString );
  768. /* adjust for any text rotation that may be set */
  769. location = grafPort.txLoc;
  770. AdjustTextRotation( &location );
  771. /* call Gdi to print the text at current pen location */
  772. GdiTextOut( txString, location );
  773. break;
  774. }
  775. case FontName:
  776. {
  777. Word dataLen;
  778. GetWord( (Word far *)&dataLen );
  779. GetWord( (Word far *)&grafPort.txFont );
  780. GetString( grafPort.txFontName );
  781. /* Notify Gdi that font name may have changed */
  782. GdiMarkAsChanged( GdiTxFont );
  783. break;
  784. }
  785. case LineJustify:
  786. {
  787. Word dataLen;
  788. Fixed interCharSpacing;
  789. Fixed textExtra;
  790. GetWord( (Word far *)&dataLen );
  791. GetFixed( &interCharSpacing ); // !!! where to put this ?
  792. GetFixed( &textExtra );
  793. /* Notify Gdi that line justification may have changed */
  794. GdiMarkAsChanged( GdiLineJustify );
  795. break;
  796. }
  797. case frameRect:
  798. case paintRect:
  799. case eraseRect:
  800. case invertRect:
  801. case fillRect:
  802. {
  803. /* read in the rectangle */
  804. GetRect( &saveRect );
  805. /* call the correct GDI routine */
  806. GdiRectangle( function - frameRect, saveRect );
  807. break;
  808. }
  809. case frameSameRect:
  810. case paintSameRect:
  811. case eraseSameRect:
  812. case invertSameRect:
  813. case fillSameRect:
  814. {
  815. /* notify gdi that this is the same primitive */
  816. GdiSamePrimitive( TRUE );
  817. /* call the correct gdi routine using last rectangle coords */
  818. GdiRectangle( function - frameSameRect, saveRect );
  819. /* notify gdi that this is no longer the same primitive */
  820. GdiSamePrimitive( FALSE );
  821. break;
  822. }
  823. case frameRRect:
  824. case paintRRect:
  825. case eraseRRect:
  826. case invertRRect:
  827. case fillRRect:
  828. {
  829. /* save the rectangle */
  830. GetRect( &saveRRect );
  831. /* call the correct gdi routine using last rectangle coords */
  832. GdiRoundRect( function - frameRRect, saveRRect, saveOvalSize );
  833. break;
  834. }
  835. case frameSameRRect:
  836. case paintSameRRect:
  837. case eraseSameRRect:
  838. case invertSameRRect:
  839. case fillSameRRect:
  840. {
  841. /* notify gdi that this is the same primitive */
  842. GdiSamePrimitive( TRUE );
  843. /* call the correct gdi routine using last rectangle coords */
  844. GdiRoundRect( function - frameSameRRect, saveRRect, saveOvalSize );
  845. /* notify gdi that this is no longer the same primitive */
  846. GdiSamePrimitive( FALSE );
  847. break;
  848. }
  849. case frameOval:
  850. case paintOval:
  851. case eraseOval:
  852. case invertOval:
  853. case fillOval:
  854. {
  855. /* save off bounding rectangle */
  856. GetRect( &saveOval );
  857. /* call the correct gdi routine using last oval coords */
  858. GdiOval( function - frameOval, saveOval );
  859. break;
  860. }
  861. case frameSameOval:
  862. case paintSameOval:
  863. case eraseSameOval:
  864. case invertSameOval:
  865. case fillSameOval:
  866. {
  867. /* notify gdi that this is the same primitive */
  868. GdiSamePrimitive( TRUE );
  869. /* call the correct gdi routine using last oval coords */
  870. GdiOval( function - frameSameOval, saveOval );
  871. /* notify gdi that this is no longer the same primitive */
  872. GdiSamePrimitive( FALSE );
  873. break;
  874. }
  875. case frameArc:
  876. case paintArc:
  877. case eraseArc:
  878. case invertArc:
  879. case fillArc:
  880. {
  881. /* read rect into the save variables, new start and arc angles */
  882. GetRect( &saveArc );
  883. GetWord( (Word far *)&saveStartAngle );
  884. GetWord( (Word far *)&saveArcAngle );
  885. #ifdef WIN32
  886. /* have to extend the sign because GetWord doesn't */
  887. saveStartAngle = (short)saveStartAngle;
  888. saveArcAngle = (short)saveArcAngle;
  889. #endif
  890. /* call the correct gdi routine using last arc angles */
  891. GdiArc( function - frameArc, saveArc, saveStartAngle, saveArcAngle );
  892. break;
  893. }
  894. case frameSameArc:
  895. case paintSameArc:
  896. case eraseSameArc:
  897. case invertSameArc:
  898. case fillSameArc:
  899. {
  900. Integer startAngle;
  901. Integer arcAngle;
  902. /* read new start and arc angles */
  903. GetWord( (Word far *)&startAngle );
  904. GetWord( (Word far *)&arcAngle );
  905. #ifdef WIN32
  906. /* have to extend the sign because GetWord doesn't */
  907. startAngle = (short)startAngle;
  908. arcAngle = (short)arcAngle;
  909. #endif
  910. /* notify gdi that this is the may be the same primitive */
  911. GdiSamePrimitive( (startAngle == saveStartAngle) &&
  912. (arcAngle == saveArcAngle) );
  913. /* save off the start and arc angles */
  914. saveStartAngle = startAngle;
  915. saveArcAngle = arcAngle;
  916. /* call the correct gdi routine using last rect and arc angles */
  917. GdiArc( function - frameSameArc, saveArc, startAngle, arcAngle );
  918. /* notify gdi that this is no longer the same primitive */
  919. GdiSamePrimitive( FALSE );
  920. break;
  921. }
  922. case framePoly:
  923. case paintPoly:
  924. case erasePoly:
  925. case invertPoly:
  926. case fillPoly:
  927. {
  928. /* save the polygon in the grafPort */
  929. GdiSamePrimitive( GetPolygon( &grafPort.polySave, (function == framePoly) ) );
  930. /* call gdi routine to draw polygon */
  931. if (grafPort.polySave)
  932. {
  933. GdiPolygon( function - framePoly, grafPort.polySave );
  934. /* turn off filling while in polygon mode */
  935. polyParams &= ~FILLREQUIRED;
  936. /* notify gdi that this is no longer the same primitive */
  937. GdiSamePrimitive( FALSE );
  938. }
  939. break;
  940. }
  941. case frameSamePoly:
  942. case paintSamePoly:
  943. case eraseSamePoly:
  944. case invertSamePoly:
  945. case fillSamePoly:
  946. {
  947. /* notify gdi that this is the same primitive */
  948. GdiSamePrimitive( TRUE );
  949. /* call gdi routine to draw polygon */
  950. GdiPolygon( function - frameSamePoly, grafPort.polySave );
  951. /* notify gdi that this is no longer the same primitive */
  952. GdiSamePrimitive( FALSE );
  953. break;
  954. }
  955. case frameRgn:
  956. case paintRgn:
  957. case eraseRgn:
  958. case invertRgn:
  959. case fillRgn:
  960. {
  961. /* save the region in the grafPort */
  962. GetRegion( &grafPort.rgnSave );
  963. /* check for memory failure; GetRegion will set ErGetGlobalError */
  964. if (!grafPort.rgnSave)
  965. break;
  966. /* if in polygon mode and a fillRgn is encountered, this indicates
  967. that the polygon should be filled once parsing is completed */
  968. if (polyMode == PARSEPOLY)
  969. {
  970. /* make sure that a PaintPoly() hasn't been handled already */
  971. if (!(polyParams & (FILLPOLY | FILLREQUIRED)))
  972. {
  973. /* set flags to fill polygon once polygon buffer is filled */
  974. polyParams |= FILLPOLY | FILLREQUIRED;
  975. }
  976. }
  977. else if (polyMode == FALSE ||
  978. ((polyMode == USEALTPOLY) && !(polyParams & FRAMEPOLY)))
  979. {
  980. /* call gdi routine to draw polygon */
  981. GdiRegion( function - frameRgn, grafPort.rgnSave );
  982. /* make sure that the polygon isn't filled when the simulation
  983. buffer is drawn at the end of the polygon definition */
  984. polyParams &= ~FILLREQUIRED;
  985. }
  986. /* save off the current fore- and background colors for
  987. polygon simulation routine to ensure correct fill colors */
  988. if (polyMode && (grafPort.fillPixPat.patType == QDOldPat))
  989. {
  990. polyFgColor = grafPort.rgbFgColor;
  991. polyBkColor = grafPort.rgbBkColor;
  992. }
  993. break;
  994. }
  995. case frameSameRgn:
  996. case paintSameRgn:
  997. case eraseSameRgn:
  998. case invertSameRgn:
  999. case fillSameRgn:
  1000. {
  1001. /* notify gdi that this is the same primitive */
  1002. GdiSamePrimitive( TRUE );
  1003. /* call gdi routine to draw polygon */
  1004. GdiRegion( function - frameSameRgn, grafPort.rgnSave );
  1005. /* notify gdi that this is no longer the same primitive */
  1006. GdiSamePrimitive( FALSE );
  1007. break;
  1008. }
  1009. case BitsRect:
  1010. case BitsRgn:
  1011. case PackBitsRect:
  1012. case PackBitsRgn:
  1013. case DirectBitsRect:
  1014. case DirectBitsRgn:
  1015. {
  1016. Boolean has24bits;
  1017. Boolean hasRegion;
  1018. Rect srcRect;
  1019. Rect dstRect;
  1020. Word mode;
  1021. PixMap pixMap;
  1022. Handle pixData;
  1023. DWord unusedBaseAddr;
  1024. RgnHandle rgn;
  1025. /* determine which type of bitmap we are reading */
  1026. has24bits = (function == DirectBitsRect ||
  1027. function == DirectBitsRgn);
  1028. hasRegion = (function == DirectBitsRgn ||
  1029. function == BitsRgn ||
  1030. function == PackBitsRgn);
  1031. /* currently there is no region created */
  1032. rgn = NULL;
  1033. /* if 24-bit, read in the base address which should == 0x000000FF */
  1034. if (has24bits)
  1035. {
  1036. GetDWord( &unusedBaseAddr );
  1037. }
  1038. /* read in the header structure */
  1039. GetPixMap( &pixMap, FALSE );
  1040. /* if this isn't an 24-bit RGB bitmap, read in the color table.
  1041. Also check the rowBytes field to signify bitmap w/2 colors */
  1042. if (!has24bits && (pixMap.rowBytes & PixelMapBit))
  1043. {
  1044. GetColorTable( &pixMap.pmTable );
  1045. }
  1046. /* call io module to update status indicator */
  1047. IOUpdateStatus();
  1048. /* read source and destination rects from stream */
  1049. GetRect( &srcRect );
  1050. GetRect( &dstRect );
  1051. GetWord( &mode );
  1052. /* if there is a region included, read this also */
  1053. if (hasRegion)
  1054. {
  1055. /* read in the region */
  1056. GetRegion( &rgn );
  1057. }
  1058. /* read the pixel bit data */
  1059. GetPixData( &pixMap, &pixData );
  1060. if (ErGetGlobalError() == NOERR && !textMode)
  1061. {
  1062. /* Call Gdi to render the bitmap and de-allocate the memory */
  1063. GdiStretchDIBits( &pixMap, pixData, srcRect, dstRect, mode, rgn );
  1064. }
  1065. else
  1066. {
  1067. /* deallocate any memory that may be allocated */
  1068. if (pixMap.pmTable != NULL)
  1069. {
  1070. GlobalFree( pixMap.pmTable );
  1071. }
  1072. if (hasRegion && (rgn != NULL))
  1073. {
  1074. GlobalFree( rgn );
  1075. }
  1076. if (pixData != NULL)
  1077. {
  1078. GlobalFree( pixData );
  1079. }
  1080. }
  1081. break;
  1082. }
  1083. case ShortComment:
  1084. {
  1085. Word comment;
  1086. Boolean doComment;
  1087. Comment gdiComment;
  1088. /* get the comment word */
  1089. GetWord( &comment );
  1090. /* assume that we won't be generating an metafile comment */
  1091. doComment = FALSE;
  1092. /* determine the corresponding GDI comment for the comment */
  1093. switch (comment)
  1094. {
  1095. case picPostScriptBegin:
  1096. case picPostScriptEnd:
  1097. EPSComment(comment);
  1098. break;
  1099. case picLParen:
  1100. case picGrpBeg:
  1101. doComment = TRUE;
  1102. gdiComment.function = BEGIN_GROUP;
  1103. break;
  1104. case picRParen:
  1105. case picGrpEnd:
  1106. doComment = TRUE;
  1107. gdiComment.function = END_GROUP;
  1108. break;
  1109. case picBitBeg:
  1110. doComment = TRUE;
  1111. gdiComment.function = BEGIN_BANDING;
  1112. break;
  1113. case picBitEnd:
  1114. doComment = TRUE;
  1115. gdiComment.function = END_BANDING;
  1116. break;
  1117. case picPolyBegin:
  1118. /* indicate that we are in polygon mode, and reset buffer */
  1119. polyMode = PARSEPOLY;
  1120. polyParams = FRAMEPOLY;
  1121. NewPolygon();
  1122. break;
  1123. case picPolyEnd:
  1124. /* flush the polygon buffer and exit polygon mode */
  1125. DrawPolyBuffer();
  1126. polyMode = FALSE;
  1127. break;
  1128. case picPolyIgnore:
  1129. /* see if we should reset the polygon buffer */
  1130. if (polyMode == USEALTPOLY)
  1131. {
  1132. /* use the alternate polygon definition to draw */
  1133. NewPolygon();
  1134. }
  1135. else
  1136. {
  1137. /* otherwise, just use the current saved polygon buffer */
  1138. polyMode = SKIPALTPOLY;
  1139. }
  1140. break;
  1141. case picTextEnd:
  1142. /* set the global flag indicating we are exiting text mode */
  1143. grafPort.txRotation = 0;
  1144. grafPort.txFlip = QDFlipNone;
  1145. textMode = FALSE;
  1146. break;
  1147. default:
  1148. break;
  1149. }
  1150. /* if there is some comment to emit, then call GDI module */
  1151. if (doComment)
  1152. {
  1153. /* make this a public comment */
  1154. gdiComment.signature = PUBLIC;
  1155. gdiComment.size = 0;
  1156. /* call the gdi entry point */
  1157. GdiShortComment( &gdiComment );
  1158. }
  1159. break;
  1160. }
  1161. case LongComment:
  1162. {
  1163. Word comment;
  1164. Integer length;
  1165. /* get the comment function */
  1166. GetWord(&comment);
  1167. /* determine what should be done with the comment */
  1168. switch (comment)
  1169. {
  1170. case picPostScriptBegin:
  1171. case picPostScriptEnd:
  1172. case picPostScriptHandle:
  1173. {
  1174. if (EPSComment(comment) == 0) /* not EPS? */
  1175. {
  1176. GetWord( &length ); /* skip it */
  1177. }
  1178. else
  1179. {
  1180. length = 0; /* EPS was already read */
  1181. }
  1182. break;
  1183. }
  1184. case picPolySmooth:
  1185. {
  1186. /* read the total length of comment */
  1187. GetWord( &length );
  1188. /* read polygon parameter mask and set flag bits */
  1189. GetByte( &polyParams );
  1190. polyParams &= MASKPOLYBITS;
  1191. polyParams |= CHECK4SPLINE;
  1192. length--;
  1193. /* if we are to fill the polygon, indicate that fill required
  1194. just in case a PaintPoly() record appears before picPolyEnd */
  1195. if (polyParams & FILLPOLY)
  1196. {
  1197. /* or in the fill required bit */
  1198. polyParams |= FILLREQUIRED;
  1199. }
  1200. break;
  1201. }
  1202. case picTextBegin:
  1203. {
  1204. Byte unusedAlignment;
  1205. /* read the comment length */
  1206. GetWord( &length );
  1207. /* read in only relevant parameters - align, flip, rotation */
  1208. GetByte( &unusedAlignment );
  1209. GetByte( &grafPort.txFlip );
  1210. GetWord( &grafPort.txRotation );
  1211. length -= 4;
  1212. /* set the global flag indicating we are in text mode. The
  1213. only case this isn't true if for badly mangled SuperPaint
  1214. files that have invalid rotation and pt size information. */
  1215. if( !(superPaintFile && badSuperPaintText) )
  1216. {
  1217. textMode = TRUE;
  1218. textClipCheck = TRUE;
  1219. }
  1220. break;
  1221. }
  1222. case picTextCenter:
  1223. {
  1224. Fixed textCenterX;
  1225. Fixed textCenterY;
  1226. /* read the comment length */
  1227. GetWord( &length );
  1228. /* read y and x offsets to center of text rotation */
  1229. GetFixed( &textCenterY );
  1230. GetFixed( &textCenterX );
  1231. length -= 8;
  1232. /* copy only the highword of the fixed value to textCenter */
  1233. textCenter.x = (short) (HIWORD( textCenterX ));
  1234. textCenter.y = (short) (HIWORD( textCenterY ));
  1235. /* make sure that the center is rounded, not truncated */
  1236. if (LOWORD( textCenterX) & 0x8000)
  1237. textCenter.x++;
  1238. if (LOWORD( textCenterY) & 0x8000)
  1239. textCenter.y++;
  1240. /* indicate that text center needs to be re-computed */
  1241. newTextCenter = TRUE;
  1242. break;
  1243. }
  1244. case picAppComment:
  1245. {
  1246. DWord signature;
  1247. Word function;
  1248. Word realFunc;
  1249. /* read total comment length */
  1250. GetWord( &length );
  1251. /* make sure that there's enough space to read signature */
  1252. if (length < sizeofMacDWord )
  1253. {
  1254. /* if insufficient, just skip remaining data */
  1255. break;
  1256. }
  1257. /* read the signature of the application */
  1258. GetDWord( &signature );
  1259. length -= sizeofMacDWord ;
  1260. /* is this PowerPoint 'PPNT' signature and function size enough? */
  1261. if ((signature != POWERPOINT && signature != POWERPOINT_OLD) ||
  1262. (length < sizeofMacWord ))
  1263. {
  1264. /* if SuperPaint signature matches, flag for text checks */
  1265. if (signature == SUPERPAINT)
  1266. superPaintFile = TRUE;
  1267. /* if wrong signature, or insufficient space, bail */
  1268. break;
  1269. }
  1270. /* read the application function ID */
  1271. GetWord( &function );
  1272. length -= sizeofMacWord ;
  1273. /* mask out high-order bit to get "real" opcode */
  1274. realFunc = function & ~PC_REGISTERED;
  1275. /* determine what to do with the function specified */
  1276. switch (realFunc)
  1277. {
  1278. case PP_FONTNAME:
  1279. {
  1280. Byte fontFamily;
  1281. Byte charSet;
  1282. Byte fontName[32];
  1283. /* font name from GDI2QD - read the LOGFONT info */
  1284. GetByte( &fontFamily );
  1285. GetByte( &charSet );
  1286. GetString( fontName );
  1287. length = 0;
  1288. /* call Gdi module to override font selection */
  1289. GdiFontName( fontFamily, charSet, fontName );
  1290. break;
  1291. }
  1292. case PP_HATCHPATTERN:
  1293. {
  1294. Integer hatchIndex;
  1295. /* hatch pattern from GDI2QD - read hatch index value */
  1296. GetWord( (Word far *)&hatchIndex );
  1297. length = 0;
  1298. /* notify Gdi module of hatch to override fill pattern */
  1299. GdiHatchPattern( hatchIndex );
  1300. break;
  1301. }
  1302. case PP_BEGINFADE:
  1303. case PP_BEGINPICTURE:
  1304. case PP_DEVINFO:
  1305. {
  1306. DWord cmntSize;
  1307. Boolean doComment;
  1308. struct
  1309. {
  1310. Comment gdiComment;
  1311. union
  1312. {
  1313. struct
  1314. {
  1315. Byte version;
  1316. Boolean isShape;
  1317. Integer shapeIndex;
  1318. Integer shapeParam1;
  1319. Boolean olpNIL;
  1320. Rect orectDR;
  1321. Rect orect;
  1322. Word shape;
  1323. Integer shapeParam2;
  1324. Rect location;
  1325. Integer gradient;
  1326. Boolean fromBackground;
  1327. Boolean darker;
  1328. Integer arcStart;
  1329. Integer arcSweep;
  1330. Word backR;
  1331. Word backG;
  1332. Word backB;
  1333. Rect rSImage;
  1334. } fade;
  1335. Word entity;
  1336. Point unitsPerPixel;
  1337. } parm;
  1338. } cmnt;
  1339. #ifdef WIN32
  1340. memset( &cmnt, 0, sizeof( cmnt ));
  1341. #endif
  1342. /* so far, we won't be writting the Escape comment */
  1343. doComment = FALSE;
  1344. /* can we read the comment size? */
  1345. if (length < sizeofMacDWord )
  1346. {
  1347. /* couldn't read the size - just exit */
  1348. break;
  1349. }
  1350. /* read in a size field and validate */
  1351. GetDWord( &cmntSize );
  1352. length -= sizeofMacDWord ;
  1353. /* is this is an invalid PP3 size field (Word len) */
  1354. if (HIWORD( cmntSize ) != 0)
  1355. {
  1356. /* yes - just skip the remaining data */
  1357. break;
  1358. }
  1359. /* a valid comment was found - fill in header struct */
  1360. cmnt.gdiComment.signature = POWERPOINT;
  1361. cmnt.gdiComment.function = function;
  1362. cmnt.gdiComment.size = 0;
  1363. /* check if this is a zero-length comment */
  1364. if (cmntSize == 0)
  1365. {
  1366. /* make sure that the comment gets written */
  1367. doComment = TRUE;
  1368. }
  1369. /* process the begin fade comment */
  1370. else if (realFunc == PP_BEGINFADE)
  1371. {
  1372. /* can we read the version field? */
  1373. if (length < sizeof( Byte ))
  1374. {
  1375. /* can't read version - just bail */
  1376. break;
  1377. }
  1378. /* read the version field */
  1379. GetByte( &cmnt.parm.fade.version );
  1380. length -= sizeof( Byte );
  1381. /* if this is version 1 or 2, copy the bytes */
  1382. if (cmnt.parm.fade.version == 1 || cmnt.parm.fade.version == 2)
  1383. {
  1384. Handle cmntHandle;
  1385. Comment far * cmntLPtr;
  1386. Byte far * cmntDataLPtr;
  1387. DWord escapeSize;
  1388. Word i;
  1389. /* determine size and allocate the required buffer */
  1390. escapeSize = cmntSize + sizeof( Comment );
  1391. cmntHandle = GlobalAlloc( GHND, escapeSize );
  1392. /* make sure allocation succeeded */
  1393. if (cmntHandle == NULL)
  1394. {
  1395. ErSetGlobalError( ErMemoryFull );
  1396. break;
  1397. }
  1398. /* lock the buffer and assign the comment header */
  1399. cmntLPtr = (Comment far *)GlobalLock( cmntHandle );
  1400. /* set the correct signature and parameters */
  1401. cmntLPtr->signature = POWERPOINT;
  1402. cmntLPtr->function = function;
  1403. cmntLPtr->size = cmntSize;
  1404. /* get pointer to the data and assign the version */
  1405. cmntDataLPtr = ((Byte far *)cmntLPtr) + sizeof( Comment );
  1406. *cmntDataLPtr++ = cmnt.parm.fade.version;
  1407. /* copy the byte over - start at 1 for version read */
  1408. for (i = 1; i < (Word)cmntSize; i++)
  1409. {
  1410. /* copy over byte and increment pointer */
  1411. GetByte( cmntDataLPtr++ );
  1412. }
  1413. /* put the comment into the metafile */
  1414. GdiEscape( MFCOMMENT, (Word)escapeSize, (StringLPtr)cmntLPtr );
  1415. /* release the memory allocated for the structure */
  1416. GlobalUnlock( cmntHandle );
  1417. GlobalFree( cmntHandle );
  1418. }
  1419. /* otherwise, perform swapping for PP3 fade */
  1420. else if (cmnt.parm.fade.version == 3)
  1421. {
  1422. Word unusedWord;
  1423. if (length < ( 1 + (11 * sizeofMacWord) +
  1424. ( 4 * sizeofMacRect) + 4
  1425. ))
  1426. /* The above magic numbers come from:
  1427. GetByte
  1428. GetWord GetWord GetWord GetWord GetWord GetWord
  1429. GetWord GetWord GetWord GetWord GetWord
  1430. GetRect GetRect GetRect GetRect
  1431. GetBoolean GetBoolean GetBoolean GetBoolean
  1432. This is to make sure enough input left for
  1433. parameters - note that the Mac size is one less
  1434. than the GDI fade */
  1435. {
  1436. /* no - just bail */
  1437. break;
  1438. }
  1439. /* read in all remaining parameters */
  1440. GetBoolean( (Boolean far *)(&cmnt.parm.fade.isShape) );
  1441. GetWord( (Word far *)(&cmnt.parm.fade.shapeIndex) );
  1442. GetWord( (Word far *)(&cmnt.parm.fade.shapeParam1) );
  1443. GetBoolean( (Boolean far *)(&cmnt.parm.fade.olpNIL) );
  1444. GetByte( (Byte far *)(&unusedWord) );
  1445. GetRect( (Rect far *)(&cmnt.parm.fade.orectDR) );
  1446. GetRect( (Rect far *)(&cmnt.parm.fade.orect) );
  1447. GetWord( (Word far *)(&cmnt.parm.fade.shape) );
  1448. GetWord( (Word far *)(&cmnt.parm.fade.shapeParam2) );
  1449. GetRect( (Rect far *)(&cmnt.parm.fade.location) );
  1450. GetWord( (Word far *)(&cmnt.parm.fade.gradient) );
  1451. GetBoolean( (Boolean far *)(&cmnt.parm.fade.fromBackground) );
  1452. GetBoolean( (Boolean far *)(&cmnt.parm.fade.darker ) );
  1453. GetWord( (Word far *)(&cmnt.parm.fade.arcStart) );
  1454. GetWord( (Word far *)(&cmnt.parm.fade.arcSweep) );
  1455. GetWord( (Word far *)(&unusedWord) );
  1456. GetWord( (Word far *)(&cmnt.parm.fade.backR) );
  1457. GetWord( (Word far *)(&cmnt.parm.fade.backG) );
  1458. GetWord( (Word far *)(&cmnt.parm.fade.backB) );
  1459. GetRect( (Rect far *)(&cmnt.parm.fade.rSImage) );
  1460. /* determine the comment size */
  1461. cmnt.gdiComment.size = sizeof( cmnt.parm.fade );
  1462. /* make sure comment gets written */
  1463. doComment = TRUE;
  1464. }
  1465. /* no more bytes to read, flag that faded object started */
  1466. length = 0;
  1467. shadedObjectStarted = TRUE;
  1468. }
  1469. else if (realFunc == PP_BEGINPICTURE)
  1470. {
  1471. /* can we read the entity reference? */
  1472. if (length < sizeofMacWord )
  1473. {
  1474. /* no - just bail */
  1475. break;
  1476. }
  1477. /* read the entity reference */
  1478. GetWord( &cmnt.parm.entity );
  1479. length -= sizeofMacWord;
  1480. /* assign the correct comment size */
  1481. cmnt.gdiComment.size = sizeof( cmnt.parm.entity );
  1482. /* make sure comment gets written */
  1483. doComment = TRUE;
  1484. }
  1485. else if (realFunc == PP_DEVINFO)
  1486. {
  1487. /* can we read the units per pixel? */
  1488. if (length < sizeofMacPoint)
  1489. {
  1490. /* no - just bail */
  1491. break;
  1492. }
  1493. /* read the units per pixel */
  1494. GetPoint( (Point far *)&cmnt.parm.unitsPerPixel );
  1495. length -= sizeofMacPoint;
  1496. /* assign the size field */
  1497. cmnt.gdiComment.size = sizeof( cmnt.parm.unitsPerPixel );
  1498. /* make sure comment gets written */
  1499. doComment = TRUE;
  1500. }
  1501. /* write out the Gdi Escape comment */
  1502. if (doComment)
  1503. {
  1504. /* call the gdi entry point */
  1505. GdiEscape( MFCOMMENT, sizeof( Comment ) + (Word)cmnt.gdiComment.size, (StringLPtr)&cmnt );
  1506. }
  1507. break;
  1508. }
  1509. case PP_ENDFADE:
  1510. {
  1511. /* make sure that the BEGINFADE was put into metafile */
  1512. if (!shadedObjectStarted)
  1513. {
  1514. /* if not, then bail out */
  1515. break;
  1516. }
  1517. /* otherwise, just drop into the next case statement */
  1518. }
  1519. case PP_ENDPICTURE:
  1520. {
  1521. Comment gdiComment;
  1522. /* make this a private PowerPoint comment */
  1523. gdiComment.signature = POWERPOINT;
  1524. gdiComment.function = function;
  1525. gdiComment.size = 0;
  1526. /* call the gdi entry point */
  1527. GdiShortComment( &gdiComment );
  1528. /* if this is the end of fade, mask out flag check */
  1529. if (realFunc == PP_ENDFADE)
  1530. {
  1531. /* end fade was processed successfully */
  1532. shadedObjectStarted = FALSE;
  1533. }
  1534. break;
  1535. }
  1536. default:
  1537. break;
  1538. }
  1539. break;
  1540. }
  1541. default:
  1542. {
  1543. /* any other comment is just skipped */
  1544. GetWord( &length );
  1545. break;
  1546. }
  1547. }
  1548. /* skip any remaining bytes to be read */
  1549. IOSkipBytes( length );
  1550. break;
  1551. }
  1552. case opEndPic:
  1553. /* do nothing - picture is closing */
  1554. break;
  1555. case HeaderOp:
  1556. {
  1557. Integer version;
  1558. Word unusedReserved1;
  1559. Fixed hRes;
  1560. Fixed vRes;
  1561. Rect unusedRect;
  1562. DWord unusedReserved2;
  1563. /* read in the the version to determine if OpenCPort() was used
  1564. to open the picture, thus containing spatial resoultion info. */
  1565. GetWord( (Word far *)&version );
  1566. /* read any other parameters - will check later if they are valid.
  1567. If version == -1, we are reading over the bounding rectangle. */
  1568. GetWord( &unusedReserved1 );
  1569. GetFixed( &hRes );
  1570. GetFixed( &vRes );
  1571. /* check if bounding rect and spatial resolution are changed */
  1572. if (version == -2)
  1573. {
  1574. /* read in the optimal source rectangle */
  1575. GetRect( &grafPort.portRect );
  1576. /* use the integer portion of hRes for the resolution dpi */
  1577. resolution = HIWORD( hRes );
  1578. }
  1579. else
  1580. {
  1581. /* otherwise, read an unused rectangle coordinate pair */
  1582. GetRect( &unusedRect );
  1583. }
  1584. /* read the trailing unused reserved LongInt */
  1585. GetDWord( &unusedReserved2 );
  1586. break;
  1587. }
  1588. default:
  1589. SkipData( currOpcodeLPtr );
  1590. break;
  1591. }
  1592. /* set flag to skip ensuing font index if font name was provided */
  1593. skipFontID = (currOpcodeLPtr->function == FontName);
  1594. /* if global error, set opcode to opEndPic to exit main loop */
  1595. if (ErGetGlobalError() != NOERR)
  1596. {
  1597. currOpcodeLPtr->function = opEndPic;
  1598. currOpcodeLPtr->length = 0;
  1599. }
  1600. } /* TranslateOpcode */
  1601. private void SkipData( opcodeEntry far * currOpcodeLPtr )
  1602. /*-------------------*/
  1603. /* skip the data - the opcode won't be translated and Gdi module won't be
  1604. called to create anything in the metafile */
  1605. {
  1606. LongInt readLength = 0;
  1607. if (currOpcodeLPtr->length >= 0)
  1608. {
  1609. IOSkipBytes( currOpcodeLPtr->length );
  1610. }
  1611. else
  1612. {
  1613. readLength = 0;
  1614. switch (currOpcodeLPtr->length)
  1615. {
  1616. case CommentSize:
  1617. {
  1618. Word unusedFunction;
  1619. GetWord( (Word far *)&unusedFunction );
  1620. GetWord( (Word far *)&readLength );
  1621. break;
  1622. }
  1623. case RgnOrPolyLen:
  1624. {
  1625. GetWord( (Word far *)&readLength );
  1626. readLength -= 2;
  1627. break;
  1628. }
  1629. case WordDataLen:
  1630. {
  1631. GetWord( (Word far *)&readLength );
  1632. break;
  1633. }
  1634. case DWordDataLen:
  1635. {
  1636. GetDWord( (DWord far *)&readLength );
  1637. break;
  1638. }
  1639. case HiByteLen:
  1640. {
  1641. readLength = (currOpcodeLPtr->function >> 8) * 2;
  1642. break;
  1643. }
  1644. } /* switch () */
  1645. IOSkipBytes( readLength );
  1646. } /* else */
  1647. } /* SkipData */
  1648. void OpenPort( void )
  1649. /*-----------*/
  1650. /* initialize the grafPort */
  1651. {
  1652. /* set port version to unintialized state */
  1653. grafPort.portVersion = 0;
  1654. /* no polygons or regions saved yet */
  1655. grafPort.clipRgn = NIL;
  1656. grafPort.rgnSave = NIL;
  1657. grafPort.polySave = NIL;
  1658. /* initialize all patterns to old-style patterns */
  1659. grafPort.bkPixPat.patType = QDOldPat;
  1660. grafPort.pnPixPat.patType = QDOldPat;
  1661. grafPort.fillPixPat.patType = QDOldPat;
  1662. /* make patterns all solid */
  1663. QDCopyBytes( (Byte far *)&SolidPattern,
  1664. (Byte far *)&grafPort.bkPixPat.pat1Data, sizeof( Pattern ) );
  1665. QDCopyBytes( (Byte far *)&SolidPattern,
  1666. (Byte far *)&grafPort.pnPixPat.pat1Data, sizeof( Pattern ) );
  1667. QDCopyBytes( (Byte far *)&SolidPattern,
  1668. (Byte far *)&grafPort.fillPixPat.pat1Data, sizeof( Pattern ) );
  1669. /* foreground/background set to black on white */
  1670. grafPort.rgbFgColor = RGB( 0x00, 0x00, 0x00 ); /* black */
  1671. grafPort.rgbBkColor = RGB( 0xFF, 0xFF, 0xFF ); /* white */
  1672. /* various pen attributes */
  1673. grafPort.pnLoc.x = 0; /* pen location (0,0) */
  1674. grafPort.pnLoc.y = 0;
  1675. grafPort.pnSize.x = 1; /* pen size (1,1) */
  1676. grafPort.pnSize.y = 1;
  1677. grafPort.pnVis = 0; /* pen is visible */
  1678. grafPort.pnMode = QDPatCopy; /* copy ROP */
  1679. grafPort.pnLocHFrac = 0x00008000; /* 1/2 */
  1680. /* font attributes */
  1681. grafPort.txFont = 0; /* system font */
  1682. grafPort.txFace = 0; /* plain style */
  1683. grafPort.txMode = QDSrcOr;
  1684. grafPort.txSize = 0; /* system font size */
  1685. grafPort.spExtra = 0;
  1686. grafPort.chExtra = 0;
  1687. grafPort.txNumerator.x = /* text scaling ratio */
  1688. grafPort.txNumerator.y =
  1689. grafPort.txDenominator.x =
  1690. grafPort.txDenominator.y = 1;
  1691. grafPort.txRotation = 0; /* no rotation or flipping */
  1692. grafPort.txFlip = QDFlipNone;
  1693. /* assume 72 dpi - this may be overridden in HeaderOp opcode */
  1694. resolution = 72;
  1695. /* private global initialization */
  1696. polyMode = FALSE;
  1697. textMode = FALSE;
  1698. shadedObjectStarted = FALSE;
  1699. superPaintFile = FALSE;
  1700. /* text rotation variables */
  1701. newTextCenter = FALSE;
  1702. textCenter.x = textCenter.y = 0;
  1703. /* allocate space for the polygon buffer */
  1704. maxPoints = 16;
  1705. polyHandle = GlobalAlloc( GHND, (maxPoints + 3) * sizeof( Point ) );
  1706. if (polyHandle == NULL)
  1707. {
  1708. ErSetGlobalError( ErMemoryFull);
  1709. }
  1710. else
  1711. {
  1712. /* get pointer address and address for the polygon coordinate list */
  1713. numPointsLPtr = (Integer far *)GlobalLock( polyHandle );
  1714. polyListLPtr = (Point far *)(numPointsLPtr + POLYLIST);
  1715. }
  1716. } /* OpenPort */
  1717. private void ClosePort( void )
  1718. /*--------------------*/
  1719. /* close grafPort and de-allocate any memory blocks */
  1720. {
  1721. if (grafPort.clipRgn != NULL)
  1722. {
  1723. GlobalFree( grafPort.clipRgn );
  1724. grafPort.clipRgn = NULL;
  1725. }
  1726. if (grafPort.rgnSave != NULL)
  1727. {
  1728. GlobalFree( grafPort.rgnSave );
  1729. grafPort.rgnSave = NULL;
  1730. }
  1731. if (grafPort.polySave != NULL)
  1732. {
  1733. GlobalFree( grafPort.polySave );
  1734. grafPort.polySave = NULL;
  1735. }
  1736. /* make sure that all the possible pixel pattern bitmaps are freed */
  1737. if (grafPort.bkPixPat.patData != NULL)
  1738. {
  1739. GlobalFree( grafPort.bkPixPat.patMap.pmTable );
  1740. GlobalFree( grafPort.bkPixPat.patData );
  1741. grafPort.bkPixPat.patData = NULL;
  1742. }
  1743. if (grafPort.pnPixPat.patData != NULL)
  1744. {
  1745. GlobalFree( grafPort.pnPixPat.patMap.pmTable );
  1746. GlobalFree( grafPort.pnPixPat.patData );
  1747. grafPort.pnPixPat.patData = NULL;
  1748. }
  1749. if (grafPort.fillPixPat.patData != NULL)
  1750. {
  1751. GlobalFree( grafPort.fillPixPat.patMap.pmTable );
  1752. GlobalFree( grafPort.fillPixPat.patData );
  1753. grafPort.fillPixPat.patData = NULL;
  1754. }
  1755. /* deallocate the polygon buffer */
  1756. GlobalUnlock( polyHandle );
  1757. GlobalFree( polyHandle );
  1758. } /* ClosePort */
  1759. private void NewPolygon( void )
  1760. /*---------------------*/
  1761. /* initialize the state of the polygon buffer - flush any previous data */
  1762. {
  1763. /* initialize number of points and bounding box */
  1764. numPoints = 0;
  1765. polyBBox.left = polyBBox.top = MAXINT;
  1766. polyBBox.right = polyBBox.bottom = -MAXINT;
  1767. } /* NewPolygon */
  1768. private void AddPolySegment( Point start, Point end )
  1769. /*-------------------------*/
  1770. /* Add the line segment to the polygon buffer */
  1771. {
  1772. /* make sure that we are in polygon mode before adding vertex */
  1773. if (polyMode == PARSEPOLY || polyMode == USEALTPOLY)
  1774. {
  1775. Point pt;
  1776. Byte i;
  1777. /* loop through both points ... */
  1778. for (i = 0; i < 2; i++)
  1779. {
  1780. /* determine which point to process */
  1781. pt = (i == 0) ? start : end;
  1782. /* determine if we should expect a zero delta increment in both
  1783. dimensions, implying that the quadratic B-spline definition will
  1784. actually be rendered as a straight-edged polygon */
  1785. if ((numPoints <= 1) || (polyMode == USEALTPOLY))
  1786. {
  1787. zeroDeltaExpected = FALSE;
  1788. }
  1789. /* check if we are expecting a zero delta from last point */
  1790. if (zeroDeltaExpected && (polyParams & CHECK4SPLINE))
  1791. {
  1792. /* make sure we are adding a zero-length line segment */
  1793. if ((start.x == end.x) && (start.y == end.y))
  1794. {
  1795. /* just skip including this in the polygon buffer */
  1796. zeroDeltaExpected = FALSE;
  1797. break;
  1798. }
  1799. else
  1800. {
  1801. /* MacDraw is rendering a smoothed (quadratic B-spline) - flag
  1802. the fact that we should use the polygon simulation */
  1803. polyMode = USEALTPOLY;
  1804. }
  1805. }
  1806. else
  1807. {
  1808. /* make sure the point is different from last point */
  1809. if (numPoints == 0 ||
  1810. polyListLPtr[numPoints - 1].x != pt.x ||
  1811. polyListLPtr[numPoints - 1].y != pt.y)
  1812. {
  1813. /* make sure that we haven't reached maximum size */
  1814. if ((numPoints + 1) >= maxPoints)
  1815. {
  1816. /* expand the number of points that can be cached by 10 */
  1817. maxPoints += 16;
  1818. /* unlock to prepare for re-allocation */
  1819. GlobalUnlock( polyHandle);
  1820. /* re-allocate the memory handle by the given amount */
  1821. polyHandle = GlobalReAlloc(
  1822. polyHandle,
  1823. (maxPoints + 3) * sizeof( Point ),
  1824. GMEM_MOVEABLE);
  1825. /* make sure that the re-allocation succeeded */
  1826. if (polyHandle == NULL)
  1827. {
  1828. /* if not, flag global error and exit from here */
  1829. ErSetGlobalError( ErMemoryFull );
  1830. return;
  1831. }
  1832. /* get new pointer addresses the polygon coordinate list */
  1833. numPointsLPtr = (Integer far *)GlobalLock( polyHandle );
  1834. polyListLPtr = (Point far *)(numPointsLPtr + POLYLIST);
  1835. }
  1836. /* insert the new point and increment number of points */
  1837. polyListLPtr[numPoints++] = pt;
  1838. /* union new point with polygon bounding box */
  1839. polyBBox.left = min( polyBBox.left, pt.x );
  1840. polyBBox.top = min( polyBBox.top, pt.y );
  1841. polyBBox.right = max( polyBBox.right, pt.x );
  1842. polyBBox.bottom = max( polyBBox.bottom, pt.y );
  1843. /* toggle the state of zeroDeltaExpected - expect same point next time */
  1844. zeroDeltaExpected = TRUE;
  1845. }
  1846. }
  1847. }
  1848. }
  1849. } /* AddPolyPt */
  1850. private void DrawPolyBuffer( void )
  1851. /*-------------------------*/
  1852. /* Draw the polygon definition if the points were read without errors */
  1853. {
  1854. /* copy the point count and bounding box into the memory block */
  1855. *numPointsLPtr = sizeofMacWord + sizeofMacRect + (numPoints * sizeofMacPoint);
  1856. *((Rect far *)(numPointsLPtr + BBOX)) = polyBBox;
  1857. /* lock the polygon handle before rendering */
  1858. GlobalUnlock( polyHandle );
  1859. /* check if we should fill the polygon or if already done */
  1860. if ((polyParams & FILLPOLY) && (polyParams & FILLREQUIRED))
  1861. {
  1862. Boolean resetFg;
  1863. Boolean resetBk;
  1864. RGBColor saveFg;
  1865. RGBColor saveBk;
  1866. /* set up fore- and background colors if they have changed */
  1867. resetFg = (polyFgColor != grafPort.rgbFgColor);
  1868. resetBk = (polyBkColor != grafPort.rgbBkColor);
  1869. if (resetFg)
  1870. {
  1871. /* change the foreground color and notify Gdi of change */
  1872. saveFg = grafPort.rgbFgColor;
  1873. grafPort.rgbFgColor = polyFgColor;
  1874. GdiMarkAsChanged( GdiFgColor );
  1875. }
  1876. if (resetBk)
  1877. {
  1878. /* change the background color and notify Gdi of change */
  1879. saveBk = grafPort.rgbBkColor;
  1880. grafPort.rgbBkColor = polyBkColor;
  1881. GdiMarkAsChanged( GdiBkColor );
  1882. }
  1883. /* call gdi routine to draw polygon */
  1884. GdiPolygon( GdiFill, polyHandle );
  1885. if (resetFg)
  1886. {
  1887. /* change the foreground color and notify Gdi of change */
  1888. grafPort.rgbFgColor = saveFg;
  1889. GdiMarkAsChanged( GdiFgColor );
  1890. }
  1891. if (resetBk)
  1892. {
  1893. /* change the background color and notify Gdi of change */
  1894. grafPort.rgbBkColor = saveBk;
  1895. GdiMarkAsChanged( GdiBkColor );
  1896. }
  1897. }
  1898. /* should the polygon be framed? */
  1899. if ((polyParams & FRAMEPOLY) &&
  1900. (grafPort.pnSize.x != 0) && (grafPort.pnSize.y != 0))
  1901. {
  1902. /* notify gdi that this is the same primitive */
  1903. GdiSamePrimitive( polyParams & FILLPOLY );
  1904. GdiPolygon( GdiFrame, polyHandle );
  1905. /* notify gdi that this is no longer the same primitive */
  1906. GdiSamePrimitive( FALSE );
  1907. }
  1908. /* get pointer address and address for the polygon coordinate list */
  1909. numPointsLPtr = (Integer far *)GlobalLock( polyHandle );
  1910. polyListLPtr = (Point far *)(numPointsLPtr + POLYLIST);
  1911. } /* DrawPolyBuffer */
  1912. private void AdjustTextRotation( Point far * newPt )
  1913. /*-----------------------------*/
  1914. /* This will calculate the correct text position if text is rotated */
  1915. {
  1916. if (textMode && (grafPort.txRotation != 0) &&
  1917. ((textCenter.x != 0) || (textCenter.y != 0)))
  1918. {
  1919. Point location;
  1920. Point center;
  1921. /* copy the new location to local variable */
  1922. location = *newPt;
  1923. /* ensure that a new text rotation was specified - recompute center */
  1924. if (newTextCenter)
  1925. {
  1926. Real degRadian;
  1927. /* calculate the new center of rotation */
  1928. center.x = textCenter.x + location.x;
  1929. center.y = textCenter.y + location.y;
  1930. /* calculate the sin() and cos() of the specified angle of rotation */
  1931. degRadian = ((Real)grafPort.txRotation * TwoPi) / 360.0;
  1932. degCos = cos( degRadian );
  1933. degSin = sin( degRadian );
  1934. /* use transformation matrix to compute offset to text center */
  1935. textCenter.x = (Integer)((center.x * (1.0 - degCos)) +
  1936. (center.y * degSin));
  1937. textCenter.y = (Integer)((center.y * (1.0 - degCos)) -
  1938. (center.x * degSin));
  1939. /* indicate that the new text center was computed */
  1940. newTextCenter = FALSE;
  1941. }
  1942. /* use transformation matrix to compute the new text basline location */
  1943. newPt->x = (Integer)((location.x * degCos) -
  1944. (location.y * degSin) + textCenter.x);
  1945. newPt->y = (Integer)((location.x * degSin) +
  1946. (location.y * degCos) + textCenter.y);
  1947. }
  1948. } /* AdjustTextRotation */
  1949. /****
  1950. *
  1951. * EPSComment(comment)
  1952. * Encapsulated PostScript Handler which translates Mac EPS to GDI EPS.
  1953. * This routine has intimate knowledge of the implementation of both
  1954. * Mac and GDI EPS filters. It processes Mac PostScript comments.
  1955. *
  1956. * returns:
  1957. * >0 successfully parsed EPS data
  1958. * 0 not EPS comment
  1959. * <0 error
  1960. *
  1961. * How the EPS filter works:
  1962. * The Mac EPS filter uses special features in the LaserWriter driver
  1963. * to send the PICT bounding box to the printer whre it is examined
  1964. * by PostScript code. The filter outputs a preamble which is a
  1965. * combination of QuickDraw and PostScript. This preamble is sent
  1966. * before the PostScript date from the EPS file. It sets the pen
  1967. * position for opposing corners of the PICT bounding box using
  1968. * QuickDraw and reads the pen position back in PostScript. Any
  1969. * transformations which have been set up in QuickDraw by the
  1970. * application to position or scale the picture will be applied
  1971. * to the coordinates of the bounding box sent by the preamble.
  1972. * PostScript code determines the transformation necessary to map the
  1973. * EPS bounding box onto the physical bounding box read from
  1974. * QuickDraw. These transformations are then applied to the PostScript
  1975. * picture when it is displayed.
  1976. *
  1977. * Operation of the GDI EPS filter is very similar except that it
  1978. * outputs a combination of GDI and PostScript.
  1979. *
  1980. * Implementation:
  1981. * The code can be in one of several states. Recognition of specific
  1982. * PostScript strings causes transition between states.
  1983. * PS_NONE Initial state, indicates no PostScript has been seen yet
  1984. * In this state, QuickDraw to GDI translation proceeds
  1985. * normally but PostScript data is examined.
  1986. * When a PostScript record is found with the string
  1987. * "pse\rpsb\r", the start of the PostScript preamble
  1988. * has been found and the program goes into state PS_PREAMBLE.
  1989. * PS_PREAMBLE All PostScript encountered in this state is ignored
  1990. * PostScript record starting with the string "[" is found.
  1991. * This is the PostScript bounding box specification.
  1992. * As soon as we see the bounding box, we have enough
  1993. * information to output the GDI EPS preamble and we go
  1994. * to state PS_BBOX.
  1995. * PS_BBOX PostScript is still ignored until a record beginning
  1996. * with "%!PS" is found, putting us into state PS_DATA.
  1997. * PS_DATA In this state, PostScript records are not ignored because
  1998. * PostScript seen now is from the EPS file. These records
  1999. * are translated to GDI POSTSCRIPT_DATA escapes.
  2000. * If the PostScript trailer "pse\rpsb\r" is encountered,
  2001. * it is ignored. If a PostScriptEnd comment is found
  2002. * it signals the end of the EPS data. We output the
  2003. * GDI PostScript trailer and we go back to state PS_NONE.
  2004. *
  2005. * Comment PostScriptHandle:
  2006. * if state == PS_NONE & data == "pse\rpsb\r"
  2007. * state = PS_PREAMBLE
  2008. * else if state == PS_PREAMBLE & data == "[ %d %d %d %d ]"
  2009. * state = PS_BBOX; output GDI EPS preamble
  2010. * else if state == PS_BBOX & data begins with "%!PS"
  2011. * state = PS_DATA
  2012. * else if state == PS_DATA
  2013. * if data == "pse\rpsb\r" ignore (is Mac PS trailer)
  2014. * else output PostScript data to GDI
  2015. *
  2016. * Comment PostScriptEnd:
  2017. * if state == PS_DATA
  2018. * state = PS_NONE; output GDI EPS trailer; exit
  2019. *
  2020. * QuickDraw primitives:
  2021. * translate QuickDraw to GDI normally
  2022. *
  2023. ****/
  2024. #define PS_ERROR (-1)
  2025. #define PS_NONE 0
  2026. #define PS_PREAMBLE 1
  2027. #define PS_BBOX 2
  2028. #define PS_DATA 3
  2029. #define PS_ENDWAIT 4
  2030. private Integer EPSComment(Word comment)
  2031. {
  2032. static Integer state = PS_NONE;
  2033. switch (comment)
  2034. {
  2035. case picPostScriptBegin:
  2036. break;
  2037. case picPostScriptEnd:
  2038. if (state == PS_DATA)
  2039. {
  2040. GdiEPSTrailer(); // output GDI trailer
  2041. state = PS_NONE; // end, successful translation
  2042. }
  2043. break;
  2044. case picPostScriptHandle:
  2045. if ((state = EPSData(state)) < 0) // process EPS data
  2046. return (-1); // error during processing
  2047. break;
  2048. default: // not a PostScript comment
  2049. return (0);
  2050. }
  2051. return (1);
  2052. }
  2053. /****
  2054. *
  2055. * Integer EPSData(Integer state)
  2056. * Process EPS Data found in the PostScriptHandle comment.
  2057. * What we do with the EPS data depends on the current state
  2058. * we are in and what the PostScript data looks like.
  2059. *
  2060. * State PS Data Action
  2061. * ----------------------------------------------------------------
  2062. * PS_NONE PS preamble string state = PS_BEGIN
  2063. * PS_PREAMBLE [ ... ] state = PS_BBOX, output GDI preamble
  2064. * PS_BBOX %!PS state = PS_DATA
  2065. * PS_DATA PS preamble string ignore, is Mac PS trailer
  2066. * PS_DATA PS data output as GDI PS data
  2067. *
  2068. * The Mac PostScript preamble string indicates that the PostScript
  2069. * data was from the Mac EPS filter. It puts us into PS_PREAMBLE state
  2070. * where we look for the bounding box specification (which begins
  2071. * with "["). When this is found, we go to state PS_BBOX and output
  2072. * the GDI EPS preamble using the bounding box. From PS_BBOX we can
  2073. * go into state PS_DATA when we find the record beginning with !PS
  2074. * which designates the start of the read EPS data.
  2075. *
  2076. * Once in state PS_DATA, PostScript data is buffered up into GDI
  2077. * printer escapes and output to the GDI stream. These are the only
  2078. * PostScript records that are translated - all others are ignored.
  2079. *
  2080. ****/
  2081. private Integer EPSData(Integer state)
  2082. {
  2083. GLOBALHANDLE h;
  2084. PSBuf far* psbuf;
  2085. char far* ptr;
  2086. Word len = 0;
  2087. Rect ps_bbox;
  2088. /*
  2089. * Allocate a buffer for the PostScript data. The first WORD
  2090. * of the buffer gives the number of bytes of PostScript data.
  2091. * The actual data follows. This is the format needed for
  2092. * the GDI Escape call.
  2093. */
  2094. GetWord(&len); // length of EPS comment
  2095. if ((h = GlobalAlloc(GHND, (DWORD) len + sizeof(PSBuf))) == 0)
  2096. {
  2097. ErSetGlobalError(ErMemoryFull); // memory allocation error
  2098. return (-1);
  2099. }
  2100. psbuf = (PSBuf far *) GlobalLock(h);
  2101. psbuf->length = len; // save byte length
  2102. ptr = (char far *) &psbuf->data; // -> PostScript data
  2103. while (len-- != 0) GetByte(ptr++); // read PS data into buffer
  2104. *ptr = 0 ; // null terminate it
  2105. ptr = (char far *) &psbuf->data; // -> PostScript data
  2106. /* If this is a superPaint file, and postscript is being processed,
  2107. check if this is a situation where text could be mangled beyond
  2108. belief and requires adjustment in the parsing process. */
  2109. if (superPaintFile && state == PS_NONE)
  2110. {
  2111. char save;
  2112. Word start = lstrlen( SUPERPAINT_TEXTSTARTJUNK );
  2113. Word stop = lstrlen( SUPERPAINT_TEXTSTOPJUNK );
  2114. /* Assume that this text is OK for now */
  2115. badSuperPaintText = FALSE;
  2116. /* If this buffer is long enough to hold the begin and end of the bogus
  2117. test Postcript commands (dealing with rotation and shearin)... */
  2118. if (psbuf->length > (start + stop))
  2119. {
  2120. /* Create a string and compare for the beginning sequence and ending
  2121. sequences. Restore the null "C" terminator after finished. */
  2122. save = *(ptr + start);
  2123. *(ptr + start) = 0;
  2124. badSuperPaintText = (lstrcmp(ptr, SUPERPAINT_TEXTSTARTJUNK) == 0 &&
  2125. lstrcmp(ptr + psbuf->length - stop, SUPERPAINT_TEXTSTOPJUNK) == 0);
  2126. *(ptr + start) = save;
  2127. }
  2128. }
  2129. /*
  2130. * If PostScript preamble is found in state PS_NONE we can advance to
  2131. * state PS_PREAMBLE. If it is found again before state PS_DATA,
  2132. * we have an incorrect sequence and should not translate this EPS.
  2133. * On the MAC, the preamble is the same as the trailer and, if found
  2134. * during state PS_ENDWAIT, it signals the end of EPS processing.
  2135. */
  2136. if (lstrcmp(ptr, MAC_PS_PREAMBLE) == 0)
  2137. switch (state)
  2138. {
  2139. case PS_NONE: // waiting for preamble
  2140. state = PS_PREAMBLE;
  2141. break;
  2142. case PS_DATA: // ignore Mac trailer
  2143. break;
  2144. default: // error if found in other states
  2145. state = PS_NONE; // abort EPS processing
  2146. break;
  2147. }
  2148. /*
  2149. * PostScript date was not MAC EPS preamble. Process other states
  2150. */
  2151. else switch (state)
  2152. {
  2153. case PS_PREAMBLE: // waiting for bbox
  2154. if (EPSBbox(psbuf, &ps_bbox))
  2155. {
  2156. GdiEPSPreamble(&ps_bbox);
  2157. state = PS_BBOX; // parsed bbox, wait for EPS data
  2158. }
  2159. break;
  2160. case PS_BBOX: // waiting for !PS
  2161. if ((ptr[0] == '%') &&
  2162. (ptr[1] == '!') &&
  2163. (ptr[2] == 'P') &&
  2164. (ptr[3] == 'S'))
  2165. state = PS_DATA; // found start of EPS data
  2166. else break;
  2167. case PS_DATA: // output EPS data to GDI
  2168. if (lstrcmp(ptr, MAC_PS_TRAILER) != 0)
  2169. GdiEPSData(psbuf); // but ignore PS trailer
  2170. state = PS_DATA;
  2171. break;
  2172. }
  2173. GlobalUnlock(h);
  2174. GlobalFree(h); // free PostScript buffer
  2175. return (state);
  2176. }
  2177. /****
  2178. *
  2179. * Boolean EPSBbox(PSBuf, Rect far *)
  2180. * Parse EPS bounding box string [ %d %d %d %d ] and store corners
  2181. * of bounding box in given rectangle.
  2182. *
  2183. * returns:
  2184. * 0 = cannot parse bounding box descriptor
  2185. * 1 = bounding box successfully parsed
  2186. *
  2187. ****/
  2188. private Boolean EPSBbox(PSBuf far *psbuf, Rect far *bbox)
  2189. {
  2190. char far* ptr = psbuf->data;
  2191. while ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\n'))
  2192. ++ptr;
  2193. if (*ptr++ != '[') return (0);
  2194. if (!(ptr = parse_number(ptr, &bbox->left))) return (0);
  2195. if (!(ptr = parse_number(ptr, &bbox->top))) return (0);
  2196. if (!(ptr = parse_number(ptr, &bbox->right))) return (0);
  2197. if (!(ptr = parse_number(ptr, &bbox->bottom))) return (0);
  2198. if (*ptr != ']') return(0);
  2199. return(1);
  2200. }
  2201. private char far* parse_number(char far* ptr, Integer far *iptr)
  2202. {
  2203. Boolean isneg = 0; // assume positive
  2204. Integer n = 0;
  2205. while ((*ptr == ' ') || (*ptr == '\t'))
  2206. ++ptr; // skip whitespace
  2207. if (*ptr == '-') // number is negative?
  2208. {
  2209. isneg = 1;
  2210. ++ptr;
  2211. }
  2212. if (!IsCharDigit(*ptr)) return(0); // digit must follow
  2213. do n = n * 10 + (*ptr++ - '0');
  2214. while (IsCharDigit(*ptr));
  2215. if (*ptr == '.') // skip any digits following decimal pt
  2216. {
  2217. do ++ptr;
  2218. while (IsCharDigit(*ptr));
  2219. }
  2220. while ((*ptr == ' ') || (*ptr == '\t'))
  2221. ++ptr; // skip whitespace
  2222. if (isneg) n = -n; // remember the sign
  2223. *iptr = n;
  2224. return (ptr);
  2225. }