Here is a simple Observer-style separation of document traversal and output-specific rendering. If people don't disagree with this too much, I can spend more than 5 minutes on it and flesh this out further.
If this seems reasonable, the first Context would naturally seem to be wrapped around Cairo. This would be very cool. :)
bob
#ifndef __RENDER_H__ #define __RENDER_H__
class RenderInterpreter;
/** * The base class for all rendering output types. This class * follows the Observer model, where there is a single * subscriber to all of the Target's methods. In this case, the target * is the RenderInterpreter, and the observer is the RenderContext. Inherit * from this and overload the methods to provide the format-specific * rendering for each of the callback types. * * An example of how to call this: * * class PDFOutput : public RenderContext * { * * Overload all of RenderContext's methods..... * * bool myOutputMethod() { * RenderInterpreter ri(*this); * if (!ri.render(document)) { * //error message * return false; * } * return true; * } * * }; * */ class RendererContext { public:
virtual bool drawRect(double width, double height, const Style &style);
virtual bool drawEllipse(double x0, double y0, double x1, double y1, double major, double minor, const Style &style);
virtual bool drawPath(blah......);
};
/** * * This is the class that traverses the SPDocument's object tree, * reading all of the necessary information to render the image with * a given set of graphic primitives. * * As the tree is descended, all of the nested transform calculations * are performed, and style inheritances are analyzed. This allows * the RenderContexts to only worry about absolute coordinates and * styles, and keep their implementations simple. * */ class RenderInterpreter { public:
RenderInterpreter(const RenderContext &context);
bool render(const SPDOcument *doc){ /** * Traverse the tree, calling the primitive drawing * methods in the context */ return true; }
private:
RenderContext &context;
};
#endif /* __RENDER_H__ */