Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtHelp / il / ilpipe.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: ilpipe.c /main/6 1996/06/19 12:21:13 ageorge $ */
24 /**---------------------------------------------------------------------
25 ***     
26 ***    (c)Copyright 1991 Hewlett-Packard Co.
27 ***    
28 ***                             RESTRICTED RIGHTS LEGEND
29 ***    Use, duplication, or disclosure by the U.S. Government is subject to
30 ***    restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
31 ***    Technical Data and Computer Software clause in DFARS 252.227-7013.
32 ***                             Hewlett-Packard Company
33 ***                             3000 Hanover Street
34 ***                             Palo Alto, CA 94304 U.S.A.
35 ***    Rights for non-DOD U.S. Government Departments and Agencies are as set
36 ***    forth in FAR 52.227-19(c)(1,2).
37 ***
38 ***-------------------------------------------------------------------*/
39
40         /*  /ilc/ilpipe.c : General pipe handling code.
41             Also contains ilCrop() as this function is very much tied to the 
42             implementation of pipes.
43         */
44
45 #include "ilint.h"
46 #include "ilimage.h"
47 #include "ilpipelem.h"
48 #include "ilpipeint.h"
49 #include "ilerrors.h"
50
51     /*  One element in the pipe, added by ilAddElement().  Notes:
52
53             pNext, pPrev    forward/back ptrs to next/prev element in list.  First element
54                             in list is *ilPipePtr->elementHead.pNext; last is *pPrev. 
55
56             elementType     One of: IL_PRODUCER, IL_FILTER, IL_CONSUMER.  Not needed or
57                             used, but very handy for debugging.
58
59             flags           flag values, e.g. IL_ADD_PIPE_NO_DST
60
61             exec            par block to Execute() for this element: ptrs to src/dst image
62                             src/dst lines to read.
63
64             Init()
65             Cleanup()
66             Destroy()
67             Execute()       functions passed to ilAddPipeElement(); see spec for details
68
69             clientPrivate   start of client's private area; MUST BE LAST
70     */
71 typedef struct _ilElementRec {
72     struct _ilElementRec *pNext, *pPrev;
73     unsigned int        elementType;
74     unsigned long       flags;
75     ilExecuteData       exec;
76     ilError           (*Init)();
77     ilError           (*Cleanup)();
78     ilError           (*Destroy)();
79     ilError           (*ExecuteThree)();
80     ilError           (*ExecuteFour)(register ilExecuteData *,
81                                      long,
82                                      long *,
83                                      float);
84     unsigned long       clientPrivate;          /* client private: MUST BE LAST */
85     } ilElementRec, *ilElementPtr;
86
87
88     /*  Actual contents of a ilPipe.   Notes:
89
90             o               std object header: MUST BE FIRST
91
92             state           current state of the pipe as returned by ilGetPipeInfo(); one
93                             of:
94
95                 IL_PIPE_INVALID     an error occurred in forming the pipe, and the pipe 
96                                     cannot be used until ilEmptyPipe() is done.  No more 
97                                     elements should be added.  The pipe is in fact empty,
98                                     only the state is different, to prevent other elements
99                                     from being added.  This state is set by calling 
100                                     ilDeclarePipeInvalid().
101
102                 IL_PIPE_EMPTY       pipe is empty; ready to add a producer (read)
103
104                 IL_PIPE_FORMING     pipe has a producer and zero or more filters; ready to
105                                     add filters or a consumer (write)
106
107                 IL_PIPE_COMPLETE    pipe has a consumer (write); ilExecutePipe() can now
108                                     be called on it (executable, from caller's view).  
109                                     Error if an attempt to add an element.
110
111                 IL_PIPE_EXECUTING   one or more, but not all, strips have been processed.
112
113             producerCode    code that defines producer; one of:
114                 
115                 IL_PIPE_NOT_IMAGE   the producer was not an image
116                 IL_PIPE_IMAGE       producer was an ilReadImage() call
117                 IL_PIPE_FEED_IMAGE  producer was an ilFeedFromImage() call
118             
119             feedStartLine
120             feedNLines      
121             feedCompOffset
122             feedCompNBytes
123             feedDone        used only if producerCode == IL_PIPE_FEED_IMAGE: values
124                             passed to / used by ilSetFeedPipeData()
125
126             elementHead     head/tail of list of ilElementRec, the elements in the pipe
127
128             hookHead        head/tail of list of IL_HOOK ilElementRec, the pseudo-elements
129                             in the pipe of type "hook" - not in elementHead list.
130
131             stackIndex      index of top of "execStack"; see below.
132
133             execStack       stack of ptrs to elements that returned IL_ERROR_ELEMENT_AGAIN
134                             "stackIndex" points to the top of stack. [0] contains the
135                             first element in the list.
136
137             nDestroyObjects # of elements in "destroyObjects" array; see below.
138
139             destroyObjects  an array of "nDestroyObjects" objects which must be destroyed
140                             (by calling ilDestroyObject()) when the pipe is emptied.  This
141                             array is added to by calling ilAddPipeDestroyObject().
142
143             lastStrip       inited to false when pipe started, set true when "last strip"
144                             error returned from an element.  Pipe execution is complete
145                             when lastStrip && stackIndex <= 0 (> 0 => last strip has still
146                             not made it all the way through the pipe).
147
148             needProducerThrottle true iff ilAddProducerImage() just called: pipe began
149                             with an ilReadImage() and no filters added yet.
150
151             copyToConsumerImage  true iff a copy filter must be inserted if the next
152                             element is a consumer, specifying a consumerImage, e.g.
153                             is ilWriteImage().  This would be true right after 
154                             ilAddProducerImage() is called, or right after any 
155                             IL_ADD_PIPE_NO_DST filter.
156
157             imageHead       head/tail of list of ilImageRec, the temporary images 
158                             associated with this pipe.  The images object prev/next ptrs
159                             are used to maintain this list.  Note that the images in this
160                             list are not official objects; they must be deleted when then
161                             the pipe is emptied.  The images have buffers only when state
162                             is IL_PIPE_EXECUTING; the list is null when state is IL_PIPE
163                             INVALID or EMPTY.
164
165             pSrcPipeImage   if non-null, points the source (input) pipe image to the next
166                             element to be added.  If null, must allocate a src image for
167                             the next element unless it is a ilWriteImage().
168
169             image           describes the current pipe image.  The values in this struct
170                             meaningful only if pipe forming (state == IL_PIPE_FORMING).
171                             The fields are as returned by ilGetPipeInfo().
172     */
173
174 #define IL_MAX_EXEC_STACK      100
175 #define IL_MAX_DESTROY_OBJECTS  10
176
177 typedef struct {
178     ilObjectRec         o;                  /* std header: MUST BE FIRST */
179     unsigned int        state;
180     unsigned int        producerCode;
181     long                feedStartLine, feedNLines, feedCompOffset, feedCompNBytes;
182     ilBool              feedDone;
183     ilElementRec        elementHead;
184     ilElementRec        hookHead;
185     int                 stackIndex;
186     ilElementPtr        execStack [IL_MAX_EXEC_STACK];
187     int                 nDestroyObjects;
188     ilObject            destroyObjects [IL_MAX_DESTROY_OBJECTS];
189     ilBool              lastStrip;
190     ilBool              needProducerThrottle;
191     ilBool              copyToConsumerImage;
192     ilObjectRec         imageHead;
193     ilImageInfo        *pSrcPipeImage;
194     struct {
195         ilPipeInfo      info;
196         ilImageDes      des;
197         ilImageFormat   format;
198         } image;
199     } ilPipeRec, *ilPipePtr;
200
201
202     /*  Default optimal strip size, in bytes.  Used by ilRecommendedStripHeight().
203             NOTE: currently the same as TIFF strip size, "IL_WRITE_TIFF_STRIP_SIZE" in
204         /ilc/iltiffwrite.c .  The two are not directly coupled, but making them different
205         may adversely affect performance, e.g. cause de/recompression!
206     */
207 static long ilDefaultStripSize = (16 * 1024);
208
209         /*  ------------------------ _ilSetDefaultStripSize  ------------------------ */
210         /*  "Back door" call to set ilDefaultStripSize.  The IL test suite uses this 
211              call to ensure that small images are stripped, and so that strip
212              size is consistent between test baselevels.
213         */
214 void _ilSetDefaultStripSize (
215     long                stripSize
216     )
217 {
218     ilDefaultStripSize = stripSize;
219 }
220
221
222         /*  ------------------------ ilFreeTempImageBuffers ------------------------ */
223         /*  Free the buffers associated with the temp images of this pipe.  The image
224             structures are not freed; just the pixels.
225         */
226 static void ilFreeTempImageBuffers (
227     register ilPipePtr  pPipe
228     )
229 {
230 register ilImagePtr     pImage;
231
232     pImage = (ilImagePtr)pPipe->imageHead.pNext;
233     while (pImage != (ilImagePtr)&pPipe->imageHead) {
234         _ilFreeImagePixels (pImage);
235         pImage = (ilImagePtr)pImage->o.pNext;
236         }
237 }
238
239         /*  -------------------------- ilAllocTempImage ----------------------- */
240         /*  Allocates a temporary (buffer) image, inits it and returns a ptr to it or
241             null if failure.  The buffer for the pixels is not allocated.  The 
242             height of the image is not set; the caller must do that.
243         */
244 static ilImagePtr ilAllocTempImage (
245     register ilPipePtr      pPipe,
246     ilPipeInfo             *pInfo,
247     ilImageDes             *pDes,
248     ilImageFormat          *pFormat
249     )
250 {
251 register ilImagePtr         pImage;
252
253     pImage = (ilImagePtr)IL_MALLOC (sizeof (ilImageRec));
254     if (!pImage)
255         return (ilImagePtr)NULL;                            /* EXIT */
256
257     pImage->des = *pDes;
258     pImage->format = *pFormat;
259     pImage->pStripOffsets = (long *)NULL;   /* freed if non-null */
260
261     pImage->i.pDes = &pImage->des;
262     pImage->i.pFormat = &pImage->format;
263     pImage->i.width = pInfo->width;
264     pImage->i.height = 0;
265
266         /*  Set clientPixels/Palette/CompData true so they are *not* deallocated */
267     pImage->i.clientPixels = TRUE;
268     pImage->i.clientPalette = TRUE;
269     pImage->i.clientCompData = TRUE;
270     pImage->i.pPalette = pInfo->pPalette;
271     pImage->i.pCompData = pInfo->pCompData;
272
273         /*  Link image into list of temp images, using object pPrev/pNext ptrs.
274         */
275     pImage->o.pNext = pPipe->imageHead.pNext;
276     pImage->o.pPrev = (ilPtr)&pPipe->imageHead;
277     ((ilImagePtr)pPipe->imageHead.pNext)->o.pPrev = (ilPtr)pImage;
278     pPipe->imageHead.pNext = (ilPtr)pImage;
279
280     return pImage;
281 }
282
283
284         /*  ------------------------ ilCleanupRunningPipe ----------------------------- */
285         /*  Cleanup a pipe which had been running, i.e. its state was IL_PIPE_EXECUTING.
286             "aborting" should be TRUE if the pipe is being aborted (was not finished).
287             The pipe state is set to IL_PIPE_COMPLETE.
288         */
289 static ilError ilCleanupRunningPipe (
290     register ilPipePtr  pPipe,
291     ilBool              aborting
292     )
293 {
294 register ilElementPtr   pElement, pElementHead;
295 ilError                 error, prevError;
296
297         /*  Run thru the list of elements and call Cleanup function if non-null, then
298             do same for "hook" list.  Pass given aborting flag to Cleanup().
299             If an error return, switch to "aborting" mode and return first error returned.
300         */
301     prevError = IL_OK;
302     pElementHead = &pPipe->elementHead;
303     while (TRUE) {
304         pElement = pElementHead->pNext;
305         while (pElement != pElementHead) {
306             if (pElement->Cleanup) {
307                 error = (*pElement->Cleanup) ((ilPtr)pElement->exec.pPrivate, aborting);
308                 if (error) {
309                     if (prevError == IL_OK)
310                         prevError = error;
311                     aborting = TRUE;                    /* error; now considered aborted */
312                     }
313                 }
314             pElement = pElement->pNext;
315             }
316         if (pElementHead == &pPipe->hookHead)
317             break;                                      /* both lists scanned; done */
318         pElementHead = &pPipe->hookHead;                /* run thru hook list */
319         }
320
321     ilFreeTempImageBuffers (pPipe);
322     pPipe->stackIndex = 0;
323     pPipe->state = IL_PIPE_COMPLETE;
324     return prevError;
325 }
326
327
328         /*  ------------------------ ilEmptyPipe -------------------------------- */
329         /*  Public function: see spec.
330             Also called locally, for example when aborting a pipe.
331         */
332 ilBool ilEmptyPipe (
333     ilPipe              pipe
334     )
335 {
336 register ilPipePtr      pPipe;
337 register ilElementPtr   pElement, pNextElement, pElementHead;
338 register ilImagePtr     pImage, pNextImage;
339 int                     i;
340 ilError                 error;
341
342     pPipe = (ilPipePtr)pipe;
343     if (pPipe->o.p.objectType != IL_PIPE) {
344         pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
345         return FALSE;
346         }
347
348         /*  Action to empty a pipe depends on current state.  Transition from running
349             (abort) to complete (empty element list) to invalid (mark as empty).
350             FALL THRU (no break) from each state.
351         */
352     error = IL_OK;                  /* assume no error; log error from Cleanup() */
353     switch (pPipe->state) {
354       case IL_PIPE_EXECUTING:       /* executing: must abort, fall thru to complete */
355         error = ilCleanupRunningPipe (pPipe, TRUE);
356
357       case IL_PIPE_COMPLETE:        /* elements but no buffers allocated */
358       case IL_PIPE_FORMING:         /* forming is same as complete */
359
360             /*  Run thru list of elements and free them.  Call optional Destroy 
361                 function if non-null.  Make list head empty.
362             */
363         pElementHead = &pPipe->elementHead;
364         while (TRUE) {
365             pElement = pElementHead->pNext;
366             while (pElement != pElementHead) {
367                 if (pElement->Destroy)
368                     (*pElement->Destroy) ((ilPtr)pElement->exec.pPrivate);
369                 pNextElement = pElement->pNext;
370                 IL_FREE (pElement);
371                 pElement = pNextElement;
372                 }
373             if (pElementHead == &pPipe->hookHead)
374                 break;                                      /* both lists scanned; done */
375             pElementHead = &pPipe->hookHead;                /* run thru hook list */
376             }
377         pPipe->elementHead.pNext = pPipe->elementHead.pPrev = &pPipe->elementHead;
378         pPipe->hookHead.pNext = pPipe->hookHead.pPrev = &pPipe->hookHead;
379
380             /*  Destroy all temp images associated with this pipe.  The buffers are
381                 already gone, because they only exist when state is IL_PIPE_EXECUTING,
382                 and ilCleanupRunningPipe() would be called in that case.
383             */
384         pImage = (ilImagePtr)pPipe->imageHead.pNext;
385         while (pImage != (ilImagePtr)&pPipe->imageHead) {
386             pNextImage = (ilImagePtr)pImage->o.pNext;
387             IL_FREE (pImage);
388             pImage = pNextImage;
389             }
390         pPipe->imageHead.pNext = pPipe->imageHead.pPrev = (ilPtr)&pPipe->imageHead;
391
392             /*  Destroy all objects in destroyObjects array. */
393         for (i = 0; i < pPipe->nDestroyObjects; i++)
394             ilDestroyObject (pPipe->destroyObjects[i]);
395         pPipe->nDestroyObjects = 0;
396
397       case IL_PIPE_INVALID:         /* pipe already empty; change state */
398         pPipe->state = IL_PIPE_EMPTY;
399
400       case IL_PIPE_EMPTY:           /* pipe in desired state */
401         break;
402         }
403
404     pPipe->o.p.context->error = error;
405     return (error == IL_OK);
406 }
407
408
409
410         /*  ------------------------ ilCreatePipe -------------------------------- */
411         /*  Public function: see spec.
412         */
413
414 ilPipe ilCreatePipe (
415     ilContext           context,
416     unsigned long       mustBeZero
417     )
418 {
419 register ilPipePtr   pPipe;
420
421     if (mustBeZero != 0) {
422         context->error = IL_ERROR_PAR_NOT_ZERO;
423         return (ilPipe)NULL;
424         }
425
426     pPipe = (ilPipePtr)_ilCreateObject (context, IL_PIPE, ((void (*)())ilEmptyPipe), 
427                                        sizeof (ilPipeRec));
428     if (!pPipe)
429         return (ilPipe)NULL;
430
431         /*  Declare pipe empty, set element and temp image lists to empty state.
432             The rest of the pipe state must be set by ilAddPipeElement() on each element.
433                 Init some of elementHead, which itself is an element, and will be
434             referenced as the current element in a pipe with no elements.
435         */
436     pPipe->state = IL_PIPE_EMPTY;
437     pPipe->elementHead.pNext = pPipe->elementHead.pPrev = &pPipe->elementHead;
438     pPipe->hookHead.pNext = pPipe->hookHead.pPrev = &pPipe->hookHead;
439     pPipe->imageHead.pNext = pPipe->imageHead.pPrev = (ilPtr)&pPipe->imageHead;
440     pPipe->elementHead.flags = 0;
441     pPipe->stackIndex = 0;
442     pPipe->nDestroyObjects = 0;
443     pPipe->image.info.stripHeight = 0;
444
445     context->error = IL_OK;
446     return (ilPipe)pPipe;
447 }
448
449
450         /*  ------------------------ ilDeclarePipeInvalid ----------------------------- */
451         /*  Public function; see spec.
452             Empties the pipe, sets state to invalid and posts given error.
453             FALSE is always returned, to allow the following:
454                if (<something wrong while forming pipe>)
455                    return ilDeclarePipeInvalid (pipe, errorCode);
456         */
457 ilBool ilDeclarePipeInvalid (
458     ilPipe              pipe,
459     ilError             error
460     )
461 {
462 register ilPipePtr   pPipe;
463
464     pPipe = (ilPipePtr)pipe;
465     ilEmptyPipe ((ilPipe)pPipe);
466     if (pPipe->o.p.objectType == IL_PIPE)
467         pPipe->state = IL_PIPE_INVALID;
468     pPipe->o.p.context->error = error;
469     return FALSE;
470 }
471
472         
473         /*  ------------------------ ilQueryPipe  ----------------------------- */
474         /*  Public function; see spec.
475             Return description of current image, from pipe header, if pipe forming.
476         */
477 unsigned int ilQueryPipe (
478     ilPipe              pipe,
479     long               *pWidth,                 /* RETURNED */
480     long               *pHeight,                /* RETURNED */
481     ilImageDes         *pDes                    /* RETURNED */
482     )
483 {
484 register ilPipePtr   pPipe;
485
486     pPipe = (ilPipePtr)pipe;
487     if (pPipe->o.p.objectType != IL_PIPE) {
488         pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
489         return IL_PIPE_INVALID;                 /* return phony state because of error */
490         }
491
492     if (pPipe->state == IL_PIPE_FORMING) {
493         if (pWidth)
494             *pWidth = pPipe->image.info.width;
495         if (pHeight)
496             *pHeight = pPipe->image.info.height;
497         if (pDes)
498             *pDes = pPipe->image.des;
499         }
500
501     pPipe->o.p.context->error = IL_OK;
502     return pPipe->state;
503 }
504
505
506         /*  ------------------------ ilGetPipeInfo ----------------------------- */
507         /*  Public function; see spec.
508             If pipe state is "forming": if "forceDecompress" and image is compressed, make 
509             it uncompressed, then return description of current pipe state.
510         */
511 unsigned int ilGetPipeInfo (
512     ilPipe              pipe,
513     ilBool              forceDecompress,
514     ilPipeInfo         *pInfo,
515     ilImageDes         *pDes,
516     ilImageFormat      *pFormat
517     )
518 {
519 register ilPipePtr   pPipe;
520
521     pPipe = (ilPipePtr)pipe;
522     if (pPipe->o.p.objectType != IL_PIPE) {
523         pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
524         return IL_PIPE_INVALID;                             /* EXIT w/ pseudo-error */
525         }
526     if (pPipe->state == IL_PIPE_FORMING) {
527
528             /*  Decompress image if it is compressed and caller asked for decompressed.
529             */
530         if (forceDecompress && (pPipe->image.des.compression != IL_UNCOMPRESSED)) {
531             _ilDecompress ((ilPipe)pPipe);
532             if (pPipe->o.p.context->error)
533                 return IL_PIPE_INVALID;                     /* EXIT w/ pseudo-error */
534             }
535
536         if (pInfo)
537             *pInfo = pPipe->image.info;
538         if (pDes)
539             *pDes = pPipe->image.des;
540         if (pFormat)
541             *pFormat = pPipe->image.format;
542         }
543
544     pPipe->o.p.context->error = IL_OK;
545     return pPipe->state;
546 }
547
548
549         /*  ----------------------- ilRecommendedStripHeight ------------------------ */
550         /*  Public function; see spec.
551         */
552 long ilRecommendedStripHeight (
553     const ilImageDes         *pDes,
554     const ilImageFormat      *pFormat,
555     long                width,
556     long                height
557     )
558 {
559 long                    bytesPerRow [IL_MAX_SAMPLES];
560 register long           stripHeight, nBytes;
561 int                     i;
562
563         /*  Get the bytes/row, per plane.  If pixel format, all bytes are in plane 0,
564             else in pDes->nSamplesPerPixel planes.
565         */
566     if (height <= 0)
567         stripHeight = 0;
568     else {
569         ilGetBytesPerRow (pDes, pFormat, width, bytesPerRow);
570         if (pFormat->sampleOrder == IL_SAMPLE_PIXELS)
571             nBytes = bytesPerRow[0];            /* all bytes in one plane */
572         else {
573             nBytes = 0;
574             for (i = 0; i < pDes->nSamplesPerPixel; i++)
575                 nBytes += bytesPerRow[i];
576             }
577         if (nBytes <= 0)
578             stripHeight = 1;
579         else {
580             stripHeight = ilDefaultStripSize / nBytes;
581             if (stripHeight > height)
582                 stripHeight = height;
583             if (stripHeight <= 0)
584                 stripHeight = 1;
585             }
586         }
587     return stripHeight;
588 }
589
590
591         /*  ----------------------- ilChangeStripHeight ------------------------ */
592         /*  Calcs the recommended strip height, in ilPipeInfo for the pipe.
593             Should be called whenever the pipe stripHeight is changed, after the
594             pipe height is changed (limits stripHeight to image height).
595         */
596 static void ilChangeStripHeight (
597     register ilPipePtr  pPipe
598     )
599 {
600 register long           stripHeight;
601
602         /*  Limit stripHeight to pipe height. */
603     stripHeight = pPipe->image.info.stripHeight;
604     if (stripHeight > pPipe->image.info.height) 
605         pPipe->image.info.stripHeight = stripHeight = pPipe->image.info.height;
606     else if (stripHeight <= 0)
607         pPipe->image.info.stripHeight = stripHeight = 1;
608
609         /*  If uncompressed image, calc recommendedStripHeight else current stripHeight */
610     if (pPipe->image.des.compression == IL_UNCOMPRESSED) {
611         register long   i;
612         i = ilRecommendedStripHeight (&pPipe->image.des, &pPipe->image.format, 
613                                       pPipe->image.info.width, pPipe->image.info.height);
614         pPipe->image.info.recommendedStripHeight = (i > stripHeight) ? stripHeight : i;
615         }
616     else pPipe->image.info.recommendedStripHeight = stripHeight;
617 }
618
619
620         /*  ------------------------ ilAddPipeDestroyObject ------------------------ */
621         /*  IL internal function, declared in /ilc/ilpipeint.h .
622             Add the given object to a list of objects to be destroyed when this pipe
623             is emptied.  The object's refCount should be inc'd before this call, so that
624             the object cannot be freed until this pipe is destroyed.
625             The pipe must be in the forming or complete state.
626             NOTE: a hard limit exists on the # of objects which can be added; not intended
627             for unlimited use, e.g. by filters!
628             Sets context->error to error code, returns true if success.
629         */
630 IL_PRIVATE ilBool _ilAddPipeDestroyObject (
631     ilPipe              pipe,
632     ilObject            object
633     )
634 {
635 register ilPipePtr      pPipe;
636
637     pPipe = (ilPipePtr)pipe;
638     if (pPipe->nDestroyObjects >= IL_MAX_DESTROY_OBJECTS) {
639         pipe->context->error = IL_ERROR_MALLOC;     /* should not happen, return phony */
640         return FALSE;
641         }
642     pPipe->destroyObjects[pPipe->nDestroyObjects] = object;
643     pPipe->nDestroyObjects++;
644     pipe->context->error = IL_OK;
645     return TRUE;
646 }
647
648
649         /*  ---------------------------- ilAddProducerImage ------------------------ */
650         /*  IL internal function, declared in /ilc/ilpipeint.h .
651             Called by ilReadImage() to set *pImage as the producer to this pipe. 
652             The pipe MUST be in the empty state.  "needProducerThrottle" is true iff a 
653             throttle must be inserted before next element added by ilAddPipeElement().
654         */
655 IL_PRIVATE ilBool _ilAddProducerImage (
656     ilPipe              pipe,
657     register ilImagePtr pImage,
658     unsigned int        producerCode,
659     long                height,
660     long                stripHeight,
661     ilBool              constantStrip,
662     ilBool              needProducerThrottle
663     )
664 {
665 register ilPipePtr      pPipe;
666
667         /*  Copy image data into pipe info, point to given image as producer. */
668     pPipe = (ilPipePtr)pipe;
669     pPipe->producerCode = producerCode;
670     pPipe->image.des = pImage->des;
671     pPipe->image.format = pImage->format;
672     pPipe->image.info.producerObject = (ilObject)pImage;
673     pPipe->image.info.tempImage = FALSE;
674     pPipe->image.info.width = pImage->i.width;
675     pPipe->image.info.height = height;
676     pPipe->image.info.constantStrip = constantStrip;
677     pPipe->image.info.stripHeight = stripHeight;
678     ilChangeStripHeight (pPipe);
679
680     pPipe->image.info.producerObject = (ilObject)pImage;
681     pPipe->image.info.pPalette = pImage->i.pPalette;        /* point to image palette */
682     pPipe->image.info.pCompData = pImage->i.pCompData;      /* point to comp data */
683     pPipe->pSrcPipeImage = &pImage->i;
684     pPipe->state = IL_PIPE_FORMING;
685     pPipe->feedDone = FALSE;            /* ilSetFeedPipeData not done yet. */
686
687         /*  Signal ilAddPipeElement() to add a throttle before next filter is added,
688             and that a copy filter must be added if ilWriteImage() is called next.
689         */
690     pPipe->needProducerThrottle = needProducerThrottle;
691     pPipe->copyToConsumerImage = TRUE;
692
693         /*  Inc pImage->refCount, and add as destroyObject for when pipe destroyed. */
694     pImage->o.refCount++;
695     return _ilAddPipeDestroyObject ((ilPipe)pPipe, (ilObject)pImage);
696 }
697
698
699         /*  ------------------------ ilSetFeedPipeData ------------------------------- */
700         /*  Called by ilFeedPipe() to set info for the first element in the given pipe,
701             which will be ilFeedProducerThrottleExecute().  If feeding compressed data:
702             "start" is the byte offset into the compressed data, and "nCompBytes" is
703             the number of bytes at that offset.  If uncompressed data: "start" is the
704             starting line, and "nCompBytes" is ignored.  Returns FALSE if the pipe was 
705             not started with a ilFeedFromImage() producer.
706         */
707 IL_PRIVATE ilBool _ilSetFeedPipeData (
708     ilPipe              pipe,
709     long                start,
710     long                nLines,
711     long                nCompBytes
712     )
713 {
714 register ilPipePtr      pPipe;
715 register ilImagePtr     pImage;
716
717     pPipe = (ilPipePtr)pipe;
718     if (pPipe->producerCode != IL_PIPE_FEED_IMAGE)
719         return FALSE;
720
721         /*  If uncompressed image, starting line plus # lines must be <= height, and
722             "start" is starting line; if compressed "start" is starting byte offset.
723         */
724     pImage = (ilImagePtr)pPipe->image.info.producerObject;
725     if (pImage->des.compression == IL_UNCOMPRESSED) {
726         if ((start + nLines) > pImage->i.height)
727             return FALSE;
728         pPipe->feedStartLine = start;
729         pPipe->feedCompNBytes = 0;
730         pPipe->feedCompOffset = 0;
731         }
732     else {
733         pPipe->feedStartLine = 0;
734         pPipe->feedCompOffset = start;
735         pPipe->feedCompNBytes = nCompBytes;
736         }
737     pPipe->feedNLines = nLines;
738     pPipe->feedDone = TRUE;                     /* pipe now fed */
739     return TRUE;
740 }
741
742
743         /*  ------------------------ ilSetPipeDesFormat ------------------------------- */
744         /*  IL internal function, declared in /ilc/ilpipeint.h .
745             Called by ilConvert() to "typecast" the pipe image to the given des and/or
746             format (ignored if pDes/pFormat null).  No validation is done on the result!
747         */
748 IL_PRIVATE void _ilSetPipeDesFormat (
749     ilPipe              pipe,
750     ilImageDes         *pDes,
751     ilImageFormat      *pFormat
752     )
753 {
754 register ilPipePtr      pPipe;
755
756     pPipe = (ilPipePtr)pipe;
757     if (pDes)
758         pPipe->image.des = *pDes;
759     if (pFormat)
760         pPipe->image.format = *pFormat;
761 }
762
763
764         /*  ------------------------ ilAddPipeElement ------------------------------- */
765         /*  Public function: see spec.
766             Add a pipe element if correct state.
767         */
768 ilPtr ilAddPipeElement (
769     ilPipe              pipe,
770     int                 elementType,
771 /* Use portable type for sizeof() operator, bug report OSF_QAR# 32082 */
772     size_t              nBytesPrivate,
773     unsigned long       flags,
774     ilSrcElementData   *pSrcData,
775     ilDstElementData   *pDstData,
776     ilError           (*Init)(),
777     ilError           (*Cleanup)(),
778     ilError           (*Destroy)(),
779 /*
780 ** Added another execute function for passing in a fourth
781 ** parameter which is a floating pointing.
782 */
783     ilError           (*ExecuteThree)(),
784     ilError           (*ExecuteFour)(register ilExecuteData *,
785                                               long,
786                                               long *,
787                                               float),
788     unsigned long       mustBeZero
789     )
790 {
791 register ilPipePtr      pPipe;
792 unsigned int            newState;           /* pipe state after this element added */
793 register ilElementPtr   pElement;           /* ptr to new element to add to list */
794 ilElementPtr            pPrevElement;
795 ilError                 error;
796 long                    stripHeight, srcBufferHeight;
797 ilBool                  constantStrip, haveConsumerImage, insertCopyFilter;
798
799     stripHeight = 0; /* initializing the stripHeight variable */
800     pPipe = (ilPipePtr)pipe;
801     if (pPipe->o.p.objectType != IL_PIPE) {
802         pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
803         return (ilPtr)NULL;                                 /* EXIT */
804         }
805     if (mustBeZero != 0) {
806         ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PAR_NOT_ZERO);
807         return (ilPtr)NULL;
808         }
809
810         /*  Validate elementType and pipe state: "empty" for producer, else "forming".
811             Set newState to state pipe becomes after this element is added.
812             If a "hook" element, add hook element and EXIT.
813                 For filters and consumers: set stripHeight to source (input) strip height
814             required by this element; set constantStrip true if every strip (except last)
815             must be stripHeight lines high.  Default if !pSrcData or stripHeight == 0:
816             !constantStrip; filters: recommended strip height; consumers: whole strip.
817                 Set some flags, explained when used below.
818         */
819     haveConsumerImage = FALSE;
820     insertCopyFilter = FALSE;
821
822     switch (elementType) {
823
824         case IL_PRODUCER:
825             if (pPipe->state != IL_PIPE_EMPTY) {
826                 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PIPE_STATE);
827                 return (ilPtr)NULL;
828                 }
829             newState = IL_PIPE_FORMING;
830             break;
831
832         case IL_FILTER:
833             if (pPipe->state != IL_PIPE_FORMING) {
834                 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PIPE_STATE);
835                 return (ilPtr)NULL;
836                 }
837             newState = IL_PIPE_FORMING;
838             if (pSrcData && (pSrcData->minBufferHeight > 0))
839                 insertCopyFilter = pPipe->copyToConsumerImage;
840             if (!pSrcData || !pSrcData->stripHeight) {
841                 stripHeight = pPipe->image.info.recommendedStripHeight;
842                 constantStrip = FALSE;
843                 }
844             else  {
845                 stripHeight = pSrcData->stripHeight;
846                 constantStrip = pSrcData->constantStrip;
847                 }
848             break;
849
850         case IL_CONSUMER:
851             if (pPipe->state != IL_PIPE_FORMING) {
852                 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PIPE_STATE);
853                 return (ilPtr)NULL;
854                 }
855             newState = IL_PIPE_COMPLETE;
856             if (pSrcData) {
857                 if (pSrcData->consumerImage) {
858                     haveConsumerImage = TRUE;
859                     insertCopyFilter = pPipe->copyToConsumerImage;
860                     }
861                 else if (pSrcData->minBufferHeight > 0)
862                     insertCopyFilter = pPipe->copyToConsumerImage;
863                 }
864             if (!pSrcData || !pSrcData->stripHeight) {
865                 stripHeight = pPipe->image.info.stripHeight;  /* accept strip height */
866                 constantStrip = FALSE;
867                 }
868             else  {
869                 stripHeight = pSrcData->stripHeight;
870                 constantStrip = pSrcData->constantStrip;
871                 }
872             break;
873
874             /*  A "hook" element: invalid if pipe executing or invalid, else add element
875                 to hook list with Init/Cleanup/Destroy functions copied.
876             */
877         case IL_HOOK:
878             if ((pPipe->state == IL_PIPE_INVALID) || (pPipe->state == IL_PIPE_EXECUTING)) {
879                 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PIPE_STATE);
880                 return (ilPtr)NULL;
881                 }
882             if (ExecuteThree || ExecuteFour) {
883                 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PAR_NOT_ZERO);
884                 return (ilPtr)NULL;
885                 }
886             pElement = (ilElementPtr)IL_MALLOC_ZERO (sizeof(ilElementRec) + nBytesPrivate);
887             if (!pElement) {
888                 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_MALLOC);
889                 return (ilPtr)NULL;                                 /* EXIT */
890                 }
891             pElement->pPrev = pPipe->hookHead.pPrev;
892             pElement->pNext = &pPipe->hookHead;
893             pPipe->hookHead.pPrev->pNext = pElement;
894             pPipe->hookHead.pPrev = pElement;
895             pElement->elementType = IL_HOOK;
896             pElement->exec.pPrivate = (ilPtr)&pElement->clientPrivate;
897             pElement->exec.pSrcImage = pElement->exec.pDstImage = (ilImageInfo *)NULL;
898             pElement->Init = Init;
899             pElement->Cleanup = Cleanup;
900             pElement->Destroy = Destroy;
901
902             pPipe->o.p.context->error = IL_OK;
903             return (ilPtr)pElement->exec.pPrivate;                  /* done; EXIT */
904             break;
905
906         default:
907             ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_ELEMENT_TYPE);
908             return (ilPtr)NULL;
909             break;
910         }   /* END switch elementType */
911
912
913         /*  Force stripHeight to be in range 1..image height */
914     if (stripHeight <= 0)
915         stripHeight = 1;
916     else if (stripHeight > pPipe->image.info.height)
917         stripHeight = pPipe->image.info.height;
918
919         /*  If pipe begins with an ilReadImage() and this is first filter, add
920             a throttle to entire strip height - this throttle knows to read whole strip
921             and return IL_ERROR_LAST_STRIP - otherwise ilExecutePipe() would not stop.
922                 Note: ilAddThrottlePipeElement() calls this function: recursion!
923             Also, note that no pipe state has been changed up to this point. BUT,
924             set needProducerThrottle to false or below check causes infinite recursion.
925         */
926     if ((elementType != IL_PRODUCER) && pPipe->needProducerThrottle) {
927         pPipe->needProducerThrottle = FALSE;        /* prevent recursion */
928         if (!_ilAddThrottlePipeElement ((ilPipe)pPipe, stripHeight, 
929                 constantStrip, pPipe->producerCode, 
930                 &pPipe->image.info.stripHeight, &pPipe->image.info.constantStrip)) {
931             ilDeclarePipeInvalid ((ilPipe)pPipe, pPipe->o.p.context->error);
932             return (ilPtr)NULL;
933             }
934         }
935
936         /*  If writing consumerImage (e.g. ilWriteImage()) or inserting a throttle
937             requiring minBufferHeight, insert copy filter if flagged: e.g. previous 
938             element was "no dst" filter or ilReadImage(); else possibly add throttle:
939                 If not a producer and pipe image is not compressed, check "stripHeight", 
940             the desired strip height, set above.
941                 If != current strip height, or caller requires a constant strip
942             and current is not constant, add a filter which makes it so.
943                 If throttle added successfully, set image info to what was asked for, but
944             first save stripHeight - it is the size of the src buffer to create, if any.
945         */
946     srcBufferHeight = pPipe->image.info.stripHeight;
947     if (insertCopyFilter) {
948         if (pPipe->image.des.compression == IL_UNCOMPRESSED) {
949             if (!_ilInsertCopyFilter ((ilPipe)pPipe, pPipe->image.info.stripHeight))
950                 return (ilPtr)NULL;
951             }
952         else if (!_ilInsertCompressedCopyFilter ((ilPipe)pPipe))
953             return (ilPtr)NULL;
954         }
955     else if ((elementType != IL_PRODUCER)
956      && (pPipe->image.des.compression == IL_UNCOMPRESSED)
957      && ((stripHeight != pPipe->image.info.stripHeight)
958       || (constantStrip && !pPipe->image.info.constantStrip)) ) {
959             if (!_ilAddThrottlePipeElement ((ilPipe)pPipe, stripHeight, 
960                 constantStrip, IL_PIPE_NOT_IMAGE,
961                 &pPipe->image.info.stripHeight, &pPipe->image.info.constantStrip)) {
962                     ilDeclarePipeInvalid ((ilPipe)pPipe, pPipe->o.p.context->error);
963                     return (ilPtr)NULL;
964                     }
965             }
966
967         /*  Allocate and zero element struct and add to end of list; exit if error. */
968     pElement = (ilElementPtr)IL_MALLOC_ZERO (sizeof(ilElementRec) + nBytesPrivate);
969     if (!pElement) {
970         ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_MALLOC);
971         return (ilPtr)NULL;                                 /* EXIT */
972         }
973     pElement->pPrev = pPipe->elementHead.pPrev;
974     pElement->pNext = &pPipe->elementHead;
975     pPipe->elementHead.pPrev->pNext = pElement;
976     pPipe->elementHead.pPrev = pElement;
977
978         /*  Copy passed data into the element struct and init element.
979             Each element's pNextSrcLine points to the next one's srcLine, and compressed.
980             pOffset/pNBytesWritten point to next one's srcOffset/nBytesToRead.
981                 Set "Destroy" to null for now, so it will not be called if we fail here.
982             Set it to passed function only when sure of success.
983         */
984     pElement->elementType = elementType;
985     pElement->flags = flags;
986     pElement->exec.pPrivate = (ilPtr)&pElement->clientPrivate;
987     pPrevElement = pElement->pPrev;
988     pPrevElement->exec.pNextSrcLine = &pElement->exec.srcLine;
989     pPrevElement->exec.compressed.pDstOffset = &pElement->exec.compressed.srcOffset;
990     pPrevElement->exec.compressed.pNBytesWritten = &pElement->exec.compressed.nBytesToRead;
991     pElement->pNext->exec.srcLine = 0;
992     pElement->Init = Init;
993     pElement->Cleanup = Cleanup;
994     pElement->Destroy = IL_NPF;         /* set when successful */
995     pElement->ExecuteThree = ExecuteThree;
996     pElement->ExecuteFour = ExecuteFour;
997
998         /*  If a producer, must have valid dst data and pDes/Format, or error.
999             Skip allocation of src image for producers - they get src on their own;
1000             set pSrcPipeImage to NULL.  Init # src lines to read to strip height.
1001                 Set ilPipeInfo.pPalette to callers if palette image, else to null
1002         */
1003     if (elementType == IL_PRODUCER) {
1004         if (!pDstData || !pDstData->pDes || !pDstData->pFormat) {
1005             ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PRODUCER_DATA);
1006             return (ilPtr)NULL;                             /* EXIT */
1007             }
1008         if ((pDstData->width <= 0) || (pDstData->height <= 0)) {
1009             ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_ZERO_SIZE_IMAGE);
1010             return (ilPtr)NULL;                             /* EXIT */
1011             }
1012         error = _ilValidateDesFormat (TRUE, pDstData->pDes, pDstData->pFormat);
1013         if (error) {
1014             ilDeclarePipeInvalid ((ilPipe)pPipe, error);
1015             return (ilPtr)NULL;                            /* EXIT */
1016             }
1017
1018         pPipe->producerCode = IL_PIPE_NOT_IMAGE;    /* not a read from a (feed) image */
1019         pPipe->pSrcPipeImage = (ilImageInfo *)NULL;
1020
1021         pPipe->image.des = *pDstData->pDes;
1022         pPipe->image.format = *pDstData->pFormat;
1023         pPipe->image.info.producerObject = pDstData->producerObject;
1024         pPipe->image.info.tempImage = TRUE;
1025
1026         pPipe->image.info.width = pDstData->width;
1027         pPipe->image.info.height = pDstData->height;
1028         pPipe->image.info.constantStrip = pDstData->constantStrip;
1029         pPipe->image.info.stripHeight = pDstData->stripHeight;
1030         ilChangeStripHeight (pPipe);
1031
1032         pPipe->image.info.pPalette = (pPipe->image.des.type == IL_PALETTE) ? 
1033                                            pDstData->pPalette : (unsigned short *)NULL;
1034         pPipe->image.info.pCompData = pDstData->pCompData;
1035         pPipe->needProducerThrottle = FALSE;        /* producer not an image */
1036         pPipe->copyToConsumerImage = FALSE;
1037
1038         pElement->exec.pSrcImage = (ilImageInfo *)NULL;
1039         }
1040     else  {
1041             /*  Not a producer.  Create src image to this element, unless a consumer which
1042                 specifies its source image (e.g. ilWriteImage()), or src image specified
1043                 as output from last element = a producer (e.g. ilReadImage()): pSrcImage.
1044             */
1045         if (pPipe->pSrcPipeImage) {
1046             pElement->exec.pSrcImage = pPipe->pSrcPipeImage;
1047             pPipe->pSrcPipeImage = (ilImageInfo *)NULL;
1048             }
1049         else if (haveConsumerImage) {
1050             pElement->exec.pSrcImage = &((ilImagePtr)pSrcData->consumerImage)->i;
1051             }
1052         else {
1053                 /*  Src image not provided; must create a temp and add to list of temps.
1054                     Set image height = max (minHeight if present, srcBufferHeight).
1055                 */
1056             ilImagePtr      pImage;
1057             pImage = ilAllocTempImage (pPipe, &pPipe->image.info, &pPipe->image.des, 
1058                                        &pPipe->image.format);
1059             if (!pImage) {
1060                 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_MALLOC);
1061                 return (ilPtr)NULL;                         /* EXIT */
1062                 }
1063             pElement->exec.pSrcImage = &pImage->i;
1064             if (pSrcData && (pSrcData->minBufferHeight > srcBufferHeight))
1065                 srcBufferHeight = pSrcData->minBufferHeight;
1066             pImage->i.height = srcBufferHeight;
1067             }
1068
1069             /*  Src image to this element is dst image of previous element.
1070                 If no dst from this element, then src to this element is src to next,
1071                 and must copy if next element is ilWriteImage(); otherwise, src to next 
1072                 is necessarily a temp image, and don't need to copy.
1073             */
1074         pElement->pPrev->exec.pDstImage = pElement->exec.pSrcImage;
1075         if (flags & IL_ADD_PIPE_NO_DST) {
1076             pPipe->pSrcPipeImage = pElement->exec.pSrcImage;
1077             pPipe->copyToConsumerImage = TRUE;
1078             }
1079         else {
1080             pPipe->image.info.tempImage = TRUE;
1081             pPipe->copyToConsumerImage = FALSE;
1082             }
1083
1084             /*  If not a consumer and have pDstData: if non-null des/format ptr, copy
1085                 data from it into the pipe image area - element changes des or format.
1086                 Set rest of data from pDstData: stripHeight if not zero.
1087                 Set ilPipeInfo.pPalette to null if not a palette image, or to callers
1088                     value if it is not null.
1089                 Validate pDes and pFormat together if either non-null (else no change).
1090             */
1091         if (pDstData && (elementType != IL_CONSUMER)) {
1092             const ilImageDes      *pDes;
1093             if ((pDstData->width <= 0) || (pDstData->height <= 0)) {
1094                 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_ZERO_SIZE_IMAGE);
1095                 return (ilPtr)NULL;                         /* EXIT */
1096                 }
1097             pPipe->image.info.width = pDstData->width;
1098             pPipe->image.info.height = pDstData->height;
1099             if (pDstData->stripHeight != 0) {
1100                 pPipe->image.info.constantStrip = pDstData->constantStrip;
1101                 pPipe->image.info.stripHeight = pDstData->stripHeight;
1102                 }
1103             if (pDes = pDstData->pDes) {
1104                 if (pDes->type == IL_PALETTE) {
1105                     if (pDstData->pPalette)
1106                         pPipe->image.info.pPalette = pDstData->pPalette;
1107                     }
1108                 else pPipe->image.info.pPalette = (unsigned short *)NULL;
1109                 pPipe->image.des = *pDes;
1110                 }
1111             pPipe->image.info.pCompData = pDstData->pCompData;
1112             if (pDstData->pFormat)
1113                 pPipe->image.format = *pDstData->pFormat;
1114             if (pDes || pDstData->pFormat) {
1115                 error = _ilValidateDesFormat (TRUE /* allow private types */, 
1116                                              &pPipe->image.des, &pPipe->image.format);
1117                 if (error) {
1118                     ilDeclarePipeInvalid ((ilPipe)pPipe, error);
1119                     return (ilPtr)NULL;                            /* EXIT */
1120                     }
1121                 }
1122             ilChangeStripHeight (pPipe);        /* reset (recommended) strip height */
1123             }   /* END have pDstData, not consumer */
1124         }       /* END not a producer */
1125
1126         /*  Success: set pipe to new state; set pElement->Destroy, return pPriv. */
1127     pPipe->state = newState;
1128     pElement->Destroy = Destroy;
1129
1130     pPipe->o.p.context->error = IL_OK;
1131     return (ilPtr)pElement->exec.pPrivate;
1132 }
1133
1134
1135         /*  ------------------------ ilAbortPipe -------------------------------- */
1136         /*  Public function: see spec.
1137             Aborts the given pipe; if not running, a noop.
1138         */
1139 ilBool ilAbortPipe (
1140     ilPipe              pipe
1141     )
1142 {
1143 register ilPipePtr      pPipe;
1144
1145     pPipe = (ilPipePtr)pipe;
1146     if (pPipe->o.p.objectType != IL_PIPE) {
1147         pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
1148         return FALSE;
1149         }
1150
1151     if (pPipe->state == IL_PIPE_EXECUTING)
1152         return ((pPipe->o.p.context->error = ilCleanupRunningPipe (pPipe, TRUE)) == IL_OK);
1153     else {
1154         pPipe->o.p.context->error = IL_OK;
1155         return TRUE;
1156         }
1157 }
1158
1159         /*  ------------------------ ilExecutePipe -------------------------------- */
1160         /*  Public function: see spec.
1161         */
1162 int ilExecutePipe (
1163     ilPipe              pipe,
1164     long                nStrips,
1165     float               ratio
1166     )
1167 {
1168 register ilPipePtr      pPipe;
1169 register ilElementPtr   pElement, pExecHead, pElementHead;
1170 ilImagePtr              pImage;
1171 long                    nLines, initNLines;
1172 ilError                 error;
1173
1174         /*  Validate zero par and that pipe is one.
1175         */
1176     pPipe = (ilPipePtr)pipe;
1177     if (pPipe->o.p.objectType != IL_PIPE) {
1178         pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
1179         return IL_EXECUTE_ERROR;                            /* EXIT */
1180         }
1181
1182         /*  Execute based on pipe state.  Error if pipe invalid, empty or forming.
1183             Otherwise: abort if requested, cleanup if in progress.  Compile pipe
1184             if complete, or executable and producer changed.  If in progress and
1185             producer changed, cleanup and return error.
1186         */
1187     pExecHead = &pPipe->elementHead;            /* head of "executable" (non-hook) list */
1188     switch (pPipe->state) {
1189       case IL_PIPE_INVALID:
1190       case IL_PIPE_EMPTY:
1191       case IL_PIPE_FORMING:
1192         pPipe->o.p.context->error = IL_ERROR_PIPE_STATE;
1193         return IL_EXECUTE_ERROR;                            /* EXIT */
1194
1195             /*  Pipe complete: do setup to become executable.
1196                 Allocate pixel buffers for all temp images of this pipe.
1197                 If error, don't cleanup, as init not done yet.
1198             */
1199       case IL_PIPE_COMPLETE:
1200         pImage = (ilImagePtr)pPipe->imageHead.pNext;
1201         while (pImage != (ilImagePtr)&pPipe->imageHead) {
1202             ilError error = _ilMallocImagePixels (pImage);
1203             if (error) {
1204                 ilFreeTempImageBuffers (pPipe);
1205                 pPipe->o.p.context->error = error;
1206                 return IL_EXECUTE_ERROR;                    /* EXIT */
1207                 }
1208             pImage = (ilImagePtr)pImage->o.pNext;
1209             }
1210
1211             /*  Call elements' Init() functions if non-null. If Init() returns error:
1212                 call Cleanup() of previous elements, whose Init()s were already called,
1213                 and free image buffers allocated above, and return error in errorInfo.
1214                 Init all srcLines and srcOffsets to 0; always start at line/byte 0.
1215                     Do above first for "hook" list, then for regular element list.
1216             */
1217         pElementHead = &pPipe->hookHead;
1218         while (TRUE) {
1219             pElement = pElementHead->pNext;
1220             while (pElement != pElementHead) {
1221                 pElement->exec.srcLine = 0;
1222                 pElement->exec.compressed.srcOffset = 0;
1223                 if (pElement->Init) {
1224                     ilError error = (*pElement->Init) ((ilPtr)pElement->exec.pPrivate, 
1225                                      pElement->exec.pSrcImage, pElement->exec.pDstImage);
1226                     if (error) {
1227                         while (TRUE) {
1228                             while (pElement->pPrev != pElementHead) {
1229                                 pElement = pElement->pPrev;
1230                                 if (pElement->Cleanup)
1231                                     (*pElement->Cleanup) (pElement->exec.pPrivate, TRUE);
1232                                 }
1233                             if (pElementHead == &pPipe->hookHead)
1234                                 break;                          /* both lists done */
1235                             pElementHead = &pPipe->hookHead;
1236                             pElement = pElementHead;
1237                             }
1238                         ilFreeTempImageBuffers (pPipe);
1239                         pPipe->o.p.context->errorInfo = error;
1240                         pPipe->o.p.context->error = (error < 0) ? 
1241                                         IL_ERROR_USER_PIPE_ELEMENT : IL_ERROR_PIPE_ELEMENT;
1242                         return IL_EXECUTE_ERROR;                /* EXIT */
1243                         }
1244                     }
1245                 pElement = pElement->pNext;
1246                 }   /* END while, one element list */
1247             if (pElementHead == pExecHead)
1248                 break;                                      /* both lists scanned; done */
1249             pElementHead = pExecHead;                       /* run thru executable list */
1250             }       /* END while TRUE, all element lists */
1251
1252             /*  Now executing; FALL THRU to execute one pass.  Point top of execStack to
1253                 first element; it changes to top of execStack on a push.
1254             */
1255         pPipe->stackIndex = 0;
1256         pPipe->execStack[0] = pExecHead->pNext;
1257         pPipe->state = IL_PIPE_EXECUTING;
1258         pPipe->lastStrip = FALSE;
1259
1260             /*  Pipe being executed, possibly first time. Execute nStrips strips (or all
1261                 if !nStrips). dstLine for each element is "srcLine" of next element.
1262                 Start with top element of "execStack".
1263                     "nLines" on entry to Execute() = # of src lines to read; 
1264                 on exit = # of dst lines written (== 0, skip rest of pipe).
1265                 If error: check for pseudo-error, else abort.  Pseudo-errors:
1266                     IL_ERROR_LAST_STRIP: finish processing this strip, then done
1267                     IL_ERROR_ELEMENT_AGAIN: element states that it needs to be recalled
1268                         (e.g. a throttle with more left in its input buffer). Push
1269                         pElement onto execStack; exit if overflow.
1270                     IL_ERROR_ELEMENT_COMPLETE: element states that it previously issued
1271                         "AGAIN" and is now done.  Pop stack; exit if underflow.
1272             */
1273       case IL_PIPE_EXECUTING:
1274         if (pPipe->producerCode == IL_PIPE_FEED_IMAGE) {
1275             ilElementPtr        pFirstElement;
1276
1277             if (!pPipe->feedDone) {         /* pipe executed directly instead of fed */
1278                 ilCleanupRunningPipe (pPipe, TRUE);
1279                 pPipe->o.p.context->error = IL_ERROR_PIPE_NOT_FED;
1280                 return IL_EXECUTE_ERROR;
1281                 }
1282             pPipe->feedDone = FALSE;
1283             initNLines = pPipe->feedNLines;
1284             pFirstElement = pExecHead->pNext;
1285             pFirstElement->exec.srcLine = pPipe->feedStartLine;
1286             pFirstElement->exec.compressed.srcOffset = pPipe->feedCompOffset;
1287             pFirstElement->exec.compressed.nBytesToRead = pPipe->feedCompNBytes;
1288             }
1289         else initNLines = pPipe->image.info.height;  /* first element reads whole image */
1290
1291         while (TRUE) {                          /* until all or nStrips done */
1292             nLines = initNLines;
1293             pElement = pPipe->execStack [pPipe->stackIndex];
1294             while (pElement != pExecHead) {
1295 /*
1296 ** Added another execute function for passing in a fourth
1297 ** parameter which is a floating pointing.  So check to see
1298 ** which execute function is not null and call that one.
1299 */
1300                 if(pElement->ExecuteThree)
1301                     {
1302                     error = (*pElement->ExecuteThree) (&pElement->exec,                                      pElement->pNext->exec.srcLine, 
1303                                       &nLines);
1304                     }
1305                 else
1306                     {
1307                     error = (*pElement->ExecuteFour) (&pElement->exec, 
1308                                                pElement->pNext->exec.srcLine, 
1309                                                &nLines, ratio);
1310                     }
1311                 if (error) {
1312                     if (error == IL_ERROR_ELEMENT_AGAIN) {
1313                         if (++pPipe->stackIndex >= IL_MAX_EXEC_STACK) {
1314                             ilCleanupRunningPipe (pPipe, TRUE);
1315                             pPipe->o.p.context->error = IL_ERROR_EXECUTE_STACK_OVERFLOW;
1316                             return IL_EXECUTE_ERROR;            /* EXIT */
1317                             }
1318                         pPipe->execStack [pPipe->stackIndex] = pElement;
1319                         }
1320                     else if (error == IL_ERROR_ELEMENT_COMPLETE) {
1321                         if (--pPipe->stackIndex < 0) {
1322                             ilCleanupRunningPipe (pPipe, TRUE);
1323                             pPipe->o.p.context->error = IL_ERROR_EXECUTE_STACK_UNDERFLOW;
1324                             return IL_EXECUTE_ERROR;            /* EXIT */
1325                             }
1326                         }
1327                     else if (error == IL_ERROR_LAST_STRIP)
1328                         pPipe->lastStrip = TRUE;
1329                     else {
1330                         ilCleanupRunningPipe (pPipe, TRUE);
1331                         pPipe->o.p.context->errorInfo = error;
1332                         pPipe->o.p.context->error = (error < 0) ? 
1333                                     IL_ERROR_USER_PIPE_ELEMENT : IL_ERROR_PIPE_ELEMENT;
1334                         return IL_EXECUTE_ERROR;                /* EXIT */
1335                         }
1336                     }
1337                 if (nLines <= 0)                /* no lines written; skip rest of pipe */
1338                     break;
1339                 pElement = pElement->pNext;
1340                 }
1341
1342                     /*  If stack is empty (if not empty, still pushing the current strip
1343                         thru the pipe): if last strip, do cleanup and exit, else downcount
1344                         nStrips (if != 0 => all strips) and return if 0.
1345                     */
1346             if (pPipe->stackIndex <= 0) {
1347                 if (pPipe->lastStrip) {
1348                     ilError error = ilCleanupRunningPipe (pPipe, FALSE);
1349                     if (error == IL_OK) 
1350                         return IL_EXECUTE_COMPLETE;
1351                     else {
1352                         pPipe->o.p.context->errorInfo = error;
1353                         pPipe->o.p.context->error = (error < 0) ? 
1354                                     IL_ERROR_USER_PIPE_ELEMENT : IL_ERROR_PIPE_ELEMENT;
1355                         return IL_EXECUTE_ERROR;
1356                         }
1357                     }
1358                 if ((nStrips != 0) && (--nStrips <= 0))
1359                     return IL_EXECUTE_AGAIN;
1360                 }
1361
1362             }   /* END while true: execute strips */
1363         }       /* END switch pipe state */
1364 }
1365
1366