Subversion Repositories filter_foundry

Rev

Rev 245 | Rev 247 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.     This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
  3.     Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
  4.     Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19. */
  20.  
  21. //#include <stdio.h>
  22. //#include <sound.h>
  23.  
  24. #include "ff.h"
  25.  
  26. #include "node.h"
  27. #include "funcs.h"
  28. #include "y.tab.h"
  29. #include "scripting.h"
  30. #include <math.h>
  31. #include "PIBufferSuite.h"
  32.  
  33. struct node *tree[4];
  34. char *err[4];
  35. int errpos[4],errstart[4],nplanes,cnvused,chunksize,toprow;
  36. value_type slider[8],cell[NUM_CELLS],map[4][0x100];
  37. char *expr[4];
  38. // long maxSpace;
  39. globals_t *gdata;
  40. FilterRecordPtr gpb;
  41.  
  42. #ifdef MAC_ENV
  43.         #define HINSTANCE HANDLE
  44.         #define hDllInstance NULL /* fake this Windows-only global */
  45. #endif
  46.  
  47. #ifdef WIN_ENV
  48. #include "manifest.h"
  49. #endif
  50.  
  51. extern struct sym_rec predefs[];
  52. extern int nplanes,varused[];
  53.  
  54. int checkandinitparams(Handle params);
  55.  
  56. // MPW MrC requires prototype
  57. DLLEXPORT MACPASCAL
  58. void ENTRYPOINT(short selector,FilterRecordPtr pb,intptr_t *data,short *result);
  59.  
  60. DLLEXPORT MACPASCAL
  61. void ENTRYPOINT(short selector, FilterRecordPtr pb, intptr_t *data, short *result){
  62.         static Boolean wantdialog = false;
  63.         static Boolean premiereWarnedOnce = false;
  64.         OSErr e = noErr;
  65.         char *reason;
  66. #ifdef WIN_ENV
  67.         // For Windows, we use an activation context to enforce that our Manifest resource will
  68.         // be used. This allows us to use Visual Styles, even if the host application does not
  69.         // support it.
  70.         ManifestActivationCtx manifestVars;
  71.         BOOL activationContextUsed;
  72. #endif
  73.  
  74.         EnterCodeResource();
  75.  
  76.         /*
  77.         char* s = (char*)malloc(512);
  78.         sprintf(s, "Host signature: '%c%c%c%c' (%d)\nMaxSpace32 = %d\nMaxSpace64 = %lld\nNum buffer procs: %d", (pb->hostSig >> 24) & 0xFF, (pb->hostSig >> 16) & 0xFF, (pb->hostSig >> 8) & 0xFF, pb->hostSig & 0xFF, pb->hostSig, pb->maxSpace, pb->maxSpace64, pb->bufferProcs->numBufferProcs);
  79.         simplealert(s);
  80.         */
  81.  
  82.         if (pb->hostSig == HOSTSIG_ADOBE_PREMIERE) {
  83.                 // DM 19.07.2021 : Tried running the 8BF file in Adobe Premiere 5 (yes, that's possible,
  84.                 // and there is even a FilterFactory for Premeire!),
  85.                 // but it crashes in evalpixel() where there is write-access to the "outp".
  86.                 // Probably the canvas structure is different (maybe it contains frames to achieve transitions?)
  87.                 if (!premiereWarnedOnce) {
  88.                         simplealert(_strdup("This version of Filter Foundry is not compatible with Adobe Premiere!"));
  89.                 }
  90.                 premiereWarnedOnce = true;
  91.                 *result = errPlugInHostInsufficient;
  92.                 return;
  93.         }
  94.  
  95.         if(selector != filterSelectorAbout && !*data){
  96.                 PSBufferSuite1* pSBufferSuite32 = NULL;
  97.  
  98.                 // Register "gdata" that contains the PARM information and other things which need to be persistant
  99.                 // TODO: memory leak? where is the stuff freed?
  100.                 if ((pb->sSPBasic == 0) ||
  101.                    (pb->sSPBasic->AcquireSuite(kPSBufferSuite, kPSBufferSuiteVersion1, (const void**)&pSBufferSuite32)) ||
  102.                    (pSBufferSuite32 == NULL))
  103.                 {
  104.                         // Old deprecated buffer suite
  105.                         BufferID tempId;
  106.                         if ((*result = pb->bufferProcs->allocateProc(sizeof(globals_t), &tempId))) return;
  107.                         *data = (intptr_t)pb->bufferProcs->lockProc(tempId, true);
  108.                         gdata = (globals_t*)*data; // preserve for the next invocation!
  109.                 }
  110.                 else
  111.                 {
  112.                         // New buffer suite (but only 32-bit version 1, because version 2 has problems with old Photoshop versions)
  113.                         // Windows Photoshop 7 and CS 2 accepts kPSBufferSuiteVersion2, but doesn't correctly implement it:
  114.                         // The symbols "New" and "GetSpace64" point to memory memory addresses outside the Photoshop.exe address range.
  115.                         // (Other Photoshop versions were not tested.)
  116.                         // 64-bit support for Windows was established in Photoshop CS 4,
  117.                         // and PSBufferSuite2 was first documented in SDK CS 6.
  118.                         // So, kPSBufferSuiteVersion2 probably was partically implemented as hidden "Work in progress" version
  119.                         // before it was publicly documented.
  120.                         // Side note:  pb->bufferSpace64/pb->maxSpace64 was documented in SDK CC 2017.
  121.                         //             pb->bufferProcs->allocateProc64/spaceProc64 was documented in SDK CS 6.
  122.                         unsigned32 siz = sizeof(globals_t);
  123.                         *data = (intptr_t)pSBufferSuite32->New(&siz, siz);
  124.                         if ((*data == 0) || (siz == 0)) {
  125.                                 *result = errPlugInHostInsufficient; // TODO: what is the correct error code for "out of memory"?
  126.                                 return;
  127.                         }
  128.                         gdata = (globals_t*)*data;
  129.                         pb->sSPBasic->ReleaseSuite(kPSBufferSuite, kPSBufferSuiteVersion1);
  130.                 }
  131.                 gdata->standalone = gdata->parmloaded = false;
  132.         } else {
  133.                 gdata = (globals_t*)*data;
  134.         }
  135.  
  136. #ifdef WIN_ENV
  137.         activationContextUsed = ActivateManifest((HMODULE)hDllInstance, 1, &manifestVars);
  138. #endif
  139.  
  140.         gpb = pb;
  141.  
  142.         nplanes = MIN(pb->planes,4);
  143.  
  144.         switch (selector){
  145.         case filterSelectorAbout:
  146.                 if (!gdata) {
  147.                         gdata = (globals_t*)malloc(sizeof(globals_t));
  148.                         if (!gdata) break;
  149.                         gdata->standalone = gdata->parmloaded = readPARMresource((HMODULE)hDllInstance,&reason,READ_OBFUSC);
  150.                         DoAbout((AboutRecordPtr)pb);
  151.                         free(gdata);
  152.                         gdata = NULL;
  153.                 } else {
  154.                         DoAbout((AboutRecordPtr)pb);
  155.                 }
  156.                 break;
  157.         case filterSelectorParameters:
  158.                 wantdialog = true;
  159.                 break;
  160.         case filterSelectorPrepare:
  161.                 DoPrepare(pb);
  162.                 init_symtab(predefs); // ready for parser calls
  163.                 init_trigtab();
  164.                 break;
  165.         case filterSelectorStart:
  166.                 if (HAS_BIG_DOC(pb)) {
  167.                         // The BigDocument structure is required if the document is larger than 30,000 pixels
  168.                         // It deprecates imageSize, filterRect, inRect, outRect, maskRect, floatCoord, and wholeSize.
  169.                         // By setting it to nonzero, we communicate to Photoshop that we support the BigDocument structure.
  170.                         pb->bigDocumentData->PluginUsing32BitCoordinates = true;
  171.                 }
  172.  
  173.                 /* initialise the parameter handle that Photoshop keeps for us */
  174.                 if(!pb->parameters)
  175.                         pb->parameters = PINEWHANDLE(1); // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that.
  176.  
  177.                 wantdialog |= checkandinitparams(pb->parameters);
  178.  
  179.                 /* wantdialog = false means that we never got a Parameters call, so we're not supposed to ask user */
  180.                 if( wantdialog && (!gdata->standalone || gdata->parm.popDialog) ){
  181.                         if( maindialog(pb) ){
  182.                                 if (!host_preserves_parameters()) {
  183.                                         /* Workaround for GIMP/PSPI, to avoid that formulas vanish when you re-open the main window.
  184.                                            The reason is a bug in PSPI: The host should preserve the value of pb->parameters, which PSPI does not do.
  185.                                            Also, all global variables are unloaded, so the plugin cannot preserve any data.
  186.                                            Workaround in FF 1.7: If the host GIMP is detected, then a special mode will be activated.
  187.                                            This mode saves the filter data into a temporary file "FilterFoundry.afs" and loads it
  188.                                            when the window is opened again. */
  189.                                         // Workaround: Save settings in "FilterFoundry.afs" if the host does not preserve pb->parameters
  190.                                         char outfilename[255];
  191.                                         char* tempdir;
  192.                                         StandardFileReply sfr;
  193.                                         sfr.sfGood = true;
  194.                                         sfr.sfReplacing = true;
  195.                                         sfr.sfType = PS_FILTER_FILETYPE;
  196.  
  197.                                         tempdir = getenv("TMP");
  198.                                         #ifdef WIN_ENV
  199.                                         if (strlen(tempdir) > 0) strcat(tempdir, "\\");
  200.                                         #else
  201.                                         if (strlen(tempdir) > 0) strcat(tempdir, "/");
  202.                                         #endif
  203.                                         sprintf(outfilename, "%sFilterFoundry.afs", tempdir);
  204.  
  205.                                         myc2pstrcpy(sfr.sfFile.name, outfilename);
  206.                                         #ifdef WIN_ENV
  207.                                         sfr.nFileExtension = (WORD)(strlen(outfilename) - strlen(".afs"));
  208.                                         #endif
  209.                                         sfr.sfScript = 0; // FIXME: is that ok?
  210.                                         savefile(&sfr);
  211.                                 }
  212.  
  213.                                 /* update stored parameters from new user settings */
  214.                                 saveparams(pb->parameters);
  215.                         }else
  216.                                 e = userCanceledErr;
  217.                 }
  218.                 wantdialog = false;
  219.  
  220.                 if(!e){
  221.                         if(setup(pb)){
  222.                                 DoStart(pb);
  223.                         }else{
  224.                                 SYSBEEP(1);
  225.                                 e = filterBadParameters;
  226.                         }
  227.                 }
  228.                 break;
  229.         case filterSelectorContinue:
  230.                 e = DoContinue(pb);
  231.                 break;
  232.         case filterSelectorFinish:
  233.                 DoFinish(pb);
  234.                 break;
  235.         default:
  236.                 e = filterBadParameters;
  237.         }
  238.  
  239.         *result = e;
  240.  
  241. #ifdef WIN_ENV
  242.         if (activationContextUsed) DeactivateManifest(&manifestVars);
  243. #endif
  244.  
  245.         ExitCodeResource();
  246. }
  247.  
  248. int checkandinitparams(Handle params){
  249.         char *reasonstr,*reason;
  250.         int i,bUninitializedParams;
  251.         Boolean showdialog;
  252.  
  253.         if (!host_preserves_parameters()) {
  254.                 // Workaround: Load settings in "FilterFoundry.afs" if host does not preserve pb->parameters
  255.                 char outfilename[255];
  256.                 char* tempdir;
  257.                 StandardFileReply sfr;
  258.                 sfr.sfGood = true;
  259.                 sfr.sfReplacing = true;
  260.                 sfr.sfType = PS_FILTER_FILETYPE;
  261.  
  262.                 tempdir = getenv("TMP");
  263.                 #ifdef WIN_ENV
  264.                 if (strlen(tempdir) > 0) strcat(tempdir, "\\");
  265.                 #else
  266.                 if (strlen(tempdir) > 0) strcat(tempdir, "/");
  267.                 #endif
  268.                 sprintf(outfilename, "%sFilterFoundry.afs", tempdir);
  269.  
  270.                 myc2pstrcpy(sfr.sfFile.name, outfilename);
  271.                 #ifdef WIN_ENV
  272.                 sfr.nFileExtension = (WORD)(strlen(outfilename) - strlen(".afs"));
  273.                 #endif
  274.                 sfr.sfScript = 0; // FIXME: is that ok?
  275.                 if (loadfile(&sfr, &reason)) return true;
  276.         }
  277.  
  278.         if( (bUninitializedParams = !(params && readparams(params,false,&reasonstr))) ){
  279.                 /* either the parameter handle was uninitialised,
  280.                    or the parameter data couldn't be read; set default values */
  281.  
  282.                 // see if saved parameters exist
  283.                 gdata->standalone = gdata->parmloaded = readPARMresource((HMODULE)hDllInstance,&reason,READ_OBFUSC);
  284.  
  285.  
  286.                 if(!gdata->standalone){
  287.                         // no saved settings (not standalone)
  288.                         for(i = 0; i < 8; ++i)
  289.                                 slider[i] = i*10+100;
  290.                         for(i = 0; i < 4; ++i)
  291.                                 if(expr[i])
  292.                                         free(expr[i]);
  293.                         if(gpb->imageMode == plugInModeRGBColor){
  294.                                 expr[0] = _strdup("r");
  295.                                 expr[1] = _strdup("g");
  296.                                 expr[2] = _strdup("b");
  297.                                 expr[3] = _strdup("a");
  298.                         }else{
  299.                                 expr[0] = _strdup("c");
  300.                                 expr[1] = _strdup("c");
  301.                                 expr[2] = _strdup("c");
  302.                                 expr[3] = _strdup("c");
  303.                         }
  304.                 }
  305.         }
  306.  
  307.         // let scripting system change parameters, if we're scripted;
  308.         // user may want to force display of dialog during scripting playback
  309.         switch (ReadScriptParamsOnRead()) {
  310.                 case SCR_SHOW_DIALOG:
  311.                         showdialog = true;
  312.                         break;
  313.                 case SCR_HIDE_DIALOG:
  314.                         showdialog = false;
  315.                         break;
  316.                 default:
  317.                 case SCR_NO_SCRIPT:
  318.                         showdialog = bUninitializedParams;
  319.                         break;
  320.         }
  321.  
  322.         saveparams(params);
  323.  
  324.         return showdialog;
  325. }
  326.  
  327. Boolean host_preserves_parameters() {
  328.         if (gpb->hostSig == HOSTSIG_GIMP) return false;
  329.         if (gpb->hostSig == HOSTSIG_IRFANVIEW) return false;
  330.  
  331.         /*
  332.         char x[100];
  333.         sprintf(x, "Host Signature: %u", gpb->hostSig);
  334.         simplealert(x);
  335.         */
  336.  
  337.         // We just assume the other hosts preserve the parameters
  338.         return true;
  339. }
  340.  
  341. int64_t maxspace(){
  342.         // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
  343.  
  344.         // Plugins that don't support MaxSpace64 shall set the field to zero; then we will use MaxSpace instead.
  345.         // Also check "gpb->bufferProcs->numBufferProcs" to see if 64 bit API is available
  346.         if ((gpb->bufferProcs->numBufferProcs >= 8) && (gpb->maxSpace64 > 0)) {
  347.                 uint64_t maxSpace64 = gpb->maxSpace64;
  348.  
  349.                 return maxSpace64;
  350.         } else {
  351.                 // Note: If maxSpace gets converted from Int32 to unsigned int, we can reach up to 4 GB RAM. However, after this, there will be a wrap to 0 GB again.
  352.                 unsigned int maxSpace32 = (unsigned int) gpb->maxSpace;
  353.                 uint64_t maxSpace64 = maxSpace32;
  354.  
  355.                 if (gpb->hostSig == HOSTSIG_IRFANVIEW) maxSpace64 *= 1024; // IrfanView is giving Kilobytes instead of Bytes
  356.                 //if (gpb->hostSig == HOSTSIG_SERIF_PHOTOPLUS) maxSpace64 *= 1024; // TODO: Serif PhotoPlus also gives Kilobytes instead of bytes. But since it uses not a unique host signature, there is nothing we can do???
  357.  
  358.                 return maxSpace64;
  359.         }
  360. }
  361.  
  362. Boolean maxspace_available() {
  363.         // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
  364.  
  365.         // GIMP PSPI sets MaxSpace to hardcoded 100 MB
  366.         if (gpb->hostSig == HOSTSIG_GIMP) return false;
  367.  
  368.         // HOSTSIG_PAINT_NET sets MaxSpace to hardcoded 1 GB, see https://github.com/0xC0000054/PSFilterPdn/issues/5
  369.         // Comment by the host author "This was done to avoid any compatibility issues with plugins handling 2 GB - 1"
  370.         if (gpb->hostSig == HOSTSIG_PAINT_NET) return false;
  371.  
  372.         return true;
  373. }
  374.  
  375. void DoPrepare(FilterRecordPtr pb){
  376.         int i;
  377.  
  378.         for(i = 4; i--;){
  379.                 if(expr[i]||tree[i]) DBG("expr[] or tree[] non-NULL in Prepare!");
  380.                 expr[i] = NULL;
  381.                 tree[i] = NULL;
  382.         }
  383.  
  384.         // Commented out by DM, 18 Dec 2018:
  385.         // This code did not work on systems with 8 GB RAM:
  386.         /*
  387.         long space = (pb->maxSpace*9)/10; // don't ask for more than 90% of available memory
  388.  
  389.         maxSpace = 512L<<10; // this is a wild guess, actually
  390.         if(maxSpace > space)
  391.                 maxSpace = space;
  392.         pb->maxSpace = maxSpace;
  393.         */
  394.  
  395.         // New variant:
  396.         if (maxspace_available()) {
  397.                 pb->maxSpace = (int32)ceil((maxspace()/10.)*9); // don't ask for more than 90% of available memory
  398.                 // FIXME: Also maxSpace64
  399.         }
  400. }
  401.  
  402. void RequestNext(FilterRecordPtr pb,long toprow){
  403.         /* Request next block of the image */
  404.  
  405.         pb->inLoPlane = pb->outLoPlane = 0;
  406.         pb->inHiPlane = pb->outHiPlane = nplanes-1;
  407.  
  408.         if (HAS_BIG_DOC(pb)) {
  409.                 // if any of the formulae involve random access to image pixels,
  410.                 // ask for the entire image
  411.                 if (needall) {
  412.                         SETRECT(BIGDOC_IN_RECT(pb), 0, 0, BIGDOC_IMAGE_SIZE(pb).h, BIGDOC_IMAGE_SIZE(pb).v);
  413.                 } else {
  414.                         // TODO: This does not work with GIMP. So, if we are using GIMP, we should
  415.                         //       somehow always use "needall=true", and/or find out why this doesn't work
  416.                         //       with GIMP.
  417.  
  418.                         // otherwise, process the filtered area, by chunksize parts
  419.                         BIGDOC_IN_RECT(pb).left = BIGDOC_FILTER_RECT(pb).left;
  420.                         BIGDOC_IN_RECT(pb).right = BIGDOC_FILTER_RECT(pb).right;
  421.                         BIGDOC_IN_RECT(pb).top = (int32)toprow;
  422.                         BIGDOC_IN_RECT(pb).bottom = (int32)MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
  423.  
  424.                         if (cnvused) {
  425.                                 // cnv() needs one extra pixel in each direction
  426.                                 if (BIGDOC_IN_RECT(pb).left > 0)
  427.                                         --BIGDOC_IN_RECT(pb).left;
  428.                                 if (BIGDOC_IN_RECT(pb).right < BIGDOC_IMAGE_SIZE(pb).h)
  429.                                         ++BIGDOC_IN_RECT(pb).right;
  430.                                 if (BIGDOC_IN_RECT(pb).top > 0)
  431.                                         --BIGDOC_IN_RECT(pb).top;
  432.                                 if (BIGDOC_IN_RECT(pb).bottom < BIGDOC_IMAGE_SIZE(pb).v)
  433.                                         ++BIGDOC_IN_RECT(pb).bottom;
  434.                         }
  435.                 }
  436.                 BIGDOC_OUT_RECT(pb) = BIGDOC_FILTER_RECT(pb);
  437.                 /*
  438.                 {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
  439.                         needall,
  440.                         BIGDOC_IN_RECT(pb).left,BIGDOC_IN_RECT(pb).top,BIGDOC_IN_RECT(pb).right,BIGDOC_IN_RECT(pb).bottom,
  441.                         BIGDOC_FILTER_RECT(pb).left,BIGDOC_FILTER_RECT(pb).top,BIGDOC_FILTER_RECT(pb).right,BIGDOC_FILTER_RECT(pb).bottom);dbg(s);}
  442.                 */
  443.         } else {
  444.                 // if any of the formulae involve random access to image pixels,
  445.                 // ask for the entire image
  446.                 if (needall) {
  447.                         SETRECT(IN_RECT(pb), 0, 0, IMAGE_SIZE(pb).h, IMAGE_SIZE(pb).v);
  448.                 }
  449.                 else {
  450.                         // TODO: This does not work with GIMP. So, if we are using GIMP, we should
  451.                         //       somehow always use "needall=true", and/or find out why this doesn't work
  452.                         //       with GIMP.
  453.  
  454.                         // otherwise, process the filtered area, by chunksize parts
  455.                         IN_RECT(pb).left = FILTER_RECT(pb).left;
  456.                         IN_RECT(pb).right = FILTER_RECT(pb).right;
  457.                         IN_RECT(pb).top = (int16)toprow;
  458.                         IN_RECT(pb).bottom = (int16)MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
  459.  
  460.                         if (cnvused) {
  461.                                 // cnv() needs one extra pixel in each direction
  462.                                 if (IN_RECT(pb).left > 0)
  463.                                         --IN_RECT(pb).left;
  464.                                 if (IN_RECT(pb).right < IMAGE_SIZE(pb).h)
  465.                                         ++IN_RECT(pb).right;
  466.                                 if (IN_RECT(pb).top > 0)
  467.                                         --IN_RECT(pb).top;
  468.                                 if (IN_RECT(pb).bottom < IMAGE_SIZE(pb).v)
  469.                                         ++IN_RECT(pb).bottom;
  470.                         }
  471.                 }
  472.                 OUT_RECT(pb) = FILTER_RECT(pb);
  473.                 /*
  474.                 {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
  475.                         needall,
  476.                         IN_RECT(pb).left,IN_RECT(pb).top,IN_RECT(pb).right,IN_RECT(pb).bottom,
  477.                         FILTER_RECT(pb).left,FILTER_RECT(pb).top,FILTER_RECT(pb).right,FILTER_RECT(pb).bottom);dbg(s);}
  478.                 */
  479.         }
  480. }
  481.  
  482. void DoStart(FilterRecordPtr pb){
  483. //dbg("DoStart");
  484.         /* if src() or rad() functions are used, random access to the image data is required,
  485.            so we must request the entire image in a single chunk. */
  486.         if (HAS_BIG_DOC(pb)) {
  487.                 chunksize = needall ? (BIGDOC_FILTER_RECT(pb).bottom - BIGDOC_FILTER_RECT(pb).top) : CHUNK_ROWS;
  488.                 toprow = BIGDOC_FILTER_RECT(pb).top;
  489.         } else {
  490.                 chunksize = needall ? (FILTER_RECT(pb).bottom - FILTER_RECT(pb).top) : CHUNK_ROWS;
  491.                 toprow = FILTER_RECT(pb).top;
  492.         }
  493.         RequestNext(pb, toprow);
  494. }
  495.  
  496. OSErr DoContinue(FilterRecordPtr pb){
  497.         OSErr e = noErr;
  498.         long outoffset;
  499.  
  500.         if (HAS_BIG_DOC(pb)) {
  501.                 VRect fr;
  502.                 if (needall) {
  503.                         fr = BIGDOC_FILTER_RECT(pb);  // filter whole selection at once
  504.                 } else if (cnvused) {
  505.                         // we've requested one pixel extra all around
  506.                         // (see RequestNext()), just for access purposes. But filter
  507.                         // original selection only.
  508.                         fr.left = BIGDOC_FILTER_RECT(pb).left;
  509.                         fr.right = BIGDOC_FILTER_RECT(pb).right;
  510.                         fr.top = toprow;
  511.                         fr.bottom = MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
  512.                 } else {  // filter whatever portion we've been given
  513.                         fr = BIGDOC_IN_RECT(pb);
  514.                 }
  515.  
  516.                 outoffset = (long)pb->outRowBytes * (fr.top - BIGDOC_OUT_RECT(pb).top)
  517.                         + (long)nplanes * (fr.left - BIGDOC_OUT_RECT(pb).left);
  518.  
  519.                 if (!(e = process_scaled_bigdoc(pb, true, fr, fr,
  520.                         (Ptr)pb->outData + outoffset, pb->outRowBytes, 1.)))
  521.                 {
  522.                         toprow += chunksize;
  523.                         if (toprow < BIGDOC_FILTER_RECT(pb).bottom)
  524.                                 RequestNext(pb, toprow);
  525.                         else {
  526.                                 SETRECT(BIGDOC_IN_RECT(pb), 0, 0, 0, 0);
  527.                                 BIGDOC_OUT_RECT(pb) = BIGDOC_MASK_RECT(pb) = BIGDOC_IN_RECT(pb);
  528.                         }
  529.                 }
  530.         } else {
  531.                 Rect fr;
  532.                 if (needall) {
  533.                         fr = FILTER_RECT(pb);  // filter whole selection at once
  534.                 } else if (cnvused) {
  535.                         // we've requested one pixel extra all around
  536.                         // (see RequestNext()), just for access purposes. But filter
  537.                         // original selection only.
  538.                         fr.left = FILTER_RECT(pb).left;
  539.                         fr.right = FILTER_RECT(pb).right;
  540.                         fr.top = toprow;
  541.                         fr.bottom = MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
  542.                 } else {  // filter whatever portion we've been given
  543.                         fr = IN_RECT(pb);
  544.                 }
  545.  
  546.                 outoffset = (long)pb->outRowBytes*(fr.top - OUT_RECT(pb).top)
  547.                                         + (long)nplanes*(fr.left - OUT_RECT(pb).left);
  548.  
  549.                 if(!(e = process_scaled_olddoc(pb, true, fr, fr,
  550.                                         (Ptr)pb->outData+outoffset, pb->outRowBytes, 1.)))
  551.                 {
  552.                         toprow += chunksize;
  553.                         if(toprow < FILTER_RECT(pb).bottom)
  554.                                 RequestNext(pb,toprow);
  555.                         else{
  556.                                 SETRECT(IN_RECT(pb),0,0,0,0);
  557.                                 OUT_RECT(pb) = MASK_RECT(pb) = IN_RECT(pb);
  558.                         }
  559.                 }
  560.         }
  561.         return e;
  562. }
  563.  
  564. void DoFinish(FilterRecordPtr pb){
  565.         int i;
  566.  
  567.         WriteScriptParamsOnRead();
  568.  
  569.         for(i = 4; i--;){
  570.                 freetree(tree[i]);
  571.                 if(expr[i]) free(expr[i]);
  572.         }
  573. }
  574.