bcababf8e2679127111ef771705727aa4d6e90f0
1 #define EXTENSION_INTERNAL_PDF_LATEX_RENDERER_CPP
3 /** \file
4 * Rendering LaTeX file (pdf+latex output)
5 */
6 /*
7 * Authors:
8 * Johan Engelen <goejendaagh@zonnet.nl>
9 * Miklos Erdelyi <erdelyim@gmail.com>
10 *
11 * Copyright (C) 2006-2010 Authors
12 *
13 * Licensed under GNU GPL
14 */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
20 #ifndef PANGO_ENABLE_BACKEND
21 #define PANGO_ENABLE_BACKEND
22 #endif
24 #ifndef PANGO_ENABLE_ENGINE
25 #define PANGO_ENABLE_ENGINE
26 #endif
29 #include <signal.h>
30 #include <errno.h>
32 #include "libnr/nr-rect.h"
33 #include "libnrtype/Layout-TNG.h"
34 #include <2geom/transforms.h>
35 #include <2geom/pathvector.h>
37 #include <glib/gmem.h>
39 #include <glibmm/i18n.h>
40 #include "display/nr-arena.h"
41 #include "display/nr-arena-item.h"
42 #include "display/nr-arena-group.h"
43 #include "display/curve.h"
44 #include "display/canvas-bpath.h"
45 #include "sp-item.h"
46 #include "sp-item-group.h"
47 #include "style.h"
48 #include "marker.h"
49 #include "sp-linear-gradient.h"
50 #include "sp-radial-gradient.h"
51 #include "sp-root.h"
52 #include "sp-use.h"
53 #include "sp-text.h"
54 #include "sp-flowtext.h"
55 #include "sp-mask.h"
56 #include "sp-clippath.h"
58 #include <unit-constants.h>
59 #include "helper/png-write.h"
60 #include "helper/pixbuf-ops.h"
62 #include "pdflatex-renderer.h"
63 #include "extension/system.h"
65 #include "io/sys.h"
67 #include <cairo.h>
69 // include support for only the compiled-in surface types
70 #ifdef CAIRO_HAS_PDF_SURFACE
71 #include <cairo-pdf.h>
72 #endif
73 #ifdef CAIRO_HAS_PS_SURFACE
74 #include <cairo-ps.h>
75 #endif
77 //#define TRACE(_args) g_printf _args
78 #define TRACE(_args)
79 //#define TEST(_args) _args
80 #define TEST(_args)
82 // FIXME: expose these from sp-clippath/mask.cpp
83 struct SPClipPathView {
84 SPClipPathView *next;
85 unsigned int key;
86 NRArenaItem *arenaitem;
87 NRRect bbox;
88 };
90 struct SPMaskView {
91 SPMaskView *next;
92 unsigned int key;
93 NRArenaItem *arenaitem;
94 NRRect bbox;
95 };
97 namespace Inkscape {
98 namespace Extension {
99 namespace Internal {
101 PDFLaTeXRenderer::PDFLaTeXRenderer(void)
102 : _m(Geom::identity())
103 {}
105 PDFLaTeXRenderer::~PDFLaTeXRenderer(void)
106 {
107 /* restore default signal handling for SIGPIPE */
108 #if !defined(_WIN32) && !defined(__WIN32__)
109 (void) signal(SIGPIPE, SIG_DFL);
110 #endif
112 return;
113 }
115 void
116 PDFLaTeXRenderer::sp_group_render(SPItem *item)
117 {
118 SPGroup *group = SP_GROUP(item);
120 GSList *l = g_slist_reverse(group->childList(false));
121 while (l) {
122 SPObject *o = SP_OBJECT (l->data);
123 if (SP_IS_ITEM(o)) {
124 renderItem (SP_ITEM (o));
125 }
126 l = g_slist_remove (l, o);
127 }
128 }
130 void
131 PDFLaTeXRenderer::sp_use_render(SPItem *item)
132 {
133 /*
134 bool translated = false;
135 SPUse *use = SP_USE(item);
137 if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) {
138 Geom::Matrix tp(Geom::Translate(use->x.computed, use->y.computed));
139 ctx->pushState();
140 ctx->transform(&tp);
141 translated = true;
142 }
144 if (use->child && SP_IS_ITEM(use->child)) {
145 renderItem(SP_ITEM(use->child));
146 }
148 if (translated) {
149 ctx->popState();
150 }
151 */
152 }
154 void
155 PDFLaTeXRenderer::sp_text_render(SPItem *item)
156 {
157 SPText *group = SP_TEXT (item);
158 /*
159 implement
160 */
161 }
163 void
164 PDFLaTeXRenderer::sp_flowtext_render(SPItem *item)
165 {
166 SPFlowtext *group = SP_FLOWTEXT(item);
167 /*
168 implement
169 */
170 }
172 void
173 PDFLaTeXRenderer::sp_root_render(SPItem *item)
174 {
175 SPRoot *root = SP_ROOT(item);
177 /*
178 if (!ctx->getCurrentState()->has_overflow && SP_OBJECT(item)->parent)
179 ctx->addClippingRect(root->x.computed, root->y.computed, root->width.computed, root->height.computed);
181 ctx->pushState();
182 setStateForItem(ctx, item);
183 Geom::Matrix tempmat (root->c2p);
184 ctx->transform(&tempmat);
185 sp_group_render(item, ctx);
186 ctx->popState();
187 */
188 }
190 void
191 PDFLaTeXRenderer::sp_item_invoke_render(SPItem *item)
192 {
193 // Check item's visibility
194 if (item->isHidden()) {
195 return;
196 }
198 if (SP_IS_ROOT(item)) {
199 TRACE(("root\n"));
200 return sp_root_render(item);
201 } else if (SP_IS_GROUP(item)) {
202 TRACE(("group\n"));
203 return sp_group_render(item);
204 } else if (SP_IS_USE(item)) {
205 TRACE(("use begin---\n"));
206 sp_use_render(item);
207 TRACE(("---use end\n"));
208 } else if (SP_IS_TEXT(item)) {
209 TRACE(("text\n"));
210 return sp_text_render(item);
211 } else if (SP_IS_FLOWTEXT(item)) {
212 TRACE(("flowtext\n"));
213 return sp_flowtext_render(item);
214 }
215 // We are not interested in writing the other SPItem types to LaTeX
216 }
218 void
219 PDFLaTeXRenderer::setStateForItem(SPItem const *item)
220 {
221 /*
222 SPStyle const *style = SP_OBJECT_STYLE(item);
223 ctx->setStateForStyle(style);
225 CairoRenderState *state = ctx->getCurrentState();
226 state->clip_path = item->clip_ref->getObject();
227 state->mask = item->mask_ref->getObject();
228 state->item_transform = Geom::Matrix (item->transform);
230 // If parent_has_userspace is true the parent state's transform
231 // has to be used for the mask's/clippath's context.
232 // This is so because we use the image's/(flow)text's transform for positioning
233 // instead of explicitly specifying it and letting the renderer do the
234 // transformation before rendering the item.
235 if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item) || SP_IS_IMAGE(item))
236 state->parent_has_userspace = TRUE;
237 TRACE(("setStateForItem opacity: %f\n", state->opacity));
238 */
239 }
241 void
242 PDFLaTeXRenderer::renderItem(SPItem *item)
243 {
244 /*
245 ctx->pushState();
246 setStateForItem(ctx, item);
248 CairoRenderState *state = ctx->getCurrentState();
249 state->need_layer = ( state->mask || state->clip_path || state->opacity != 1.0 );
251 // Draw item on a temporary surface so a mask, clip path, or opacity can be applied to it.
252 if (state->need_layer) {
253 state->merge_opacity = FALSE;
254 ctx->pushLayer();
255 }
256 Geom::Matrix tempmat (item->transform);
257 ctx->transform(&tempmat);
258 sp_item_invoke_render(item, ctx);
260 if (state->need_layer)
261 ctx->popLayer();
263 ctx->popState();
264 */
265 }
267 bool
268 PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *base)
269 {
270 // The boundingbox calculation here should be exactly the same as the one by CairoRenderer::setupDocument !
272 if (!base)
273 base = SP_ITEM(sp_document_root(doc));
275 NRRect d;
276 if (pageBoundingBox) {
277 d.x0 = d.y0 = 0;
278 d.x1 = ceil(sp_document_width(doc));
279 d.y1 = ceil(sp_document_height(doc));
280 } else {
281 sp_item_invoke_bbox(base, &d, sp_item_i2d_affine(base), TRUE, SPItem::RENDERING_BBOX);
282 }
284 // convert from px to pt
285 d.x0 *= PT_PER_PX;
286 d.x1 *= PT_PER_PX;
287 d.y0 *= PT_PER_PX;
288 d.y1 *= PT_PER_PX;
290 double _width = d.x1-d.x0;
291 double _height = d.y1-d.y0;
293 if (!pageBoundingBox)
294 {
295 double high = sp_document_height(doc);
296 high *= PT_PER_PX;
298 transform( Geom::Translate( -d.x0 * PX_PER_PT,
299 (d.y1 - high) * PX_PER_PT ) );
300 }
302 return true;
303 }
305 void
306 PDFLaTeXRenderer::transform(Geom::Matrix const &transform)
307 {
308 _m *= transform;
309 }
312 /*
313 #include "macros.h" // SP_PRINT_*
315 // Apply an SVG clip path
316 void
317 PDFLaTeXRenderer::applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp)
318 {
319 g_assert( ctx != NULL && ctx->_is_valid );
321 if (cp == NULL)
322 return;
324 CairoRenderContext::CairoRenderMode saved_mode = ctx->getRenderMode();
325 ctx->setRenderMode(CairoRenderContext::RENDER_MODE_CLIP);
327 Geom::Matrix saved_ctm;
328 if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) {
329 //SP_PRINT_DRECT("clipd", cp->display->bbox);
330 NRRect clip_bbox(cp->display->bbox);
331 Geom::Matrix t(Geom::Scale(clip_bbox.x1 - clip_bbox.x0, clip_bbox.y1 - clip_bbox.y0));
332 t[4] = clip_bbox.x0;
333 t[5] = clip_bbox.y0;
334 t *= ctx->getCurrentState()->transform;
335 ctx->getTransform(&saved_ctm);
336 ctx->setTransform(&t);
337 }
339 TRACE(("BEGIN clip\n"));
340 SPObject *co = SP_OBJECT(cp);
341 for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
342 if (SP_IS_ITEM(child)) {
343 SPItem *item = SP_ITEM(child);
345 // combine transform of the item in clippath and the item using clippath:
346 Geom::Matrix tempmat (item->transform);
347 tempmat = tempmat * (ctx->getCurrentState()->item_transform);
349 // render this item in clippath
350 ctx->pushState();
351 ctx->transform(&tempmat);
352 setStateForItem(ctx, item);
353 sp_item_invoke_render(item, ctx);
354 ctx->popState();
355 }
356 }
357 TRACE(("END clip\n"));
359 // do clipping only if this was the first call to applyClipPath
360 if (ctx->getClipMode() == CairoRenderContext::CLIP_MODE_PATH
361 && saved_mode == CairoRenderContext::RENDER_MODE_NORMAL)
362 cairo_clip(ctx->_cr);
364 if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX)
365 ctx->setTransform(&saved_ctm);
367 ctx->setRenderMode(saved_mode);
368 }
370 // Apply an SVG mask
371 void
372 PDFLaTeXRenderer::applyMask(CairoRenderContext *ctx, SPMask const *mask)
373 {
374 g_assert( ctx != NULL && ctx->_is_valid );
376 if (mask == NULL)
377 return;
379 //SP_PRINT_DRECT("maskd", &mask->display->bbox);
380 NRRect mask_bbox(mask->display->bbox);
381 // TODO: should the bbox be transformed if maskUnits != userSpaceOnUse ?
382 if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) {
383 Geom::Matrix t(Geom::Scale(mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0));
384 t[4] = mask_bbox.x0;
385 t[5] = mask_bbox.y0;
386 t *= ctx->getCurrentState()->transform;
387 ctx->setTransform(&t);
388 }
390 // Clip mask contents... but...
391 // The mask's bounding box is the "geometric bounding box" which doesn't allow for
392 // filters which extend outside the bounding box. So don't clip.
393 // ctx->addClippingRect(mask_bbox.x0, mask_bbox.y0, mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0);
395 ctx->pushState();
397 TRACE(("BEGIN mask\n"));
398 SPObject *co = SP_OBJECT(mask);
399 for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
400 if (SP_IS_ITEM(child)) {
401 SPItem *item = SP_ITEM(child);
402 renderItem(ctx, item);
403 }
404 }
405 TRACE(("END mask\n"));
407 ctx->popState();
408 }
409 */
411 } /* namespace Internal */
412 } /* namespace Extension */
413 } /* namespace Inkscape */
415 #undef TRACE
417 /* End of GNU GPL code */
419 /*
420 Local Variables:
421 mode:c++
422 c-file-style:"stroustrup"
423 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
424 indent-tabs-mode:nil
425 fill-column:99
426 End:
427 */
428 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :