1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/lib/DtHelp/il/ilrwimage.c
2012-03-10 18:58:32 +00:00

525 lines
22 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $XConsortium: ilrwimage.c /main/6 1996/06/19 12:21:00 ageorge $ */
/**---------------------------------------------------------------------
***
*** (c)Copyright 1991 Hewlett-Packard Co.
***
*** RESTRICTED RIGHTS LEGEND
*** Use, duplication, or disclosure by the U.S. Government is subject to
*** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
*** Technical Data and Computer Software clause in DFARS 252.227-7013.
*** Hewlett-Packard Company
*** 3000 Hanover Street
*** Palo Alto, CA 94304 U.S.A.
*** Rights for non-DOD U.S. Government Departments and Agencies are as set
*** forth in FAR 52.227-19(c)(1,2).
***
***-------------------------------------------------------------------*/
/* /ilc/ilrwimage.c : A misnomer. Now contains pipe throttles
inserted by ilAddPipeElement().
NOTE: code in this file handles uncompressed images only.
*/
#include "ilint.h"
#include "ilimage.h"
#include "ilpipelem.h"
#include "ilpipeint.h"
#include "ilerrors.h"
/* Private structure for all throttle elements.
"Init()" are fields that Init() must init, "Add()" when pipe element is added,
else temp values used during pipe execution.
*/
typedef struct {
ilBool beingRecalled; /* Init(): ilExecutePipe() recalling us? */
long nBufferLines; /* Init(): # of unprocessed lines in buffer */
long nLinesReceived; /* Init(): total # src lines received */
long imageHeight; /* Add(): total height of image */
long stripHeight; /* Add(): size of each output strip */
} ilThrottlePrivRec, *ilThrottlePrivPtr;
/* ---------------------- ilThrottleInit --------------------------------- */
/* Init() function for throttle pipe elements.
*/
static ilError ilThrottleInit (
ilThrottlePrivPtr pPriv,
ilImageInfo *pSrcImage,
ilImageInfo *pDstImage
)
{
pPriv->beingRecalled = FALSE;
pPriv->nBufferLines = 0;
pPriv->nLinesReceived = 0;
return IL_OK;
}
/* --------------------- ilProducerThrottleExecute -------------------------- */
/* Execute() for a filter inserted by ilAddThrottlePipeElement() to be the
logical producer, i.e. the pipe began with an ilReadImage(). Must
output constant strips (except possibly the last) and return "last strip"
error on last one.
*/
static ilError ilProducerThrottleExecute (
register ilExecuteData *pData,
long dstLine, /* ignored */
long *pNLines /* ignored on input */
)
{
register ilThrottlePrivPtr pPriv;
/* Set the next elements srcLine to our current line. Bump srcLine by
stripHeight (# lines just "written"), but if that is to/past end of image,
return last strip error, else "ok", to do more strips.
*/
pPriv = (ilThrottlePrivPtr)pData->pPrivate;
*pData->pNextSrcLine = pData->srcLine;
if ((pData->srcLine + pPriv->stripHeight) >= pPriv->imageHeight) {
*pNLines = pPriv->imageHeight - pData->srcLine;
return IL_ERROR_LAST_STRIP;
}
else {
*pNLines = pPriv->stripHeight;
pData->srcLine += pPriv->stripHeight;
return IL_OK;
}
}
/* --------------------- ilFeedProducerThrottleExecute ----------------------- */
/* Execute() for a filter inserted by ilAddThrottlePipeElement() to be the
logical producer when the pipe began with an ilFeedFromImage().
Coupled to ilExecutePipe(): *pNLines on input must be nLines and
pData->srcLine must be startLine, as passed to ilFeedPipe()
*/
static ilError ilFeedProducerThrottleExecute (
register ilExecuteData *pData,
long dstLine, /* ignored */
long *pNLines
)
{
register ilThrottlePrivPtr pPriv;
long nLines;
/* Point next element to the feed data, set into pData by ilExecutePipe():
srcLine (for uncompressed) and srcOffset, nBytesToRead for compressed data.
If all lines received (count in nLinesReceived), return "last strip", else ok.
*/
pPriv = (ilThrottlePrivPtr)pData->pPrivate;
*pData->pNextSrcLine = pData->srcLine;
*pData->compressed.pDstOffset = pData->compressed.srcOffset;
*pData->compressed.pNBytesWritten = pData->compressed.nBytesToRead;
nLines = *pNLines;
if ((nLines + pPriv->nLinesReceived) >= pPriv->imageHeight) {
*pNLines = pPriv->imageHeight - pPriv->nLinesReceived;
return IL_ERROR_LAST_STRIP;
}
else {
pPriv->nLinesReceived += nLines;
return IL_OK;
}
}
/* --------------------- ilNonConstantThrottleExecute --------------------- */
/* Execute() for when not the producer, but constant strips are not required.
*/
static ilError ilNonConstantThrottleExecute (
register ilExecuteData *pData,
long dstLine, /* ignored */
long *pNLines
)
{
register ilThrottlePrivPtr pPriv;
/* Not from a producer, but !constantStrip; easy: caller just wants strips
of size "stripHeight" or smaller. For each strip written to this throttle,
break it into "stripHeight" or smaller pieces; completely process each strip.
Move srcLine thru image; always have next element read from srcLine.
If not beingRecalled, then previous filter actually wrote something to us:
store how much was written into nBufferLines; exit if nothing.
*/
*pData->pNextSrcLine = pData->srcLine;
pPriv = (ilThrottlePrivPtr)pData->pPrivate;
if (!pPriv->beingRecalled) {
pPriv->nBufferLines = *pNLines;
if (!pPriv->nBufferLines)
return IL_OK; /* EXIT */
}
/* Write "pPriv->stripHeight" sized strips. If that or less in buffer, write it
and cancel the recall if on; reset srcLine to be beginning of buffer.
*/
if ((pData->srcLine + pPriv->stripHeight) >= pPriv->nBufferLines) {
*pNLines = pPriv->nBufferLines - pData->srcLine;
pData->srcLine = 0;
if (pPriv->beingRecalled) {
pPriv->beingRecalled = FALSE;
return IL_ERROR_ELEMENT_COMPLETE; /* EXIT */
}
else return IL_OK; /* EXIT */
}
/* More than pPriv->stripHeight lines in buffer: write stripHeight lines, bump
srcLine by that amount, and if not beingRecalled, make it so.
*/
*pNLines = pPriv->stripHeight;
pData->srcLine += pPriv->stripHeight;
if (!pPriv->beingRecalled) {
pPriv->beingRecalled = TRUE;
return IL_ERROR_ELEMENT_AGAIN; /* EXIT */
}
else return IL_OK; /* EXIT */
}
/* --------------------- ilConstantThrottleExecute --------------------- */
/* Execute() for when not a producer and constant strips are required.
*/
static ilError ilConstantThrottleExecute (
register ilExecuteData *pData,
long dstLine, /* ignored */
long *pNLines
)
{
register ilThrottlePrivPtr pPriv;
long nLines, nLinesToWrite;
register ilError returnCode;
pPriv = (ilThrottlePrivPtr)pData->pPrivate;
if (pPriv->beingRecalled)
nLines = 0; /* # lines passed is garbage on a recall */
else {
nLines = *pNLines;
pPriv->nBufferLines += nLines;
pPriv->nLinesReceived += nLines;
}
/* If have (at least) a strip's worth in buffer, "write" it and request a
recall. If beingRecalled (i.e. this code was done on the previous call),
bump srcLine by stripHeight (# lines done before), else set srcLine to
zero to start at the beginning of the buffer.
*/
if (pPriv->nBufferLines >= pPriv->stripHeight) {
nLinesToWrite = pPriv->stripHeight;
pPriv->nBufferLines -= pPriv->stripHeight;
if (pPriv->beingRecalled) {
pData->srcLine += pPriv->stripHeight;
returnCode = IL_OK;
}
else {
pPriv->beingRecalled = TRUE;
pData->srcLine = 0;
returnCode = IL_ERROR_ELEMENT_AGAIN;
}
}
else {
/* Dont have a strip's worth in buffer. If beingRecalled, then some lines
have been read out from beginning of buffer by next element. Copy the
the lines above that point down to the beginning of the buffer, and
set srcLine to the line past them.
If not being recalled, bump srcLine by # lines received this strip.
*/
if (pPriv->beingRecalled) {
int nPlanes;
ilImagePlaneInfo *pPlane;
const ilImageDes *pDes = pData->pSrcImage->pDes;
pData->srcLine += pPriv->stripHeight;
if (pPriv->nBufferLines > 0) {
nPlanes = (pData->pSrcImage->pFormat->sampleOrder == IL_SAMPLE_PIXELS) ?
1 : pDes->nSamplesPerPixel;
pPlane = pData->pSrcImage->plane;
/* If a YCbCr image, copy subsampled buffers properly. */
if (pDes->type == IL_YCBCR) {
int vertShift;
const ilYCbCrSampleInfo *pSample = pDes->typeInfo.YCbCr.sample;
while (nPlanes-- > 0) {
vertShift = _ilSubsampleShift [pSample->subsampleVert];
pSample++;
bcopy ((char *)(pPlane->pPixels +
(pData->srcLine >> vertShift) * pPlane->nBytesPerRow),
(char *)pPlane->pPixels,
(pPriv->nBufferLines >> vertShift) * pPlane->nBytesPerRow);
pPlane++;
}
}
else {
while (nPlanes-- > 0) {
bcopy ((char *)(pPlane->pPixels +
pData->srcLine * pPlane->nBytesPerRow),
(char *)pPlane->pPixels,
pPriv->nBufferLines * pPlane->nBytesPerRow);
pPlane++;
}
}
}
pData->srcLine = pPriv->nBufferLines;
}
else pData->srcLine += nLines;
/* Dont have strip's worth, need more lines: if all lines read, write a
short final strip, otherwise write 0 lines and wait for more lines to
come in, written to pData->srcLine.
*/
if (pPriv->nLinesReceived >= pPriv->imageHeight) {
nLinesToWrite = pPriv->nBufferLines; /* write last (short) strip */
pPriv->nBufferLines = 0;
pData->srcLine = 0;
}
else nLinesToWrite = 0;
/* Cancel recall if one in effect, mark that we are not in a recall. */
returnCode = (pPriv->beingRecalled) ? IL_ERROR_ELEMENT_COMPLETE : IL_OK;
pPriv->beingRecalled = FALSE;
} /* END need more lines */
/* Tell next element to read "nLinesWrite" starting at "pData->srcLine". */
*pNLines = nLinesToWrite;
*pData->pNextSrcLine = pData->srcLine;
return returnCode;
}
/* ------------------ ilCopyImageExecute ------------------------------- */
/* Copies the src image to the dst image. Used when pipe is formed by an
ilReadImage() followed immediately by an ilWriteImage().
Handles uncompressed images only; compressed images handled separately.
*/
static ilError ilCopyImageExecute (
register ilExecuteData *pData,
long dstLine,
long *pNLines
)
{
ilImageInfo *pSrcImage, *pDstImage;
ilImagePlaneInfo *pSrcPlane, *pDstPlane;
const ilYCbCrSampleInfo *pSample;
long srcRowBytes, dstRowBytes;
long nLines, nBytes, srcStart, dstStart;
int nPlanes;
ilPtr pSrcLine, pDstLine;
register long lineCount;
/* Point to src/dst image and first plane of each */
pSrcImage = pData->pSrcImage;
pDstImage = pData->pDstImage;
pSrcPlane = &pSrcImage->plane[0];
pDstPlane = &pDstImage->plane[0];
nLines = *pNLines;
/* If a YCbCr image point pSample to first plane's sample info; else null */
if (pSrcImage->pDes->type == IL_YCBCR)
pSample = pSrcImage->pDes->typeInfo.YCbCr.sample;
else pSample = (ilYCbCrSampleInfo *)NULL;
/* Loop thru and copy, plane by plane: 1 plane if pixel order. If YCbCr image
(pSample) divide nLines and src/dstStart by subsample factor (1,2 or 4).
*/
nPlanes = (pSrcImage->pFormat->sampleOrder == IL_SAMPLE_PIXELS) ?
1 : pSrcImage->pDes->nSamplesPerPixel;
while (nPlanes-- > 0) {
lineCount = nLines;
srcStart = pData->srcLine;
dstStart = dstLine;
if (pSample) {
int vertShift;
vertShift = _ilSubsampleShift [pSample->subsampleVert];
lineCount >>= vertShift;
srcStart >>= vertShift;
dstStart >>= vertShift;
pSample++;
}
srcRowBytes = pSrcPlane->nBytesPerRow;
pSrcLine = pSrcPlane->pPixels + srcStart * srcRowBytes;
pSrcPlane++;
dstRowBytes = pDstPlane->nBytesPerRow;
pDstLine = pDstPlane->pPixels + dstStart * dstRowBytes;
pDstPlane++;
/* Copy min(src,dst) row bytes from each line; set to -1 */
nBytes = (srcRowBytes < dstRowBytes) ? srcRowBytes : dstRowBytes;
if (nBytes <= 0)
continue; /* no bytes (? perhaps subsampled ?), next plane */
while (lineCount-- > 0) {
bcopy ((char *)pSrcLine, (char *)pDstLine, nBytes);
pSrcLine += srcRowBytes;
pDstLine += dstRowBytes;
}
} /* END one plane */
return IL_OK;
}
/* ---------------------- ilInsertCopyFilter ------------------------------ */
/* Insert a "filter" which merely copies the pipe image to the dest image.
This is necessary when the pipe is "<Read Image> <WriteImage>", because both
ilReadImage() allows the next filter to read directly from its image, and
ilWriteImage() allows the previous filter to write directly to its image,
but together, there needs to be a filter in between. It is also used after
an IL_ADD_PIPE_NO_DST filter.
*/
IL_PRIVATE ilBool _ilInsertCopyFilter (
ilPipe pipe,
long height
)
{
ilSrcElementData srcData;
/* Add a filter which copies src to dst. No private needed; the Execute()
function ilCopyImageExecute() does all necessary setup. Specify src
stripHeight of whole image, to do whole copy in one strip.
*/
srcData.consumerImage = (ilObject)NULL;
srcData.stripHeight = height;
srcData.constantStrip = FALSE;
srcData.minBufferHeight = 0;
if (!ilAddPipeElement (pipe, IL_FILTER, 0, 0, &srcData, (ilDstElementData *)NULL,
IL_NPF, IL_NPF, IL_NPF, ilCopyImageExecute, NULL, 0))
return FALSE;
pipe->context->error = IL_OK;
return TRUE;
}
/* ----------------------- ilAddThrottlePipeElement ---------------------- */
/* Called by ilAddPipeElement to add a "throttle" pipe element to feed
strips of height "stripHeight" or zero (0) to the next element.
For uncompressed images only: if "constantStrip" is true, the strips out of
this filter must all be "stripHeight" or zero lines high, except for the last
strip; if false, the height of each strip must be <= "stripHeight".
If "producerCode" is not IL_PIPE_NOT_IMAGE, then the throttle is a
logical producer: the pipe began with an ilReadImage() or ilFeedFromImage()
and must signal IL_ERROR_LAST_STRIP; else the throttle is not the producer.
This flag is used in place of "tempImage" in pipe info which IS INCORRECT -
ilExecutePipe() changes it to avoid infinite recursion.
The strip height from this filter is returned to "*pStripHeight", and
"*pConstantStrip" is set true if constant strips are output.
Returns: true if success, else false.
*/
IL_PRIVATE ilBool _ilAddThrottlePipeElement (
ilPipe pipe,
long stripHeight,
ilBool constantStrip,
unsigned int producerCode,
long *pStripHeight,
ilBool *pConstantStrip
)
{
ilPipeInfo info;
ilSrcElementData srcData;
register ilThrottlePrivPtr pPriv;
ilGetPipeInfo (pipe, FALSE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL);
srcData.consumerImage = (ilObject)NULL;
srcData.stripHeight = info.stripHeight;
srcData.constantStrip = FALSE;
srcData.minBufferHeight = 0;
switch (producerCode) {
/* If reading directly from whole image, always output constant strips. */
case IL_PIPE_IMAGE:
pPriv = (ilThrottlePrivPtr)ilAddPipeElement (pipe, IL_FILTER,
sizeof (ilThrottlePrivRec), IL_ADD_PIPE_NO_DST,
&srcData, (ilDstElementData *)NULL, ilThrottleInit, IL_NPF, IL_NPF,
ilProducerThrottleExecute, NULL, 0);
constantStrip = TRUE;
break;
/* If feeding pipe from an image, first add producer filter to "write"
the number of lines passed to ilFeedPipe(). If stripHeight written by feed
(info.stripHeight) is < requested strip height and !constantStrip, or if
equal and feed gives constant strips, done; else insert a filter to copy
the feed image to output buffer (else throttle will never get a buffer),
fall thru and treat same as if pipe not started with a read from an image.
*/
case IL_PIPE_FEED_IMAGE:
pPriv = (ilThrottlePrivPtr)ilAddPipeElement (pipe, IL_FILTER,
sizeof (ilThrottlePrivRec), IL_ADD_PIPE_NO_DST,
&srcData, (ilDstElementData *)NULL, ilThrottleInit, IL_NPF, IL_NPF,
ilFeedProducerThrottleExecute, NULL, 0);
if (!pPriv) return FALSE;
pPriv->imageHeight = info.height;
pPriv->stripHeight = stripHeight;
if (((info.stripHeight <= stripHeight) && !constantStrip)
|| ((info.stripHeight == stripHeight) && info.constantStrip))
break; /* else ! FALL THRU TO ... */
/* Copy feed image data to buffer, fall thru to add throttle */
_ilInsertCopyFilter (pipe, info.stripHeight);
/* If not constant strips are not required, simple, else tougher:
Must buffer those passed to us, possibly requesting a recall when we have
more than one strip's worth in the buffer. Need space in buffer for
worst case: we have 1 line less than needed for (requested) "stripHeight",
and then previous element then writes "info.stripHeight" lines.
*/
case IL_PIPE_NOT_IMAGE:
if (!constantStrip) {
pPriv = (ilThrottlePrivPtr)ilAddPipeElement (pipe, IL_FILTER,
sizeof (ilThrottlePrivRec), IL_ADD_PIPE_NO_DST,
&srcData, (ilDstElementData *)NULL, ilThrottleInit, IL_NPF, IL_NPF,
ilNonConstantThrottleExecute, NULL, 0);
}
else {
srcData.minBufferHeight = stripHeight + info.stripHeight - 1;
if (srcData.minBufferHeight > info.height)
srcData.minBufferHeight = info.height;
pPriv = (ilThrottlePrivPtr)ilAddPipeElement (pipe, IL_FILTER,
sizeof (ilThrottlePrivRec), IL_ADD_PIPE_NO_DST,
&srcData, (ilDstElementData *)NULL, ilThrottleInit, IL_NPF, IL_NPF,
ilConstantThrottleExecute, NULL, 0);
}
break;
}
/* Check for successful element add, init private */
if (!pPriv) return FALSE;
pPriv->imageHeight = info.height;
pPriv->stripHeight = stripHeight;
/* Return new strip height and whether constantStrip */
*pStripHeight = stripHeight;
*pConstantStrip = constantStrip;
return TRUE;
}