Code

remove memory boundries on bitmap renderer, optimize memory usage
[inkscape.git] / src / extension / internal / cairo-renderer.cpp
index da88a5eae779307c1b4f98fd985085a7a8bd345e..bc3c6c4848b6c9fbd795e4e8cb9c2a5baae0af89 100644 (file)
@@ -1,11 +1,11 @@
-#define __SP_CAIRO_RENDERER_C__
-
 /** \file
  * Rendering with Cairo.
  */
 /*
  * Author:
  *   Miklos Erdelyi <erdelyim@gmail.com>
+ *   Jon A. Cruz <jon@joncruz.org>
+ *   Abhishek Sharma
  *
  * Copyright (C) 2006 Miklos Erdelyi
  *
@@ -29,6 +29,7 @@
 #include <errno.h>
 
 #include "libnr/nr-rect.h"
+#include "libnrtype/Layout-TNG.h"
 #include <2geom/transforms.h>
 #include <2geom/pathvector.h>
 
@@ -102,6 +103,7 @@ namespace Extension {
 namespace Internal {
 
 CairoRenderer::CairoRenderer(void)
+  : _omitText(false)
 {}
 
 CairoRenderer::~CairoRenderer(void)
@@ -184,19 +186,37 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
 
     if (!shape->curve) return;
 
-    sp_item_invoke_bbox(item, &pbox, Geom::identity(), TRUE);
+    item->invoke_bbox( &pbox, Geom::identity(), TRUE);
 
     SPStyle* style = SP_OBJECT_STYLE (item);
 
     Geom::PathVector const & pathv = shape->curve->get_pathvector();
+    if (pathv.empty()) return;
 
     ctx->renderPathVector(pathv, style, &pbox);
 
-    for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
-      // START position
-        for (int i = 0; i < 2; i++) {  // SP_MARKER_LOC and SP_MARKER_LOC_START
-            if ( shape->marker[i] ) {
-                SPMarker* marker = SP_MARKER (shape->marker[i]);
+    // START marker
+    for (int i = 0; i < 2; i++) {  // SP_MARKER_LOC and SP_MARKER_LOC_START
+        if ( shape->marker[i] ) {
+            SPMarker* marker = SP_MARKER (shape->marker[i]);
+            Geom::Matrix tr;
+            if (marker->orient_auto) {
+                tr = sp_shape_marker_get_transform_at_start(pathv.begin()->front());
+            } else {
+                tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(pathv.begin()->front().pointAt(0));
+            }
+            sp_shape_render_invoke_marker_rendering(marker, tr, style, ctx);
+        }
+    }
+    // MID marker
+    for (int i = 0; i < 3; i += 2) {  // SP_MARKER_LOC and SP_MARKER_LOC_MID
+        if ( !shape->marker[i] ) continue;
+        SPMarker* marker = SP_MARKER (shape->marker[i]);
+        for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
+            // START position
+            if ( path_it != pathv.begin() 
+                 && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there
+            {
                 Geom::Matrix tr;
                 if (marker->orient_auto) {
                     tr = sp_shape_marker_get_transform_at_start(path_it->front());
@@ -205,11 +225,8 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
                 }
                 sp_shape_render_invoke_marker_rendering(marker, tr, style, ctx);
             }
-        }
-
-      // MID position
-        for (int i = 0; i < 3; i += 2) {  // SP_MARKER_LOC and SP_MARKER_LOC_MID
-            if ( shape->marker[i] && (path_it->size_default() > 1) ) {
+            // MID position
+            if (path_it->size_default() > 1) {
                 Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
                 Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
                 while (curve_it2 != path_it->end_default())
@@ -217,9 +234,6 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
                     /* Put marker between curve_it1 and curve_it2.
                      * Loop to end_default (so including closing segment), because when a path is closed,
                      * there should be a midpoint marker between last segment and closing straight line segment */
-
-                    SPMarker* marker = SP_MARKER (shape->marker[i]);
-
                     Geom::Matrix tr;
                     if (marker->orient_auto) {
                         tr = sp_shape_marker_get_transform(*curve_it1, *curve_it2);
@@ -233,32 +247,43 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
                     ++curve_it2;
                 }
             }
-        }
-
-      // END position
-        for (int i = 0; i < 4; i += 3) {  // SP_MARKER_LOC and SP_MARKER_LOC_END
-            if ( shape->marker[i] ) {
-                SPMarker* marker = SP_MARKER (shape->marker[i]);
-
-                /* Get reference to last curve in the path.
-                 * For moveto-only path, this returns the "closing line segment". */
-                unsigned int index = path_it->size_default();
-                if (index > 0) {
-                    index--;
-                }
-                Geom::Curve const &lastcurve = (*path_it)[index];
-
+            // END position
+            if ( path_it != (pathv.end()-1) && !path_it->empty()) {
+                Geom::Curve const &lastcurve = path_it->back_default();
                 Geom::Matrix tr;
                 if (marker->orient_auto) {
                     tr = sp_shape_marker_get_transform_at_end(lastcurve);
                 } else {
                     tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(lastcurve.pointAt(1));
                 }
-
                 sp_shape_render_invoke_marker_rendering(marker, tr, style, ctx);
             }
         }
     }
+    // END marker
+    for (int i = 0; i < 4; i += 3) {  // SP_MARKER_LOC and SP_MARKER_LOC_END
+        if ( shape->marker[i] ) {
+            SPMarker* marker = SP_MARKER (shape->marker[i]);
+
+            /* Get reference to last curve in the path.
+             * For moveto-only path, this returns the "closing line segment". */
+            Geom::Path const &path_last = pathv.back();
+            unsigned int index = path_last.size_default();
+            if (index > 0) {
+                index--;
+            }
+            Geom::Curve const &lastcurve = path_last[index];
+
+            Geom::Matrix tr;
+            if (marker->orient_auto) {
+                tr = sp_shape_marker_get_transform_at_end(lastcurve);
+            } else {
+                tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(lastcurve.pointAt(1));
+            }
+
+            sp_shape_render_invoke_marker_rendering(marker, tr, style, ctx);
+        }
+    }
 }
 
 static void sp_group_render(SPItem *item, CairoRenderContext *ctx)
@@ -425,10 +450,25 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx)
 
     // Get the bounding box of the selection in document coordinates.
     Geom::OptRect bbox = 
-           item->getBounds(sp_item_i2d_affine(item), SPItem::RENDERING_BBOX);
+           item->getBounds(item->i2d_affine(), SPItem::RENDERING_BBOX);
+
+    // no bbox, e.g. empty group
+       if (!bbox) {
+        return;
+    }
+
+    Geom::Rect docrect(Geom::Rect(Geom::Point(0, 0), SP_OBJECT(item)->document->getDimensions()));
+    Geom::Rect bboxrect(Geom::Rect(Geom::Point(bbox->min()[Geom::X], bbox->min()[Geom::Y]), Geom::Point(bbox->max()[Geom::X], bbox->max()[Geom::Y])));
 
-    if (!bbox) // no bbox, e.g. empty group
+    Geom::OptRect _bbox = Geom::intersect(docrect, bboxrect);
+
+       // assign the object dimension clipped on the document, no need to draw on area not on canvas
+    bbox = _bbox;
+
+    // no bbox, e.g. empty group
+    if (!bbox) {
         return;
+    }
 
     // The width and height of the bitmap in pixels
     unsigned width = (unsigned) floor ((bbox->max()[Geom::X] - bbox->min()[Geom::X]) * (res / PX_PER_IN));
@@ -456,7 +496,7 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx)
                                  (Geom::Matrix)(Geom::Translate (shift_x, shift_y));
 
     // ctx matrix already includes item transformation. We must substract.
-    Geom::Matrix t_item =  sp_item_i2d_affine (item);
+    Geom::Matrix t_item =  item->i2d_affine ();
     Geom::Matrix t = t_on_document * t_item.inverse();
 
     // Do the export
@@ -545,6 +585,11 @@ CairoRenderer::setStateForItem(CairoRenderContext *ctx, SPItem const *item)
 void
 CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item)
 {
+    if ( _omitText && (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) ) {
+        // skip text if _omitText is true
+        return;
+    }
+
     ctx->pushState();
     setStateForItem(ctx, item);
 
@@ -569,18 +614,21 @@ CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item)
 bool
 CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool pageBoundingBox, SPItem *base)
 {
+// PLEASE note when making changes to the boundingbox and transform calculation, corresponding changes should be made to PDFLaTeXRenderer::setupDocument !!!
+
     g_assert( ctx != NULL );
 
-    if (!base)
-        base = SP_ITEM(sp_document_root(doc));
+    if (!base) {
+        base = SP_ITEM(doc->getRoot());
+    }
 
     NRRect d;
     if (pageBoundingBox) {
         d.x0 = d.y0 = 0;
-        d.x1 = ceil(sp_document_width(doc));
-        d.y1 = ceil(sp_document_height(doc));
+        d.x1 = doc->getWidth();
+        d.y1 = doc->getHeight();
     } else {
-        sp_item_invoke_bbox(base, &d, sp_item_i2d_affine(base), TRUE, SPItem::RENDERING_BBOX);
+        base->invoke_bbox( &d, base->i2d_affine(), TRUE, SPItem::RENDERING_BBOX);
     }
 
     if (ctx->_vector_based_target) {
@@ -600,7 +648,7 @@ CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool page
 
     if (ret && !pageBoundingBox)
     {
-        double high = sp_document_height(doc);
+        double high = doc->getHeight();
         if (ctx->_vector_based_target)
             high *= PT_PER_PX;
 
@@ -640,7 +688,7 @@ CairoRenderer::applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp)
 
     TRACE(("BEGIN clip\n"));
     SPObject *co = SP_OBJECT(cp);
-    for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
+    for ( SPObject *child = co->firstChild() ; child; child = child->getNext() ) {
         if (SP_IS_ITEM(child)) {
             SPItem *item = SP_ITEM(child);
 
@@ -698,7 +746,7 @@ CairoRenderer::applyMask(CairoRenderContext *ctx, SPMask const *mask)
 
     TRACE(("BEGIN mask\n"));
     SPObject *co = SP_OBJECT(mask);
-    for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
+    for ( SPObject *child = co->firstChild() ; child; child = child->getNext() ) {
         if (SP_IS_ITEM(child)) {
             SPItem *item = SP_ITEM(child);
             renderItem(ctx, item);
@@ -781,4 +829,4 @@ calculatePreserveAspectRatio(unsigned int aspect_align, unsigned int aspect_clip
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :