KCMS CMM Developer's Guide

KcsXformSeq Derivatives

The KcsXformSeq class is a KcsXform derivative that allows a list or concatenation of transformations to act as one KcsXform. It is an alias to an ordered transformation collection that allows all normal list management in addition to all of the required KcsXform protocols. It also allows a hierarchy of KcsXform instances by providing the ability to sequence the list. Evaluating through a sequence of KcsXforms is like serially running each transform, with successive transformations taking input from the output of its predecessor and ending with the last one putting its output into the destination location.

Constructs and Destructors

You can construct a KcsXformSeq with any of the following:

Saving

Saving trickles down throughout the whole connected hierarchy. Any change to any transformation in the sequence is saved when the sequence is saved. This happens because the sequence shares the transformations passed to it. The instance also gets the chunk Ids from each transformation in the list. It then packs these and other state information into a memory block and does a setChunk()() to allow lookup of this transformation list upon a load request to the sequence.

When requested to save in universal format (see "Universal" for details), the sequence does a composition that generates one transformation that is saved in this format.

Loading and Constructing the List

A KcsXformSeq instance saves its transformations as a list of chunk Ids to later instantiate when needed. For every chunk Id in its own chunk, getChunkXform()() takes the current chunk set and chunk Ids and, through the chunk set protocol of createXform()(), allocates the transformation represented by that unique combination.

Connections

KcsXformSeq is the only class in the KCMS framework that supports connection (and connection is the only reason the KcsXformSeq class exists). The base KcsXform class uses a sequence derivative in its connect()() method.

To make a connection, you can call either of two KcsXformSeq constructors (or use a combination of the two): one constructor takes a list of transformation pointers; the other creates a sequence of 0s. Then edit the transformations list with the list()() methods. See "Validation" for additional information on the connection method.

Optimization

When a sequence is told to optimize itself, first it optimizes each transformation in the chain individually. Then it composes all the transformations into one KcsTechUCP transformation. Finally it uses that composed KcsTechUCP to do future evaluations. Overall optimization is provided with optimization and composition of the individual transformations in the list.

The KcsXformSeq class performs composition by asking each transformation in the list to compose. If none comply, it uses the base class method to compose. It attempts to compose from the rightmost to leftmost. By doing so, the harder-to-model devices (typically printers, which are on the right) get composed first.

If you request to optimize for size, KcsXformSeq detaches all of the original list. After optimizing for size, the only way to regenerate the original list is to build it again.

Composition

The KcsXformSeq class uses the compose()() method to implement optimization. Since the KcsXformSeq class is a KcsXform derivative, you can generate one KcsTechUCP that represents the complete connection. This offers performance and quality advantages.

Evaluation

Evaluation of a KcsXformSeq instance is done with either the optimized or non-optimized technique.

Optimized evaluation uses the composed transformation it constructed when told to optimize. It keeps a pointer to that optimized transformation in its private section. When asked to evaluate, it passes the information down to the optimized transformation.

Unoptimized evaluation is used when the sequence is not optimized. This implementation evaluates the data through the list of transformations sequentially. Between transformations, a buffer is used to hold the temporary calculations. The first step evaluates from the source buffer, while the last step evaluates into the destination buffer.

Up to two different extra buffers are used between non-endpoint transformations, depending on the layout of the data. They are swapped between eval()()s. If the composition of the transformations is different (for example, chunky and planar), two buffers are needed. If the implementation did not use this technique, the data from one complete pixel (or component set) overrides a different (set of) pixel. The eval()() method always alternates between two buffer pointers. Both buffer pointers point to the same buffer if an output buffer for a transformation is compatible with the input buffor for the next transformation. This can be optimized further if all buffer layouts describe a buffer that is compatible with the destination buffer supplied by the caller. In this case, the buffer pointers point to the destination buffer described. And if the caller is using the same buffer for source and destination, everything ultimately uses one buffer. Such buffers are KcsMemoryBlocks that can be resized.

Validation

Each time a connection is made, it is validated against a set of rules defined in thisKcsXformSeq class. The rules use the current set of attributes as well as the current state of all of the transformations in the connection.

If the sequence rules pass, the sequence passes itself down to all the validation methods of each KcsXform in the list. In this way, all KcsXforms are allowed to determine if a connection can be made. If an error occurs in any single KcsXform, the connection is refused.

The List

The list of transformations is represented by a memory block of pointers to KcsXforms. The size of the block is incremented by a constant each time the current block fills with pointers. A few methods access and edit the list.

Note that a NULL parent starts the list based on this sequence. You must pass the last parent found into the next call to getNextXform()() and use the same object for invocations of this method. getNextXform()() returns KCS_END_OF_XFORMS when it reaches the end of the transformations in the sequence. All getNextXform()() calls are sequential. Any sharing of an object must take this into account. Otherwise, if the calls to getNextXform()() are not synchronized, two different results may occur. getNextXform()() works correctly when called on a sequence that is a part of another sequence: it runs through that subsequence only.

For example, given sequence A (a->B->e) and sequence B (c->d) where a, c, d, and e are primitive transformation types: A->GetNext()(). If GetNextXform()() is called (starting with a NULL parent **) until it returns KCS_END_OF_SEQUENCE, it returns transformations in the following order: a, c, d, e, B->GetNext()(). If called (starting with a NULL parent **) until it returns KCS_END_OF_SEQUENCE, it returns transformations in the following order: c, d. It also skips over all sequences of 0 transformations as if they are not even there.