Skip to main content
Skip table of contents

Monitoring progress or aborting (ITransform)


Introduction

In response to a customer request, Mako 4.7.3 and later implements a mechanism to signal an abort to a transform process (using ITransform), and another to enable its progress to be monitored.

Aborting an ITransform

An IAbortPtr object has been added to CTransformState. This structure is passed to the various handlers in ITransform and ICustomTransform::IImplementation . The handlers can call CHECKABORT() to check if an abort has been signaled. This throws an exception if an abort was requested. Numerous calls to the CHECKABORT() macro in the default handlers in CCustomTransform, CCustomTransform::CGenericImplementation and CTransformCommon for the convenience of the implementors. If a client creates their own handler then they should call the CHECKABORT() macro.

Also added to the work item API is ITPWorkItem::getHasAborted() and ITPWorkItem::getHasErrored() so that the caller that submitted the work item can distinguish between them. If an abort is encountered, it can rethrow that exception, so the abort signal is not lost.

Code Snippets

First, we can create an IAbort instance:

CPP
CTransformState state;
state.abort = IAbort::create();

And use it to signal an abort:

CPP
state.abort->signalAbort();

This is where these elements are implemented in the code example provided.

CPP
// Transform on a thread
CTransformState state;
state.abort = IAbort::create();
CTransformThread transformThreadInfo(jawsMako, content, state);

The last line passes the state into the thread implementation and is subsequently passed to the transform in the thread runner class:

CPP
IDOMNodePtr transformed = transform->transform(m_content, changed, true, m_state);

The example runs the transform in its own thread so that the main thread can monitor the keyboard, waiting for the user to press ESC. Should they do so, an abort is signaled:

CPP
// Wait for the worker thread to complete
while (!transformThreadInfo.aborted() && !transformThreadInfo.completed()) {
    if (_kbhit())
        {
            if (_getch() == 27) // ESC
                state.abort->signalAbort();
        }
}

Obtaining progress information from an ITransform

A new class, IProgressTick, allows a call back method to monitor the progress of a task. The callback can pass an integer (from 0 to maximum value) or a float (0.0 to 1.0) which represents the progress of a task. The task needs to call the tick() method to indicate progress. A value can be passed to the IProgressTick::create() method to specify an (estimated) maximum value for the integer progress count.

To implement progress monitoring of an ITransform, the following steps are needed:

  • Create a transform (in this example, using a custom transformation)
  • Create an IProgressTick instance
  • Create a monitor to record progress
  • Set the callback method to be called by the IProgressTick
  • Set the IProgressTick to be called by the transform.

In the example, these steps are coded as follows:

First we create a transform:

CPP
CShadingPatternTransformImplementation implementation(m_jawsMako);
ITransformPtr transform = ICustomTransform::create(m_jawsMako, &implementation);

Next we create an IProgressTick:

CPP
uint32 numNodes = countChildren(m_content) + 1; /* num of subnodes + this one */

IProgressTickPtr progressTick = IProgressTick::create(numNodes);

If you don't really need a callback for each node then, you can set an optional parameter (after the maximum value) that indicates the frequency in which the callback is invoked. For example we can set the frequency to 5 which means the callback is only invoked every 5 ticks. This can help minimize the effect of the callback on performance.

CPP
TickMonitorInt* mon = new TickMonitorInt();

This is the tick monitor class implementation:

CPP
class TickMonitorInt
{
public:
    TickMonitorInt()
    {
        last_val = 0;
    }
    std::vector<uint32> ticks;
    uint32              last_val;
};

Next we set the callback method to be called by IProgressTick:

CPP
progressTick->setCallback(progressCallbackInt, mon);

This is the progress tick callback implementation, which includes an updating the user on progress:

CPP
static void progressCallbackInt(void* priv, uint32 count, uint32 maxVal)
{
    TickMonitorInt* mon = (TickMonitorInt*)priv;

    mon->ticks.push_back(count);
    mon->last_val = count;
    
	globalMtx.lock();
    std::wcout << L"Node " << count << L" of " << maxVal << L"\r";
    if (count >= maxVal)
        std::wcout << std::endl;
    globalMtx.unlock();
}

The progress of the transformation is reported as a count from 1 to n, where n is the number of nodes on the page.

Finally:

CPP
transform->setProgressTick(progressTick);

The example puts these all these elements together.

Downloads

Source code

An example (makotransformer.cpp) can be found on GitHub. You can drop it into the makoapps folder of your Mako SDK distribution and build it in the same way as makoconverter.

This sample makes use of a custom transform that converts colors to gray, object by object. You can experiment with the attached file which was used for unit testing during development.

shadingalltypes100.pdf

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.