Code

create/destroy the cairo_t for all items to render into (currently used only in outli...
[inkscape.git] / src / display / nr-arena-image.cpp
index ee566d2dceb90a8b0a749c857ddd017a36090d95..e187c331f43c00c386e8246871d51cfcaa335f0d 100644 (file)
  */
 
 #include <libnr/nr-compose-transform.h>
+#include <libnr/nr-blit.h>
 #include "../prefs-utils.h"
 #include "nr-arena-image.h"
+#include "style.h"
+#include "display/nr-arena.h"
+#include "display/nr-filter.h"
+#include "display/nr-filter-gaussian.h"
+#include <livarot/Path.h>
+#include <livarot/Shape.h>
+#include "sp-filter.h"
+#include "sp-gaussian-blur.h"
 
 int nr_arena_image_x_sample = 1;
 int nr_arena_image_y_sample = 1;
@@ -24,12 +33,15 @@ int nr_arena_image_y_sample = 1;
  *
  */
 
+// defined in nr-arena-shape.cpp
+void nr_pixblock_render_shape_mask_or(NRPixBlock &m, Shape *theS);
+
 static void nr_arena_image_class_init (NRArenaImageClass *klass);
 static void nr_arena_image_init (NRArenaImage *image);
 static void nr_arena_image_finalize (NRObject *object);
 
 static unsigned int nr_arena_image_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
-static unsigned int nr_arena_image_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
+static unsigned int nr_arena_image_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
 static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, NR::Point p, double delta, unsigned int sticky);
 
 static NRArenaItemClass *parent_class;
@@ -79,6 +91,8 @@ nr_arena_image_init (NRArenaImage *image)
        image->height = 256.0;
 
        nr_matrix_set_identity (&image->grid2px);
+
+       image->style = 0;
 }
 
 static void
@@ -130,6 +144,12 @@ nr_arena_image_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int
                bbox.y0 = image->y;
                bbox.x1 = image->x + image->width;
                bbox.y1 = image->y + image->height;
+
+               image->c00 = (NR::Point(bbox.x0, bbox.y0) * gc->transform);
+               image->c01 = (NR::Point(bbox.x0, bbox.y1) * gc->transform);
+               image->c10 = (NR::Point(bbox.x1, bbox.y0) * gc->transform);
+               image->c11 = (NR::Point(bbox.x1, bbox.y1) * gc->transform);
+
                nr_rect_d_matrix_transform (&bbox, &bbox, &gc->transform);
 
                item->bbox.x0 = (int) floor (bbox.x0);
@@ -152,27 +172,14 @@ nr_arena_image_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int
 #define b2i (image->grid2px)
 
 static unsigned int
-nr_arena_image_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
+nr_arena_image_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
 {
        nr_arena_image_x_sample = prefs_get_int_attribute ("options.bitmapoversample", "value", 1);
        nr_arena_image_y_sample = nr_arena_image_x_sample;
 
-       NRArenaImage *image = NR_ARENA_IMAGE (item);
-
-       if (!image->px) return item->state;
-
-       guint32 Falpha = item->opacity;
-       if (Falpha < 1) return item->state;
+       bool outline = (item->arena->rendermode == RENDERMODE_OUTLINE);
 
-       unsigned char * dpx = NR_PIXBLOCK_PX (pb);
-       const int drs = pb->rs;
-       const int dw = pb->area.x1 - pb->area.x0;
-       const int dh = pb->area.y1 - pb->area.y0;
-
-       unsigned char * spx = image->px;
-       const int srs = image->pxrs;
-       const int sw = image->pxw;
-       const int sh = image->pxh;
+       NRArenaImage *image = NR_ARENA_IMAGE (item);
 
        NR::Matrix d2s;
 
@@ -183,23 +190,78 @@ nr_arena_image_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigne
        d2s[4] = b2i[0] * pb->area.x0 + b2i[2] * pb->area.y0 + b2i[4];
        d2s[5] = b2i[1] * pb->area.x0 + b2i[3] * pb->area.y0 + b2i[5];
 
-       if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) {
-               /* fixme: This is not implemented yet (Lauris) */
-               /* nr_R8G8B8_R8G8B8_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample); */
-       } else if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
-               nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample);
-       } else if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
-
-               //FIXME: The _N_N_N_ version gives a gray border around images, see bug 906376
-               // This mode is only used when exporting, screen rendering always has _P_P_P_, so I decided to simply replace it for now
-               // Feel free to propose a better fix
-
-               //nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample);
-               nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample);
+       if (!outline) {
+
+               if (!image->px) return item->state;
+
+               guint32 Falpha = item->opacity;
+               if (Falpha < 1) return item->state;
+
+               unsigned char * dpx = NR_PIXBLOCK_PX (pb);
+               const int drs = pb->rs;
+               const int dw = pb->area.x1 - pb->area.x0;
+               const int dh = pb->area.y1 - pb->area.y0;
+
+               unsigned char * spx = image->px;
+               const int srs = image->pxrs;
+               const int sw = image->pxw;
+               const int sh = image->pxh;
+
+               if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) {
+                       /* fixme: This is not implemented yet (Lauris) */
+                       /* nr_R8G8B8_R8G8B8_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample); */
+               } else if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
+                       nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample);
+               } else if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
+
+                       //FIXME: The _N_N_N_ version gives a gray border around images, see bug 906376
+                       // This mode is only used when exporting, screen rendering always has _P_P_P_, so I decided to simply replace it for now
+                       // Feel free to propose a better fix
+
+                       //nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample);
+                       nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample);
+               }
+
+               pb->empty = FALSE;
+
+       } else { // outline; draw a rect instead
+
+               Path*  thePath = new Path;
+               thePath->SetBackData (false);
+               thePath->Reset ();
+
+               thePath->MoveTo (image->c00);
+               // the box
+               thePath->LineTo (image->c10);
+               thePath->LineTo (image->c11);
+               thePath->LineTo (image->c01);
+               thePath->LineTo (image->c00);
+               // the diagonals
+               thePath->LineTo (image->c11);
+               thePath->MoveTo (image->c10);
+               thePath->LineTo (image->c01);
+
+               // livarot black magic - exactly this sequnce of conversions to get stable rendering of the shape
+               thePath->Convert(1.0);
+               Shape* theShape = new Shape;
+               thePath->Stroke(theShape, true, 0.25, join_pointy, butt_straight, 5);
+               Shape* theShape1 = new Shape;
+               theShape1->ConvertToShape(theShape, fill_nonZero);
+
+               NRPixBlock m;
+               nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
+               m.visible_area = pb->visible_area; 
+               nr_pixblock_render_shape_mask_or(m, theShape1);
+               m.empty = FALSE;
+               guint32 rgba = prefs_get_int_attribute("options.wireframecolors", "images", 0xff0000ff);
+               nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
+               pb->empty = FALSE;
+               nr_pixblock_release(&m);
+               delete theShape;
+               delete theShape1;
+               delete thePath;
        }
 
-       pb->empty = FALSE;
-
        return item->state;
 }
 
@@ -256,3 +318,53 @@ nr_arena_image_set_geometry (NRArenaImage *image, double x, double y, double wid
        nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE);
 }
 
+void nr_arena_image_set_style (NRArenaImage *image, SPStyle *style)
+{
+  g_return_if_fail(image != NULL);
+  g_return_if_fail(NR_IS_ARENA_IMAGE(image));
+
+  if (style) sp_style_ref(style);
+  if (image->style) sp_style_unref(image->style);
+  image->style = style;
+
+  //if there is a filter set for this group
+  if (style && style->filter.set && style->filter.filter) {
+  
+        image->filter = new NR::Filter();
+        image->filter->set_x(style->filter.filter->x);
+        image->filter->set_y(style->filter.filter->y);
+        image->filter->set_width(style->filter.filter->width);
+        image->filter->set_height(style->filter.filter->height);
+        
+        //go through all SP filter primitives
+        for(int i=0; i<style->filter.filter->_primitive_count; i++)
+        {
+            SPFilterPrimitive *primitive = style->filter.filter->_primitives[i];
+            //if primitive is gaussianblur
+//            if(SP_IS_GAUSSIANBLUR(primitive))
+            {
+                NR::FilterGaussian * gaussian = (NR::FilterGaussian *) image->filter->add_primitive(NR::NR_FILTER_GAUSSIANBLUR);
+                SPGaussianBlur * spblur = SP_GAUSSIANBLUR(primitive);
+                float num = spblur->stdDeviation.getNumber();
+                if( num>=0.0 )
+                {
+                    float optnum = spblur->stdDeviation.getOptNumber();
+                    if( optnum>=0.0 )
+                        gaussian->set_deviation((double) num, (double) optnum);
+                    else
+                        gaussian->set_deviation((double) num);
+                }
+            }
+        }
+    }
+    else
+    {
+        //no filter set for this group
+        image->filter = NULL;
+    }
+
+  if (style && style->enable_background.set
+      && style->enable_background.value == SP_CSS_BACKGROUND_NEW) {
+    image->background_new = true;
+  }
+}