diff options
| author | Shlomi Fish <shlomif@shlomifish.org> | 2016-09-29 16:32:49 +0000 |
|---|---|---|
| committer | Shlomi Fish <shlomif@shlomifish.org> | 2016-09-29 16:32:49 +0000 |
| commit | f51ad5ea1ef1c96a93a64910cb263a360fc32d00 (patch) | |
| tree | 29626e107bf83f920304192ccacb3d538a4676e3 /src | |
| parent | Remove "== true" and trailing whitespace. (diff) | |
| parent | fix tabs in src/main-cmdlineact (diff) | |
| download | inkscape-f51ad5ea1ef1c96a93a64910cb263a360fc32d00.tar.gz inkscape-f51ad5ea1ef1c96a93a64910cb263a360fc32d00.zip | |
Merged.
(bzr r15100.1.23)
Diffstat (limited to 'src')
40 files changed, 916 insertions, 371 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9928f9694..3c4f28aa8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,9 +44,9 @@ set(sp_SRC sp-marker.cpp sp-mask.cpp sp-mesh-array.cpp + sp-mesh-gradient.cpp sp-mesh-patch.cpp sp-mesh-row.cpp - sp-mesh.cpp sp-metadata.cpp sp-missing-glyph.cpp sp-namedview.cpp @@ -134,9 +134,9 @@ set(sp_SRC sp-marker.h sp-mask.h sp-mesh-array.h + sp-mesh-gradient.h sp-mesh-patch.h sp-mesh-row.h - sp-mesh.h sp-metadata.h sp-missing-glyph.h sp-namedview.h diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 24a75de4c..a7625f4a1 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -13,6 +13,7 @@ #endif #include "display/cairo-utils.h" +#include <arpa/inet.h> #include <stdexcept> #include <glib/gstdio.h> @@ -1321,6 +1322,91 @@ guint32 argb32_from_rgba(guint32 in) return px; } + +/** + * Converts a pixbuf to a PNG data structure. + * For 8-but RGBA png, this is like copying. + * + */ +const guchar* pixbuf_to_png(guchar const**rows, guchar* px, int num_rows, int num_cols, int stride, int color_type, int bit_depth) +{ + int n_fields = 1 + (color_type&2) + (color_type&4)/4; + const guchar* new_data = (const guchar*)malloc((n_fields * bit_depth * num_rows * num_cols)/8 + 64); + char* ptr = (char*) new_data; + int pad=0; //used when we write image data smaller than one byte (for instance in black and white images where 1px = 1bit) + for(int row = 0; row < num_rows; ++row){ + rows[row] = (const guchar*)ptr; + for(int col = 0; col < num_cols; ++col){ + guint32 *pixel = reinterpret_cast<guint32*>(px + row*stride)+col; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + //this part should probably be rewritten as (a tested, working) big endian, using htons() and ntohs() + guint64 a = (*pixel & 0xff000000) >> 24; + guint64 b = (*pixel & 0x00ff0000) >> 16; + guint64 g = (*pixel & 0x0000ff00) >> 8; + guint64 r = (*pixel & 0x000000ff); + + //one of possible rgb to greyscale formulas. This one is called "luminance, "luminosity" or "luma" + guint16 gray = (guint16)((guint32)((0.2126*(r<<24) + 0.7152*(g<<24) + 0.0722*(b<<24)))>>16); + + if (!pad) *((guint64*)ptr)=0; + if (color_type & 2) { //RGB + // for 8bit->16bit transition, I take the FF -> FFFF convention (multiplication by 0x101). + // If you prefer FF -> FF00 (multiplication by 0x100), remove the <<8, <<24, <<40 and <<56 + if (color_type & 4) { //RGBA + if (bit_depth==8) + *((guint32*)ptr) = *pixel; + else + *((guint64*)ptr) = (guint64)((a<<56)+(a<<48)+(b<<40)+(b<<32)+(g<<24)+(g<<16)+(r<<8)+(r)); + } + else{ //no alpha + if(bit_depth==8) + *((guint32*)ptr) = ((*pixel)<<8)>>8; + else + *((guint64*)ptr) = (guint64)((b<<40)+(b<<32)+(g<<24)+(g<<16)+(r<<8)+r); + } + } else { //Grayscale + if(bit_depth==16) + *(guint16*)ptr= ((gray & 0xff00)>>8) + ((gray &0x00ff)<<8); + else *((guint16*)ptr) += guint16(((gray >> (16-bit_depth))<<pad) ); //note the "+=" + + if(color_type & 4) { //Alpha channel + if (bit_depth == 16) + *((guint32*)(ptr+2)) = a + (a<<8); + else + *((guint32*)(ptr)) += guint32((a << 8) >> (16 - bit_depth))<<(bit_depth + pad); + } + } + +#else + // I don't have any access to a big-endian machine to test this. It should still work with default export settings. + guint64 r = (*pixel & 0xff000000) >> 24; + guint64 g = (*pixel & 0x00ff0000) >> 16; + guint64 b = (*pixel & 0x0000ff00) >> 8; + guint64 a = (*pixel & 0x000000ff); + guint32 gray = (guint32)(0.2126*(r<<24) + 0.7152*(g<<24) + 0.0722*(b<<24)); + if(color_type & 2){ + if(bit_depth==8)*ptr = *pixel; else *ptr = (guint64)((r<<56)+(g<<40)+(b<<24)+(a<<8)); + } else { + *((guint32*)ptr) += guint32(gray>>pad); + if(color_type & 4) *((guint32*)ptr) += guint32((a>>pad)>> bit_depth); + } +#endif + pad+=bit_depth*n_fields; + ptr+=(pad/8); + pad%=8; + } + if(pad){pad=0;ptr++;}//align bytes on rows + } + return new_data; +} + + + + + + + + /* Local Variables: mode:c++ diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index 2a7e460e8..72087471d 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -178,6 +178,8 @@ void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs); G_GNUC_CONST guint32 argb32_from_pixbuf(guint32 in); G_GNUC_CONST guint32 pixbuf_from_argb32(guint32 in); +const guchar* pixbuf_to_png(guchar const**rows, guchar* px, int nrows, int ncols, int stride, int color_type, int bit_depth); + /** Convert a pixel in 0xRRGGBBAA format to Cairo ARGB32 format. */ G_GNUC_CONST guint32 argb32_from_rgba(guint32 in); diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 1310bb343..e65752c84 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -42,7 +42,7 @@ #include "sp-hatch.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "sp-pattern.h" #include "sp-mask.h" #include "sp-clippath.h" @@ -1257,8 +1257,8 @@ CairoRenderContext::_createPatternForPaintServer(SPPaintServer const *const pain sp_color_get_rgb_floatv(&rg->vector.stops[i].color, rgb); cairo_pattern_add_color_stop_rgba(pattern, rg->vector.stops[i].offset, rgb[0], rgb[1], rgb[2], rg->vector.stops[i].opacity * alpha); } - } else if (SP_IS_MESH (paintserver)) { - SPMesh *mg = SP_MESH(paintserver); + } else if (SP_IS_MESHGRADIENT (paintserver)) { + SPMeshGradient *mg = SP_MESHGRADIENT(paintserver); pattern = mg->pattern_new(_cr, pbox, 1.0); } else if (SP_IS_PATTERN (paintserver)) { diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index 4521d72fd..061fadbaa 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -39,7 +39,7 @@ #include "sp-gradient-reference.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "sp-stop.h" #include "gradient-drag.h" #include "gradient-chemistry.h" @@ -147,7 +147,7 @@ static SPGradient *sp_gradient_get_private_normalized(SPDocument *document, SPGr repr = xml_doc->createElement("svg:radialGradient"); } else { // Rows/patches added in sp_gradient_reset_to_userspace for new meshes. - repr = xml_doc->createElement("svg:mesh"); + repr = xml_doc->createElement("svg:meshgradient"); } // privates are garbage-collectable @@ -271,7 +271,7 @@ static SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradi repr_new->setAttribute("x2", repr->attribute("x2")); repr_new->setAttribute("y2", repr->attribute("y2")); } else { - std::cout << "sp_gradient_fork_private_if_necessary: mesh not implemented" << std::endl; + std::cerr << "sp_gradient_fork_private_if_necessary: mesh not implemented" << std::endl; } return gr_new; @@ -409,7 +409,7 @@ SPGradient *sp_gradient_reset_to_userspace(SPGradient *gr, SPItem *item) // IN SPMeshNodeArray::create() //sp_repr_set_svg_double(repr, "x", bbox->min()[Geom::X]); //sp_repr_set_svg_double(repr, "y", bbox->min()[Geom::Y]); - SPMesh* mg = SP_MESH( gr ); + SPMeshGradient* mg = SP_MESHGRADIENT( gr ); mg->array.create( mg, item, bbox ); } @@ -754,10 +754,10 @@ guint32 sp_item_gradient_stop_query_style(SPItem *item, GrPointType point_type, break; } return 0; - } else if (SP_IS_MESH(gradient)) { + } else if (SP_IS_MESHGRADIENT(gradient)) { // Mesh gradient - SPMesh *mg = SP_MESH(gradient); + SPMeshGradient *mg = SP_MESHGRADIENT(gradient); switch (point_type) { case POINT_MG_CORNER: { @@ -855,12 +855,13 @@ void sp_item_gradient_stop_set_style(SPItem *item, GrPointType point_type, guint } else { // Mesh gradient - SPMesh *mg = SP_MESH(gradient); + SPMeshGradient *mg = SP_MESHGRADIENT(gradient); bool changed = false; switch (point_type) { case POINT_MG_CORNER: { + // Update mesh array (which is not updated automatically when stop is changed?) gchar const* color_str = sp_repr_css_property( stop, "stop-color", NULL ); if( color_str ) { SPColor color( 0 ); @@ -880,9 +881,14 @@ void sp_item_gradient_stop_set_style(SPItem *item, GrPointType point_type, guint mg->array.corners[ point_i ]->opacity = opacity; changed = true; } + // Update stop if( changed ) { - gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); - mg->array.write( mg ); + SPStop *stopi = mg->array.corners[ point_i ]->stop; + if (stopi) { + sp_repr_css_change(stopi->getRepr(), stop, "style"); + } else { + std::cerr << "sp_item_gradient_stop_set_style: null stopi" << std::endl; + } } break; } @@ -1205,8 +1211,8 @@ void sp_item_gradient_set_coords(SPItem *item, GrPointType point_type, guint poi gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); } } - } else if (SP_IS_MESH(gradient)) { - SPMesh *mg = SP_MESH(gradient); + } else if (SP_IS_MESHGRADIENT(gradient)) { + SPMeshGradient *mg = SP_MESHGRADIENT(gradient); //Geom::Affine new_transform; //bool transform_set = false; @@ -1236,7 +1242,7 @@ void sp_item_gradient_set_coords(SPItem *item, GrPointType point_type, guint poi } if( write_repr ) { //std::cout << "Write mesh repr" << std::endl; - sp_mesh_repr_write( mg ); + mg->array.write( mg ); } } @@ -1342,8 +1348,8 @@ Geom::Point getGradientCoords(SPItem *item, GrPointType point_type, guint point_ g_warning( "Bad radial gradient handle type" ); break; } - } else if (SP_IS_MESH(gradient)) { - SPMesh *mg = SP_MESH(gradient); + } else if (SP_IS_MESHGRADIENT(gradient)) { + SPMeshGradient *mg = SP_MESHGRADIENT(gradient); switch (point_type) { case POINT_MG_CORNER: diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index d50a67490..fc75054a0 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -40,7 +40,7 @@ #include "knot.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "gradient-chemistry.h" #include "gradient-drag.h" #include "sp-stop.h" @@ -407,7 +407,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler //r1_knot = false; } } - } else if (SP_IS_MESH(gradient)) { + } else if (SP_IS_MESHGRADIENT(gradient)) { // add_stop_near_point() // Find out which curve pointer is over and use that curve to determine @@ -415,7 +415,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler // This is silly as we already should know which line we are over... // but that information is not saved (sp_gradient_context_is_over_line). - SPMesh *mg = SP_MESH(gradient); + SPMeshGradient *mg = SP_MESHGRADIENT(gradient); Geom::Affine transform = Geom::Affine(mg->gradientTransform)*(Geom::Affine)item->i2dt_affine(); guint rows = mg->array.patch_rows(); @@ -543,7 +543,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler } else { - SPMesh *mg = SP_MESH(gradient); + SPMeshGradient *mg = SP_MESHGRADIENT(gradient); if( divide_row > -1 ) { mg->array.split_row( divide_row, divide_coord ); @@ -552,7 +552,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler } // Update repr - sp_mesh_repr_write( mg ); + mg->array.write( mg ); mg->array.built = false; mg->ensureArray(); // How do we do this? @@ -901,7 +901,7 @@ static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, gui dragger->point = p; dragger->fireDraggables (false, scale_radial); dragger->updateDependencies(false); - dragger->updateHandles( p_old, MG_NODE_NO_SCALE ); + dragger->moveMeshHandles( p_old, MG_NODE_NO_SCALE ); } } @@ -1076,7 +1076,7 @@ static void gr_knot_ungrabbed_handler(SPKnot *knot, unsigned int state, gpointer } else { dragger->fireDraggables (true); } - dragger->updateHandles( dragger->point_original, MG_NODE_NO_SCALE ); + dragger->moveMeshHandles( dragger->point_original, MG_NODE_NO_SCALE ); for (std::set<GrDragger *>::const_iterator it = dragger->parent->selected.begin(); it != dragger->parent->selected.end() ; ++it ) { if (*it == dragger) @@ -1306,9 +1306,8 @@ bool GrDragger::mayMerge(GrDraggable *da2) * Ooops, needs to be reimplemented. */ void -GrDragger::updateHandles ( Geom::Point pc_old, MeshNodeOperation op ) +GrDragger::moveMeshHandles ( Geom::Point pc_old, MeshNodeOperation op ) { - // This routine might more properly be in mesh-context.cpp but moving knots is // handled here rather than there. @@ -1342,7 +1341,7 @@ GrDragger::updateHandles ( Geom::Point pc_old, MeshNodeOperation op ) // Must be a mesh gradient SPGradient *gradient = getGradient(draggable->item, draggable->fill_or_stroke); - if ( !SP_IS_MESH( gradient ) ) continue; + if ( !SP_IS_MESHGRADIENT( gradient ) ) continue; selected_corners[ gradient ].push_back( draggable->point_i ); } @@ -1368,8 +1367,8 @@ GrDragger::updateHandles ( Geom::Point pc_old, MeshNodeOperation op ) // Must be a mesh gradient SPGradient *gradient = getGradient(item, fill_or_stroke); - if ( !SP_IS_MESH( gradient ) ) continue; - SPMesh *mg = SP_MESH( gradient ); + if ( !SP_IS_MESHGRADIENT( gradient ) ) continue; + SPMeshGradient *mg = SP_MESHGRADIENT( gradient ); // pc_old is the old corner position in desktop coordinates, we need it in gradient coordinate. gradient = sp_gradient_convert_to_userspace (gradient, item, (fill_or_stroke == Inkscape::FOR_FILL) ? "fill" : "stroke"); @@ -1947,8 +1946,9 @@ void GrDrag::addDraggersLinear(SPLinearGradient *lg, SPItem *item, Inkscape::Pai /** *Add draggers for the mesh gradient mg on item */ -void GrDrag::addDraggersMesh(SPMesh *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke) +void GrDrag::addDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke) { + mg->ensureArray(); std::vector< std::vector< SPMeshNode* > > nodes = mg->array.nodes; // Show/hide mesh on fill/stroke. This doesn't work at the moment... and prevents node color updating. @@ -1966,7 +1966,7 @@ void GrDrag::addDraggersMesh(SPMesh *mg, SPItem *item, Inkscape::PaintTarget fil // Make sure we have at least one patch defined. if( mg->array.patch_rows() == 0 || mg->array.patch_columns() == 0 ) { - std::cout << "Empty Mesh, No Draggers to Add" << std::endl; + std::cerr << "Empty Mesh, No Draggers to Add" << std::endl; return; } @@ -2021,14 +2021,14 @@ void GrDrag::addDraggersMesh(SPMesh *mg, SPItem *item, Inkscape::PaintTarget fil } default: - std::cout << "Bad Mesh draggable type" << std::endl; + std::cerr << "Bad Mesh draggable type" << std::endl; break; } } } } - mg->array.drag_valid = true; + mg->array.draggers_valid = true; } /** @@ -2083,8 +2083,8 @@ void GrDrag::updateDraggers() addDraggersLinear( SP_LINEARGRADIENT(server), item, Inkscape::FOR_FILL ); } else if ( SP_IS_RADIALGRADIENT(server) ) { addDraggersRadial( SP_RADIALGRADIENT(server), item, Inkscape::FOR_FILL ); - } else if ( SP_IS_MESH(server) ) { - addDraggersMesh( SP_MESH(server), item, Inkscape::FOR_FILL ); + } else if ( SP_IS_MESHGRADIENT(server) ) { + addDraggersMesh( SP_MESHGRADIENT(server), item, Inkscape::FOR_FILL ); } } } @@ -2099,8 +2099,8 @@ void GrDrag::updateDraggers() addDraggersLinear( SP_LINEARGRADIENT(server), item, Inkscape::FOR_STROKE ); } else if ( SP_IS_RADIALGRADIENT(server) ) { addDraggersRadial( SP_RADIALGRADIENT(server), item, Inkscape::FOR_STROKE ); - } else if ( SP_IS_MESH(server) ) { - addDraggersMesh( SP_MESH(server), item, Inkscape::FOR_STROKE ); + } else if ( SP_IS_MESHGRADIENT(server) ) { + addDraggersMesh( SP_MESHGRADIENT(server), item, Inkscape::FOR_STROKE ); } } } @@ -2154,9 +2154,9 @@ void GrDrag::updateLines() Geom::Point center = getGradientCoords(item, POINT_RG_CENTER, 0, Inkscape::FOR_FILL); addLine(item, center, getGradientCoords(item, POINT_RG_R1, 0, Inkscape::FOR_FILL), Inkscape::FOR_FILL); addLine(item, center, getGradientCoords(item, POINT_RG_R2, 0, Inkscape::FOR_FILL), Inkscape::FOR_FILL); - } else if ( SP_IS_MESH(server) ) { + } else if ( SP_IS_MESHGRADIENT(server) ) { - SPMesh *mg = SP_MESH(server); + SPMeshGradient *mg = SP_MESHGRADIENT(server); guint rows = mg->array.patch_rows(); guint columns = mg->array.patch_columns(); @@ -2216,10 +2216,10 @@ void GrDrag::updateLines() Geom::Point center = getGradientCoords(item, POINT_RG_CENTER, 0, Inkscape::FOR_STROKE); addLine(item, center, getGradientCoords(item, POINT_RG_R1, 0, Inkscape::FOR_STROKE), Inkscape::FOR_STROKE); addLine(item, center, getGradientCoords(item, POINT_RG_R2, 0, Inkscape::FOR_STROKE), Inkscape::FOR_STROKE); - } else if ( SP_IS_MESH(server) ) { + } else if ( SP_IS_MESHGRADIENT(server) ) { // MESH FIXME: TURN ROUTINE INTO FUNCTION AND CALL FOR BOTH FILL AND STROKE. - SPMesh *mg = SP_MESH(server); + SPMeshGradient *mg = SP_MESHGRADIENT(server); guint rows = mg->array.patch_rows(); guint columns = mg->array.patch_columns(); @@ -2351,7 +2351,7 @@ void GrDrag::selected_move(double x, double y, bool write_repr, bool scale_radia d->knot->moveto(d->point); d->fireDraggables (write_repr, scale_radial); - d->updateHandles( p_old, MG_NODE_NO_SCALE ); + d->moveMeshHandles( p_old, MG_NODE_NO_SCALE ); d->updateDependencies(write_repr); } } diff --git a/src/gradient-drag.h b/src/gradient-drag.h index b07f748a7..cf0a35c89 100644 --- a/src/gradient-drag.h +++ b/src/gradient-drag.h @@ -34,7 +34,7 @@ class SPKnot; class SPDesktop; class SPCSSAttr; class SPLinearGradient; -class SPMesh; +class SPMeshGradient; class SPItem; class SPObject; class SPRadialGradient; @@ -105,7 +105,7 @@ struct GrDragger { void updateDependencies(bool write_repr); /* Update handles/tensors when mesh corner moved */ - void updateHandles( Geom::Point pc_old, MeshNodeOperation op ); + void moveMeshHandles( Geom::Point pc_old, MeshNodeOperation op ); bool mayMerge(GrDragger *other); bool mayMerge(GrDraggable *da2); @@ -209,7 +209,7 @@ private: void addDraggersRadial(SPRadialGradient *rg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); void addDraggersLinear(SPLinearGradient *lg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); - void addDraggersMesh( SPMesh *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); + void addDraggersMesh( SPMeshGradient *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); bool styleSet( const SPCSSAttr *css ); diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 682aee9b2..2433e2777 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -123,8 +123,8 @@ void PngTextList::add(gchar const* key, gchar const* text) static bool sp_png_write_rgba_striped(SPDocument *doc, gchar const *filename, unsigned long int width, unsigned long int height, double xdpi, double ydpi, - int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data), - void *data) + int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data, int color_type, int bit_depth), + void *data, bool interlace, int color_type, int bit_depth, int zlib) { g_return_val_if_fail(filename != NULL, false); g_return_val_if_fail(data != NULL, false); @@ -184,22 +184,28 @@ sp_png_write_rgba_striped(SPDocument *doc, * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED */ + + png_set_compression_level(png_ptr, zlib); + png_set_IHDR(png_ptr, info_ptr, width, height, - 8, /* bit_depth */ - PNG_COLOR_TYPE_RGB_ALPHA, - PNG_INTERLACE_NONE, + bit_depth, + color_type, + interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - /* otherwise, if we are dealing with a color image then */ - sig_bit.red = 8; - sig_bit.green = 8; - sig_bit.blue = 8; - /* if the image has an alpha channel then */ - sig_bit.alpha = 8; - png_set_sBIT(png_ptr, info_ptr, &sig_bit); + if ((color_type&2) && bit_depth == 16) { + // otherwise, if we are dealing with a color image then + sig_bit.red = 8; + sig_bit.green = 8; + sig_bit.blue = 8; + // if the image has an alpha channel then + if (color_type&4) + sig_bit.alpha = 8; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + } PngTextList textList; @@ -248,7 +254,10 @@ sp_png_write_rgba_striped(SPDocument *doc, /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ /* note that if sRGB is present the cHRM chunk must be ignored * on read and must be written in accordance with the sRGB profile */ - png_set_pHYs(png_ptr, info_ptr, unsigned(xdpi / 0.0254 + 0.5), unsigned(ydpi / 0.0254 + 0.5), PNG_RESOLUTION_METER); + if(xdpi < 0.0254 ) xdpi = 0.0255; + if(ydpi < 0.0254 ) ydpi = 0.0255; + + png_set_pHYs(png_ptr, info_ptr, unsigned(xdpi / 0.0254 ), unsigned(ydpi / 0.0254 ), PNG_RESOLUTION_METER); /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); @@ -271,15 +280,18 @@ sp_png_write_rgba_striped(SPDocument *doc, */ png_bytep* row_pointers = new png_bytep[ebp->sheight]; - - r = 0; - while (r < static_cast<png_uint_32>(height)) { - void *to_free; - int n = get_rows((unsigned char const **) row_pointers, &to_free, r, height-r, data); - if (!n) break; - png_write_rows(png_ptr, row_pointers, n); - g_free(to_free); - r += n; + int number_of_passes = interlace ? png_set_interlace_handling(png_ptr) : 1; + + for(int i=0;i<number_of_passes; ++i){ + r = 0; + while (r < static_cast<png_uint_32>(height)) { + void *to_free; + int n = get_rows((unsigned char const **) row_pointers, &to_free, r, height-r, data, color_type, bit_depth); + if (!n) break; + png_write_rows(png_ptr, row_pointers, n); + g_free(to_free); + r += n; + } } delete[] row_pointers; @@ -308,7 +320,7 @@ sp_png_write_rgba_striped(SPDocument *doc, * */ static int -sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, void *data) +sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, void *data, int color_type, int bit_depth) { struct SPEBP *ebp = (struct SPEBP *) data; @@ -343,15 +355,14 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v ebp->drawing->render(dc, bbox); cairo_surface_destroy(s); - *to_free = px; - // PNG stores data as unpremultiplied big-endian RGBA, which means // it's identical to the GdkPixbuf format. convert_pixels_argb32_to_pixbuf(px, ebp->width, num_rows, stride); - - for (int r = 0; r < num_rows; r++) { - rows[r] = px + r * stride; - } + + // If a custom bit depth or color type is asked, then convert rgb to grayscale, etc. + const guchar* new_data = pixbuf_to_png(rows, px, num_rows, ebp->width, stride, color_type, bit_depth); + *to_free = (void*) new_data; + free(px); return num_rows; } @@ -385,10 +396,10 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, unsigned long bgcolor, unsigned int (*status) (float, void *), void *data, bool force_overwrite, - const std::vector<SPItem*> &items_only) + const std::vector<SPItem*> &items_only, bool interlace, int color_type, int bit_depth, int zlib) { return sp_export_png_file(doc, filename, Geom::Rect(Geom::Point(x0,y0),Geom::Point(x1,y1)), - width, height, xdpi, ydpi, bgcolor, status, data, force_overwrite, items_only); + width, height, xdpi, ydpi, bgcolor, status, data, force_overwrite, items_only, interlace, color_type, bit_depth, zlib); } ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, @@ -397,7 +408,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, unsigned long bgcolor, unsigned (*status)(float, void *), void *data, bool force_overwrite, - const std::vector<SPItem*> &items_only) + const std::vector<SPItem*> &items_only, bool interlace, int color_type, int bit_depth, int zlib) { g_return_val_if_fail(doc != NULL, EXPORT_ERROR); g_return_val_if_fail(filename != NULL, EXPORT_ERROR); @@ -468,7 +479,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, ebp.px = g_try_new(guchar, 4 * ebp.sheight * width); if (ebp.px) { - write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp); + write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp, interlace, color_type, bit_depth, zlib); g_free(ebp.px); } diff --git a/src/helper/png-write.h b/src/helper/png-write.h index 2657fb635..e47f01743 100644 --- a/src/helper/png-write.h +++ b/src/helper/png-write.h @@ -34,12 +34,14 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, double x0, double y0, double x1, double y1, unsigned long int width, unsigned long int height, double xdpi, double ydpi, unsigned long bgcolor, - unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>()); + unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>(), + bool interlace = false, int color_type = 6, int bit_depth = 8, int zlib = 6); ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, Geom::Rect const &area, unsigned long int width, unsigned long int height, double xdpi, double ydpi, unsigned long bgcolor, - unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>()); + unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>(), + bool interlace = false, int color_type = 6, int bit_depth = 8, int zlib = 6); #endif // SEEN_SP_PNG_WRITE_H diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index a7459faed..4deb29d8f 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -25,11 +25,11 @@ namespace Inkscape { namespace LivePathEffect { static const Util::EnumData<ModeType> ModeTypeData[MT_END] = { - { MT_V, N_("Vertical Page Center"), "Vertical Page Center, use select tool to move item instead line" }, - { MT_H, N_("Horizontal Page Center"), "Horizontal Page Center, use select tool to move item instead line" }, - { MT_FREE, N_("Free from reflection line"), "Free from path" }, - { MT_X, N_("X from middle knot"), "X from middle knot" }, - { MT_Y, N_("Y from middle knot"), "Y from middle knot" } + { MT_V, N_("Vertical Page Center"), "vertical" }, + { MT_H, N_("Horizontal Page Center"), "horizontal" }, + { MT_FREE, N_("Free from reflection line"), "free" }, + { MT_X, N_("X from middle knot"), "X" }, + { MT_Y, N_("Y from middle knot"), "Y" } }; static const Util::EnumDataConverter<ModeType> MTConverter(ModeTypeData, MT_END); @@ -87,7 +87,7 @@ void LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem) { using namespace Geom; - + original_bbox(lpeitem); Point point_a(boundingbox_X.max(), boundingbox_Y.min()); Point point_b(boundingbox_X.max(), boundingbox_Y.max()); Point point_c(boundingbox_X.max(), boundingbox_Y.middle()); @@ -145,6 +145,18 @@ LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem) } void +LPEMirrorSymmetry::transform_multiply(Geom::Affine const& postmul, bool set) +{ + center_point *= postmul; + previous_center = center_point; + // cycle through all parameters. Most parameters will not need transformation, but path and point params do. + for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) { + Parameter * param = *it; + param->param_transform_multiply(postmul, set); + } +} + +void LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem) { using namespace Geom; @@ -178,10 +190,13 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in) Geom::Translate m1(point_a[0], point_a[1]); double hyp = Geom::distance(point_a, point_b); - double c = (point_b[0] - point_a[0]) / hyp; // cos(alpha) - double s = (point_b[1] - point_a[1]) / hyp; // sin(alpha) - - Geom::Affine m2(c, -s, s, c, 0.0, 0.0); + double cos = 0; + double sin = 0; + if (hyp > 0) { + cos = (point_b[0] - point_a[0]) / hyp; + sin = (point_b[1] - point_a[1]) / hyp; + } + Geom::Affine m2(cos, -sin, sin, cos, 0.0, 0.0); Geom::Scale sca(1.0, -1.0); Geom::Affine m = m1.inverse() * m2; @@ -292,8 +307,8 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in) } if (!fuse_paths || discard_orig_path) { - for (int i = 0; i < static_cast<int>(path_in.size()); ++i) { - path_out.push_back(path_in[i] * m); + for (size_t i = 0; i < original_pathv.size(); ++i) { + path_out.push_back(original_pathv[i] * m); } } diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h index 9e5b4d628..7ec4029e0 100644 --- a/src/live_effects/lpe-mirror_symmetry.h +++ b/src/live_effects/lpe-mirror_symmetry.h @@ -46,6 +46,7 @@ public: virtual ~LPEMirrorSymmetry(); virtual void doOnApply (SPLPEItem const* lpeitem); virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual void transform_multiply(Geom::Affine const& postmul, bool set); virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); /* the knotholder entity classes must be declared friends */ friend class MS::KnotHolderEntityCenterMirrorSymmetry; diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index 8a6a95f2e..6a6b59519 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -31,8 +31,8 @@ enum DeformationType { }; static const Util::EnumData<unsigned> DeformationTypeData[] = { - {DEFORMATION_PERSPECTIVE , N_("Perspective"), "Perspective"}, - {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "Envelope deformation"} + {DEFORMATION_PERSPECTIVE , N_("Perspective"), "perspective"}, + {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "envelope_deformation"} }; static const Util::EnumDataConverter<unsigned> DeformationTypeConverter(DeformationTypeData, sizeof(DeformationTypeData)/sizeof(*DeformationTypeData)); diff --git a/src/main-cmdlineact.cpp b/src/main-cmdlineact.cpp index c1b756ad5..a23c036a0 100644 --- a/src/main-cmdlineact.cpp +++ b/src/main-cmdlineact.cpp @@ -23,74 +23,81 @@ namespace Inkscape { std::list <CmdLineAction *> CmdLineAction::_list; -CmdLineAction::CmdLineAction (bool isVerb, gchar const * arg) : _isVerb(isVerb), _arg(NULL) { - if (arg != NULL) { - _arg = g_strdup(arg); - } +CmdLineAction::CmdLineAction(bool isVerb, gchar const *arg) : _isVerb(isVerb), _arg(NULL) +{ + if (arg != NULL) { + _arg = g_strdup(arg); + } - _list.insert(_list.end(), this); + _list.insert(_list.end(), this); - return; + return; } -CmdLineAction::~CmdLineAction () { - if (_arg != NULL) { - g_free(_arg); - } +CmdLineAction::~CmdLineAction() +{ + if (_arg != NULL) { + g_free(_arg); + } } void -CmdLineAction::doIt (ActionContext const & context) { - //printf("Doing: %s\n", _arg); - if (_isVerb) { - Inkscape::Verb * verb = Inkscape::Verb::getbyid(_arg); - if (verb == NULL) { - printf(_("Unable to find verb ID '%s' specified on the command line.\n"), _arg); - return; - } - SPAction * action = verb->get_action(context); - sp_action_perform(action, NULL); - } else { - if (context.getDocument() == NULL || context.getSelection() == NULL) { return; } - - SPDocument * doc = context.getDocument(); - SPObject * obj = doc->getObjectById(_arg); - if (obj == NULL) { - printf(_("Unable to find node ID: '%s'\n"), _arg); - return; - } - - Inkscape::Selection * selection = context.getSelection(); - selection->add(obj); - } - return; +CmdLineAction::doIt(ActionContext const &context) +{ + //printf("Doing: %s\n", _arg); + if (_isVerb) { + Inkscape::Verb *verb = Inkscape::Verb::getbyid(_arg); + if (verb == NULL) { + printf(_("Unable to find verb ID '%s' specified on the command line.\n"), _arg); + return; + } + SPAction *action = verb->get_action(context); + sp_action_perform(action, NULL); + } else { + if (context.getDocument() == NULL || context.getSelection() == NULL) { + return; + } + + SPDocument *doc = context.getDocument(); + SPObject *obj = doc->getObjectById(_arg); + if (obj == NULL) { + printf(_("Unable to find node ID: '%s'\n"), _arg); + return; + } + + Inkscape::Selection *selection = context.getSelection(); + selection->add(obj); + } + return; } bool -CmdLineAction::doList (ActionContext const & context) { - bool hasActions = !_list.empty(); - for (std::list<CmdLineAction *>::iterator i = _list.begin(); - i != _list.end(); ++i) { - CmdLineAction * entry = *i; - entry->doIt(context); - } - return hasActions; +CmdLineAction::doList(ActionContext const &context) +{ + bool hasActions = !_list.empty(); + for (std::list<CmdLineAction *>::iterator i = _list.begin(); + i != _list.end(); ++i) { + CmdLineAction *entry = *i; + entry->doIt(context); + } + return hasActions; } bool -CmdLineAction::idle (void) { - std::list<SPDesktop *> desktops; - INKSCAPE.get_all_desktops(desktops); - - // We're going to assume one desktop per document, because no one - // should have had time to make more at this point. - for (std::list<SPDesktop *>::iterator i = desktops.begin(); - i != desktops.end(); ++i) { - SPDesktop * desktop = *i; - //Inkscape::UI::View::View * view = dynamic_cast<Inkscape::UI::View::View *>(desktop); - doList(ActionContext(desktop)); - } - return false; +CmdLineAction::idle(void) +{ + std::list<SPDesktop *> desktops; + INKSCAPE.get_all_desktops(desktops); + + // We're going to assume one desktop per document, because no one + // should have had time to make more at this point. + for (std::list<SPDesktop *>::iterator i = desktops.begin(); + i != desktops.end(); ++i) { + SPDesktop *desktop = *i; + //Inkscape::UI::View::View * view = dynamic_cast<Inkscape::UI::View::View *>(desktop); + doList(ActionContext(desktop)); + } + return false; } } // Inkscape diff --git a/src/main-cmdlineact.h b/src/main-cmdlineact.h index b8ec4403b..171313401 100644 --- a/src/main-cmdlineact.h +++ b/src/main-cmdlineact.h @@ -21,18 +21,18 @@ class ActionContext; class CmdLineAction { bool _isVerb; - char * _arg; + char *_arg; static std::list <CmdLineAction *> _list; public: - CmdLineAction (bool isVerb, char const * arg); - virtual ~CmdLineAction (); + CmdLineAction(bool isVerb, char const *arg); + virtual ~CmdLineAction(); - void doIt (ActionContext const & context); + void doIt(ActionContext const &context); /** Return true if any actions were performed */ - static bool doList (ActionContext const & context); - static bool idle (void); + static bool doList(ActionContext const &context); + static bool idle(void); }; } // Inkscape diff --git a/src/sp-factory.cpp b/src/sp-factory.cpp index 62af684a2..f98291378 100644 --- a/src/sp-factory.cpp +++ b/src/sp-factory.cpp @@ -36,7 +36,7 @@ #include "sp-linear-gradient.h" #include "sp-marker.h" #include "sp-mask.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "sp-mesh-patch.h" #include "sp-mesh-row.h" #include "sp-metadata.h" @@ -154,8 +154,12 @@ SPObject *SPFactory::createObject(std::string const& id) ret = new SPGuide; else if (id == "svg:hatch") ret = new SPHatch; - else if (id == "svg:hatchPath") + else if (id == "svg:hatchpath") ret = new SPHatchPath; + else if (id == "svg:hatchPath") { + std::cerr << "Warning: <hatchPath> has been renamed <hatchpath>" << std::endl; + ret = new SPHatchPath; + } else if (id == "svg:image") ret = new SPImage; else if (id == "svg:g") @@ -168,8 +172,17 @@ SPObject *SPFactory::createObject(std::string const& id) ret = new SPMarker; else if (id == "svg:mask") ret = new SPMask; - else if (id == "svg:mesh") - ret = new SPMesh; + else if (id == "svg:mesh") { // SVG 2 old + ret = new SPMeshGradient; + std::cerr << "Warning: <mesh> has been renamed <meshgradient>." << std::endl; + std::cerr << "Warning: <mesh> has been repurposed as a shape that tightly wraps a <meshgradient>." << std::endl; + } + else if (id == "svg:meshGradient") { // SVG 2 old + ret = new SPMeshGradient; + std::cerr << "Warning: <meshGradient> has been renamed <meshgradient>" << std::endl; + } + else if (id == "svg:meshgradient") // SVG 2 + ret = new SPMeshGradient; else if (id == "svg:meshpatch") ret = new SPMeshpatch; else if (id == "svg:meshrow") @@ -198,7 +211,11 @@ SPObject *SPFactory::createObject(std::string const& id) ret = new SPRoot; else if (id == "svg:script") ret = new SPScript; - else if (id == "svg:solidColor") + else if (id == "svg:solidColor") { + ret = new SPSolidColor; + std::cerr << "Warning: <solidColor> has been renamed <solidcolor>" << std::endl; + } + else if (id == "svg:solidcolor") ret = new SPSolidColor; else if (id == "spiral") ret = new SPSpiral; diff --git a/src/sp-gradient.cpp b/src/sp-gradient.cpp index f24e25ab1..d3e38485b 100644 --- a/src/sp-gradient.cpp +++ b/src/sp-gradient.cpp @@ -1,6 +1,6 @@ /** \file * SPGradient, SPStop, SPLinearGradient, SPRadialGradient, - * SPMesh, SPMeshRow, SPMeshPatch + * SPMeshGradient, SPMeshRow, SPMeshPatch */ /* * Authors: @@ -22,6 +22,7 @@ */ #define noSP_GRADIENT_VERBOSE +//#define OBJECT_TRACE #include <cstring> #include <string> @@ -43,7 +44,7 @@ #include "sp-gradient-reference.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "sp-mesh-row.h" #include "sp-stop.h" @@ -114,7 +115,7 @@ bool SPGradient::isEquivalent(SPGradient *that) else if ( (SP_IS_LINEARGRADIENT(this) && SP_IS_LINEARGRADIENT(that)) || (SP_IS_RADIALGRADIENT(this) && SP_IS_RADIALGRADIENT(that)) || - (SP_IS_MESH(this) && SP_IS_MESH(that))) { + (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that))) { if(!this->isAligned(that))break; } else { break; } // this should never happen, some unhandled type of gradient @@ -199,9 +200,9 @@ bool SPGradient::isAligned(SPGradient *that) (sg->fy.computed != tg->fy.computed) ) { break; } } else if( sg->cx._set || sg->cy._set || sg->fx._set || sg->fy._set || sg->r._set ) { break; } // some mix of set and not set // none set? assume aligned and fall through - } else if (SP_IS_MESH(this) && SP_IS_MESH(that)) { - SPMesh *sg=SP_MESH(this); - SPMesh *tg=SP_MESH(that); + } else if (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that)) { + SPMeshGradient *sg=SP_MESHGRADIENT(this); + SPMeshGradient *tg=SP_MESHGRADIENT(that); if( sg->x._set != !tg->x._set) { break; } if( sg->y._set != !tg->y._set) { break; } @@ -228,7 +229,7 @@ SPGradient::SPGradient() : SPPaintServer(), units(), state(2), vector() { - this->has_patches = 0; + this->has_patches = 0; this->ref = new SPGradientReference(this); this->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(SPGradient::gradientRefChanged), this)); @@ -318,6 +319,12 @@ void SPGradient::release() */ void SPGradient::set(unsigned key, gchar const *value) { +#ifdef OBJECT_TRACE + std::stringstream temp; + temp << "SPGradient::set: " << key << " " << (value?value:"null"); + objectTrace( temp.str() ); +#endif + switch (key) { case SP_ATTR_GRADIENTUNITS: if (value) { @@ -409,6 +416,10 @@ void SPGradient::set(unsigned key, gchar const *value) SPPaintServer::set(key, value); break; } + +#ifdef OBJECT_TRACE + objectTrace( "SPGradient::set", false ); +#endif } /** @@ -498,29 +509,24 @@ void SPGradient::remove_child(Inkscape::XML::Node *child) */ void SPGradient::modified(guint flags) { +#ifdef OBJECT_TRACE + objectTrace( "SPGradient::modified" ); +#endif + if (flags & SP_OBJECT_CHILD_MODIFIED_FLAG) { - // CPPIFY - // This comparison has never worked (i. e. always evaluated to false), - // the right value would have been SP_TYPE_MESH - //if( this->get_type() != SP_GRADIENT_TYPE_MESH ) { -// if (!SP_IS_MESH(this)) { -// this->invalidateVector(); -// } else { -// this->invalidateArray(); -// } - this->invalidateVector(); + if (SP_IS_MESHGRADIENT(this)) { + this->invalidateArray(); + } else { + this->invalidateVector(); + } } if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - // CPPIFY - // see above - //if( this->get_type() != SP_GRADIENT_TYPE_MESH ) { -// if (!SP_IS_MESH(this)) { -// this->ensureVector(); -// } else { -// this->ensureArray(); -// } - this->ensureVector(); + if (SP_IS_MESHGRADIENT(this)) { + this->ensureArray(); + } else { + this->ensureVector(); + } } if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; @@ -546,6 +552,10 @@ void SPGradient::modified(guint flags) sp_object_unref(child); } + +#ifdef OBJECT_TRACE + objectTrace( "SPGradient::modified", false ); +#endif } SPStop* SPGradient::getFirstStop() @@ -576,6 +586,10 @@ int SPGradient::getStopCount() const */ Inkscape::XML::Node *SPGradient::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { +#ifdef OBJECT_TRACE + objectTrace( "SPGradient::write" ); +#endif + SPPaintServer::write(xml_doc, repr, flags); if (flags & SP_OBJECT_WRITE_BUILD) { @@ -646,6 +660,9 @@ Inkscape::XML::Node *SPGradient::write(Inkscape::XML::Document *xml_doc, Inkscap repr->setAttribute( "osb:paint", 0 ); } +#ifdef OBJECT_TRACE + objectTrace( "SPGradient::write", false ); +#endif return repr; } @@ -898,7 +915,7 @@ bool SPGradient::invalidateArray() if (array.built) { array.built = false; - array.clear(); + // array.clear(); ret = true; } @@ -1008,39 +1025,12 @@ void SPGradient::rebuildArray() { // std::cout << "SPGradient::rebuildArray()" << std::endl; - if( !SP_IS_MESH(this) ) { + if( !SP_IS_MESHGRADIENT(this) ) { g_warning( "SPGradient::rebuildArray() called for non-mesh gradient" ); return; } - array.read( SP_MESH( this ) ); - - has_patches = false; - for (auto& ro: children) { - if (SP_IS_MESHROW(&ro)) { - has_patches = true; - // std::cout << " Has Patches" << std::endl; - break; - } - } - - // MESH_FIXME: TO PROPERLY COPY - SPGradient *reffed = ref->getObject(); - if ( !hasPatches() && reffed ) { - std::cout << "SPGradient::rebuildArray(): reffed array NOT IMPLEMENTED!!!" << std::endl; - /* Copy array from referenced gradient */ - array.built = true; // Prevent infinite recursion. - reffed->ensureArray(); - // if (!reffed->array.nodes.empty()) { - // array.built = reffed->array.built; - // for( uint i = 0; i < reffed->array.nodes.size(); ++i ) { - // array.nodes[i].assign(reffed->array.nodes[i].begin(), reffed->array.nodes[i].end()); - - // // FILL ME - // } - // return; - // } - } + array.read( SP_MESHGRADIENT( this ) ); } Geom::Affine @@ -1131,9 +1121,7 @@ sp_gradient_create_preview_pattern(SPGradient *gr, double width) { cairo_pattern_t *pat = NULL; - // CPPIFY - //if( gr->get_type() != SP_GRADIENT_TYPE_MESH ) { - if (!SP_IS_MESH(gr)) { + if (!SP_IS_MESHGRADIENT(gr)) { gr->ensureVector(); pat = cairo_pattern_create_linear(0, 0, width, 0); diff --git a/src/sp-gradient.h b/src/sp-gradient.h index ab45d6f08..7348bb5ca 100644 --- a/src/sp-gradient.h +++ b/src/sp-gradient.h @@ -210,8 +210,6 @@ sp_gradient_pattern_common_setup(cairo_pattern_t *cp, void sp_gradient_repr_write_vector(SPGradient *gr); void sp_gradient_repr_clear_vector(SPGradient *gr); -void sp_mesh_repr_write(SPMesh *mg); - cairo_pattern_t *sp_gradient_create_preview_pattern(SPGradient *gradient, double width); /** Transforms to/from gradient position space in given environment */ diff --git a/src/sp-item.cpp b/src/sp-item.cpp index e03b715c0..d161562fd 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -59,6 +59,7 @@ #define noSP_ITEM_DEBUG_IDLE +//#define OBJECT_TRACE static SPItemView* sp_item_view_list_remove(SPItemView *list, SPItemView *view); @@ -691,6 +692,10 @@ void SPItem::update(SPCtx* ctx, guint flags) { void SPItem::modified(unsigned int /*flags*/) { +#ifdef OBJECT_TRACE + objectTrace( "SPItem::modified" ); + objectTrace( "SPItem::modified", false ); +#endif } Inkscape::XML::Node* SPItem::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { diff --git a/src/sp-mesh-array.cpp b/src/sp-mesh-array.cpp index 0dd89ac96..c47c338de 100644 --- a/src/sp-mesh-array.cpp +++ b/src/sp-mesh-array.cpp @@ -46,7 +46,7 @@ #include "document.h" #include "sp-root.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "sp-mesh-array.h" #include "sp-mesh-row.h" #include "sp-mesh-patch.h" @@ -574,7 +574,60 @@ void SPMeshPatchI::setOpacity( guint i, gdouble opacity ) { }; -SPMeshNodeArray::SPMeshNodeArray( SPMesh *mg ) { +/** + Return stop pointer for corner of patch. +*/ +SPStop* SPMeshPatchI::getStopPtr( guint i ) { + + assert( i < 4 ); + + SPStop* stop = nullptr; + switch ( i ) { + case 0: + stop = (*nodes)[ row ][ col ]->stop; + break; + case 1: + stop = (*nodes)[ row ][ col+3 ]->stop; + break; + case 2: + stop = (*nodes)[ row+3 ][ col+3 ]->stop; + break; + case 3: + stop = (*nodes)[ row+3 ][ col ]->stop; + break; + } + + return stop; +}; + + +/** + Set stop pointer for corner of patch. +*/ +void SPMeshPatchI::setStopPtr( guint i, SPStop* stop ) { + + assert( i < 4 ); + + switch ( i ) { + case 0: + (*nodes)[ row ][ col ]->stop = stop; + break; + case 1: + (*nodes)[ row ][ col+3 ]->stop = stop; + break; + case 2: + (*nodes)[ row+3 ][ col+3 ]->stop = stop; + break; + case 3: + (*nodes)[ row+3 ][ col ]->stop = stop; + break; + + } + +}; + + +SPMeshNodeArray::SPMeshNodeArray( SPMeshGradient *mg ) { read( mg ); @@ -586,7 +639,7 @@ SPMeshNodeArray::SPMeshNodeArray( const SPMeshNodeArray& rhs ) { built = false; mg = NULL; - drag_valid = false; + draggers_valid = false; nodes = rhs.nodes; // This only copies the pointers but it does size the vector of vectors. @@ -607,7 +660,7 @@ SPMeshNodeArray& SPMeshNodeArray::operator=( const SPMeshNodeArray& rhs ) { built = false; mg = NULL; - drag_valid = false; + draggers_valid = false; nodes = rhs.nodes; // This only copies the pointers but it does size the vector of vectors. @@ -620,12 +673,34 @@ SPMeshNodeArray& SPMeshNodeArray::operator=( const SPMeshNodeArray& rhs ) { return *this; }; - -void SPMeshNodeArray::read( SPMesh *mg_in ) { +// Fill array with data from mesh objects. +// Returns true of array's dimensions unchanged. +bool SPMeshNodeArray::read( SPMeshGradient *mg_in ) { mg = mg_in; - clear(); + // Count rows and columns, if unchanged reuse array to keep draggers valid. + unsigned cols = 0; + unsigned rows = 0; + for (auto& ro: mg->children) { + if (SP_IS_MESHROW(&ro)) { + ++rows; + if (rows == 1 ) { + for (auto& po: ro.children) { + if (SP_IS_MESHPATCH(&po)) { + ++cols; + } + } + } + } + } + bool same_size = true; + if (cols != patch_columns() || rows != patch_rows() ) { + // Draggers will be invalidated. + same_size = false; + clear(); + draggers_valid = false; + } Geom::Point current_p( mg->x.computed, mg->y.computed ); // std::cout << "SPMeshNodeArray::read: p: " << current_p << std::endl; @@ -701,7 +776,7 @@ void SPMeshNodeArray::read( SPMesh *mg_in ) { dp = Geom::Point( x, y ); new_patch.setPoint( istop, 3, current_p + dp ); } else { - std::cout << "Failed to read l" << std::endl; + std::cerr << "Failed to read l" << std::endl; } } // To facilitate some side operations, set handles to 1/3 and @@ -723,7 +798,7 @@ void SPMeshNodeArray::read( SPMesh *mg_in ) { p = Geom::Point( x, y ); new_patch.setPoint( istop, 3, p ); } else { - std::cout << "Failed to read L" << std::endl; + std::cerr << "Failed to read L" << std::endl; } } // To facilitate some side operations, set handles to 1/3 and @@ -743,7 +818,7 @@ void SPMeshNodeArray::read( SPMesh *mg_in ) { p += current_p; new_patch.setPoint( istop, i, p ); } else { - std::cout << "Failed to read c: " << i << std::endl; + std::cerr << "Failed to read c: " << i << std::endl; } } break; @@ -756,13 +831,13 @@ void SPMeshNodeArray::read( SPMesh *mg_in ) { p = Geom::Point( x, y ); new_patch.setPoint( istop, i, p ); } else { - std::cout << "Failed to read C: " << i << std::endl; + std::cerr << "Failed to read C: " << i << std::endl; } } break; default: // should not reach - std::cout << "Path Error: unhandled path type: " << path_type << std::endl; + std::cerr << "Path Error: unhandled path type: " << path_type << std::endl; } current_p = new_patch.getPoint( istop, 3 ); @@ -774,6 +849,7 @@ void SPMeshNodeArray::read( SPMesh *mg_in ) { double opacity = stop->opacity; new_patch.setColor( istop, color ); new_patch.setOpacity( istop, opacity ); + new_patch.setStopPtr( istop, stop ); } } @@ -797,7 +873,7 @@ void SPMeshNodeArray::read( SPMesh *mg_in ) { if( !os.fail() ) { new_patch.setTensorPoint( i, new_patch.getPoint( i, 0 ) + Geom::Point( x, y ) ); } else { - std::cout << "Failed to read p: " << i << std::endl; + std::cerr << "Failed to read p: " << i << std::endl; break; } } @@ -830,15 +906,15 @@ void SPMeshNodeArray::read( SPMesh *mg_in ) { // std::cout << "SPMeshNodeArray::Read: result:" << std::endl; // print(); - drag_valid = false; built = true; + return same_size; }; /** Write repr using our array. */ -void SPMeshNodeArray::write( SPMesh *mg ) { +void SPMeshNodeArray::write( SPMeshGradient *mg ) { // std::cout << "SPMeshNodeArray::write: entrance:" << std::endl; // print(); @@ -967,10 +1043,10 @@ void SPMeshNodeArray::write( SPMesh *mg ) { break; case 'z': case 'Z': - std::cout << "sp_mesh_repr_write: bad path type" << path_type << std::endl; + std::cout << "SPMeshNodeArray::write(): bad path type" << path_type << std::endl; break; default: - std::cout << "sp_mesh_repr_write: unhandled path type" << path_type << std::endl; + std::cout << "SPMeshNodeArray::write(): unhandled path type" << path_type << std::endl; } stop->setAttribute("path", is.str().c_str()); // std::cout << "SPMeshNodeArray::write: path: " << is.str().c_str() << std::endl; @@ -1039,7 +1115,7 @@ static SPColor default_color( SPItem *item ) { /** Create a default mesh. */ -void SPMeshNodeArray::create( SPMesh *mg, SPItem *item, Geom::OptRect bbox ) { +void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bbox ) { // std::cout << "SPMeshNodeArray::create: Entrance" << std::endl; @@ -1415,6 +1491,7 @@ void SPMeshNodeArray::print() { << " Node edge: " << nodes[i][j]->node_edge << " Set: " << nodes[i][j]->set << " Path type: " << nodes[i][j]->path_type + << " Stop: " << nodes[i][j]->stop << std::endl; } else { std::cout << "Error: missing mesh node." << std::endl; @@ -1776,7 +1853,9 @@ guint SPMeshNodeArray::patch_rows() { Number of patch columns. */ guint SPMeshNodeArray::patch_columns() { - + if (nodes.empty()) { + return 0; + } return nodes[0].size()/3; } @@ -2345,7 +2424,11 @@ guint SPMeshNodeArray::color_pick( std::vector<guint> icorners, SPItem* item ) { */ void SPMeshNodeArray::update_handles( guint corner, std::vector< guint > /*selected*/, Geom::Point p_old, MeshNodeOperation /*op*/ ) { - assert( drag_valid ); + if (!draggers_valid) { + std::cerr << "SPMeshNodeArray::update_handles: Draggers not valid!" << std::endl; + return; + } + // assert( draggers_valid ); // std::cout << "SPMeshNodeArray::update_handles: " // << " corner: " << corner diff --git a/src/sp-mesh-array.h b/src/sp-mesh-array.h index b078b221e..49ee88e53 100644 --- a/src/sp-mesh-array.h +++ b/src/sp-mesh-array.h @@ -85,6 +85,7 @@ enum MeshNodeOperation { MG_NODE_SCALE_HANDLE }; +class SPStop; class SPMeshNode { public: @@ -95,6 +96,7 @@ public: draggable = -1; path_type = 'u'; opacity = 0.0; + stop = nullptr; } NodeType node_type; unsigned int node_edge; @@ -104,6 +106,7 @@ public: char path_type; SPColor color; double opacity; + SPStop *stop; // Stop corresponding to node. }; @@ -133,21 +136,23 @@ public: void setColor( unsigned int i, SPColor c ); double getOpacity( unsigned int i ); void setOpacity( unsigned int i, double o ); + SPStop* getStopPtr( unsigned int i ); + void setStopPtr( unsigned int i, SPStop* ); }; -class SPMesh; +class SPMeshGradient; // An array of mesh nodes. class SPMeshNodeArray { // Should be private public: - SPMesh *mg; + SPMeshGradient *mg; std::vector< std::vector< SPMeshNode* > > nodes; public: // Draggables to nodes - bool drag_valid; + bool draggers_valid; std::vector< SPMeshNode* > corners; std::vector< SPMeshNode* > handles; std::vector< SPMeshNode* > tensors; @@ -156,17 +161,17 @@ public: friend class SPMeshPatchI; - SPMeshNodeArray() { built = false; mg = NULL; drag_valid = false; }; - SPMeshNodeArray( SPMesh *mg ); + SPMeshNodeArray() { built = false; mg = NULL; draggers_valid = false; }; + SPMeshNodeArray( SPMeshGradient *mg ); SPMeshNodeArray( const SPMeshNodeArray& rhs ); SPMeshNodeArray& operator=(const SPMeshNodeArray& rhs); ~SPMeshNodeArray() { clear(); }; bool built; - void read( SPMesh *mg ); - void write( SPMesh *mg ); - void create( SPMesh *mg, SPItem *item, Geom::OptRect bbox ); + bool read( SPMeshGradient *mg ); + void write( SPMeshGradient *mg ); + void create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bbox ); void clear(); void print(); diff --git a/src/sp-mesh.cpp b/src/sp-mesh-gradient.cpp index 5a6f2bd8e..572131c60 100644 --- a/src/sp-mesh.cpp +++ b/src/sp-mesh-gradient.cpp @@ -3,33 +3,59 @@ #include "attributes.h" #include "display/cairo-utils.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" /* * Mesh Gradient */ //#define MESH_DEBUG -SPMesh::SPMesh() : SPGradient(), type( SP_MESH_TYPE_COONS ), type_set(false) { +//#define OBJECT_TRACE + +SPMeshGradient::SPMeshGradient() : SPGradient(), type( SP_MESH_TYPE_COONS ), type_set(false) { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::SPMeshGradient" ); +#endif + // Start coordinate of mesh this->x.unset(SVGLength::NONE, 0.0, 0.0); this->y.unset(SVGLength::NONE, 0.0, 0.0); + +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::SPMeshGradient", false ); +#endif } -SPMesh::~SPMesh() { +SPMeshGradient::~SPMeshGradient() { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::~SPMeshGradient (empty function)" ); + objectTrace( "SPMeshGradient::~SPMeshGradient", false ); +#endif } -void SPMesh::build(SPDocument *document, Inkscape::XML::Node *repr) { +void SPMeshGradient::build(SPDocument *document, Inkscape::XML::Node *repr) { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::build" ); +#endif + SPGradient::build(document, repr); - // Start coordinate of mesh + // Start coordinate of meshgradient this->readAttr( "x" ); this->readAttr( "y" ); this->readAttr( "type" ); + +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::build", false ); +#endif } -void SPMesh::set(unsigned key, gchar const *value) { +void SPMeshGradient::set(unsigned key, gchar const *value) { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::set" ); +#endif + switch (key) { case SP_ATTR_X: if (!this->x.read(value)) { @@ -54,11 +80,11 @@ void SPMesh::set(unsigned key, gchar const *value) { } else if (!strcmp(value, "bicubic")) { this->type = SP_MESH_TYPE_BICUBIC; } else { - std::cerr << "SPMesh::set(): invalid value " << value << std::endl; + std::cerr << "SPMeshGradient::set(): invalid value " << value << std::endl; } this->type_set = TRUE; } else { - // std::cout << "SPMesh::set() No value " << std::endl; + // std::cout << "SPMeshGradient::set() No value " << std::endl; this->type = SP_MESH_TYPE_COONS; this->type_set = FALSE; } @@ -70,18 +96,22 @@ void SPMesh::set(unsigned key, gchar const *value) { SPGradient::set(key, value); break; } + +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::set", false ); +#endif } /** * Write mesh gradient attributes to associated repr. */ -Inkscape::XML::Node* SPMesh::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { -#ifdef MESH_DEBUG - std::cout << "sp_mesh_write() ***************************" << std::endl; +Inkscape::XML::Node* SPMeshGradient::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::write", false ); #endif if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:mesh"); + repr = xml_doc->createElement("svg:meshgradient"); } if ((flags & SP_OBJECT_WRITE_ALL) || this->x._set) { @@ -108,17 +138,13 @@ Inkscape::XML::Node* SPMesh::write(Inkscape::XML::Document *xml_doc, Inkscape::X SPGradient::write(xml_doc, repr, flags); +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::write", false ); +#endif return repr; } -void -sp_mesh_repr_write(SPMesh *mg) -{ - mg->array.write( mg ); -} - - -cairo_pattern_t* SPMesh::pattern_new(cairo_t * /*ct*/, +cairo_pattern_t* SPMeshGradient::pattern_new(cairo_t * /*ct*/, #if defined(MESH_DEBUG) || (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 4)) Geom::OptRect const &bbox, double opacity @@ -132,7 +158,7 @@ cairo_pattern_t* SPMesh::pattern_new(cairo_t * /*ct*/, using Geom::Y; #ifdef MESH_DEBUG - std::cout << "sp_mesh_create_pattern: (" << bbox->x0 << "," << bbox->y0 << ") (" << bbox->x1 << "," << bbox->y1 << ") " << opacity << std::endl; + std::cout << "sp_meshgradient_create_pattern: " << (*bbox) << " " << opacity << std::endl; #endif this->ensureArray(); @@ -145,7 +171,7 @@ cairo_pattern_t* SPMesh::pattern_new(cairo_t * /*ct*/, if( type_set ) { switch (type) { case SP_MESH_TYPE_COONS: - // std::cout << "SPMesh::pattern_new: Coons" << std::endl; + // std::cout << "SPMeshGradient::pattern_new: Coons" << std::endl; break; case SP_MESH_TYPE_BICUBIC: array.bicubic( &array_smoothed, type ); diff --git a/src/sp-mesh-gradient.h b/src/sp-mesh-gradient.h new file mode 100644 index 000000000..a221554a3 --- /dev/null +++ b/src/sp-mesh-gradient.h @@ -0,0 +1,43 @@ +#ifndef SP_MESH_GRADIENT_H +#define SP_MESH_GRADIENT_H + +/** \file + * SPMeshGradient: SVG <meshgradient> implementation. + */ + +#include "svg/svg-length.h" +#include "sp-gradient.h" + +#define SP_MESHGRADIENT(obj) (dynamic_cast<SPMeshGradient*>((SPObject*)obj)) +#define SP_IS_MESHGRADIENT(obj) (dynamic_cast<const SPMeshGradient*>((SPObject*)obj) != NULL) + +/** Mesh gradient. */ +class SPMeshGradient : public SPGradient { +public: + SPMeshGradient(); + virtual ~SPMeshGradient(); + + SVGLength x; // Upper left corner of meshgradient + SVGLength y; // Upper right corner of mesh + SPMeshType type; + bool type_set; + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); + +protected: + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void set(unsigned key, char const *value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags); +}; + +#endif /* !SP_MESH_GRADIENT_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-mesh-patch.cpp b/src/sp-mesh-patch.cpp index 9727ffef6..9a173a8db 100644 --- a/src/sp-mesh-patch.cpp +++ b/src/sp-mesh-patch.cpp @@ -57,7 +57,6 @@ SPMeshpatch* SPMeshpatch::getPrevMeshpatch() /* * Mesh Patch */ - SPMeshpatch::SPMeshpatch() : SPObject() { this->tensor_string = NULL; } @@ -74,7 +73,6 @@ void SPMeshpatch::build(SPDocument* doc, Inkscape::XML::Node* repr) { /** * Virtual build: set meshpatch attributes from its associated XML node. */ - void SPMeshpatch::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_TENSOR: { @@ -91,9 +89,36 @@ void SPMeshpatch::set(unsigned int key, const gchar* value) { } /** - * Virtual set: set attribute to value. + * modified */ +void SPMeshpatch::modified(unsigned int flags) { + flags &= SP_OBJECT_MODIFIED_CASCADE; + GSList *l = NULL; + + for (auto& child: children) { + sp_object_ref(&child); + l = g_slist_prepend(l, &child); + } + + l = g_slist_reverse(l); + + while (l) { + SPObject *child = SP_OBJECT(l->data); + l = g_slist_remove(l, child); + + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + child->emitModified(flags); + } + + sp_object_unref(child); + } +} + + +/** + * Virtual set: set attribute to value. + */ Inkscape::XML::Node* SPMeshpatch::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:meshpatch"); diff --git a/src/sp-mesh-patch.h b/src/sp-mesh-patch.h index 88d6325c3..e018b81ea 100644 --- a/src/sp-mesh-patch.h +++ b/src/sp-mesh-patch.h @@ -21,8 +21,8 @@ /** Gradient Meshpatch. */ class SPMeshpatch : public SPObject { public: - SPMeshpatch(); - virtual ~SPMeshpatch(); + SPMeshpatch(); + virtual ~SPMeshpatch(); SPMeshpatch* getNextMeshpatch(); SPMeshpatch* getPrevMeshpatch(); @@ -31,9 +31,10 @@ public: //SVGLength ty[4]; // Tensor points protected: - virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); - virtual void set(unsigned int key, const char* value); - virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags); + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void set(unsigned int key, const char* value); + virtual void modified(unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags); }; #endif /* !SEEN_SP_MESHPATCH_H */ diff --git a/src/sp-mesh-row.cpp b/src/sp-mesh-row.cpp index 90173da8c..5ac349c27 100644 --- a/src/sp-mesh-row.cpp +++ b/src/sp-mesh-row.cpp @@ -65,17 +65,44 @@ void SPMeshrow::build(SPDocument* doc, Inkscape::XML::Node* repr) { SPObject::build(doc, repr); } + /** * Virtual build: set meshrow attributes from its associated XML node. */ - void SPMeshrow::set(unsigned int /*key*/, const gchar* /*value*/) { } /** - * Virtual set: set attribute to value. + * modified */ +void SPMeshrow::modified(unsigned int flags) { + flags &= SP_OBJECT_MODIFIED_CASCADE; + GSList *l = NULL; + + for (auto& child: children) { + sp_object_ref(&child); + l = g_slist_prepend(l, &child); + } + + l = g_slist_reverse(l); + + while (l) { + SPObject *child = SP_OBJECT(l->data); + l = g_slist_remove(l, child); + + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + child->emitModified(flags); + } + + sp_object_unref(child); + } +} + + +/** + * Virtual set: set attribute to value. + */ Inkscape::XML::Node* SPMeshrow::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:meshrow"); diff --git a/src/sp-mesh-row.h b/src/sp-mesh-row.h index ffb3efa6b..40335e2b9 100644 --- a/src/sp-mesh-row.h +++ b/src/sp-mesh-row.h @@ -19,16 +19,17 @@ /** Gradient Meshrow. */ class SPMeshrow : public SPObject { public: - SPMeshrow(); - virtual ~SPMeshrow(); + SPMeshrow(); + virtual ~SPMeshrow(); SPMeshrow* getNextMeshrow(); SPMeshrow* getPrevMeshrow(); protected: - virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); - virtual void set(unsigned int key, const char* value); - virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags); + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void set(unsigned int key, const char* value); + virtual void modified(unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags); }; #endif /* !SEEN_SP_MESHROW_H */ diff --git a/src/sp-mesh.h b/src/sp-mesh.h deleted file mode 100644 index 6f992d034..000000000 --- a/src/sp-mesh.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef SP_MESH_H -#define SP_MESH_H - -/** \file - * SPMesh: SVG <mesh> implementation. - */ - -#include "svg/svg-length.h" -#include "sp-gradient.h" - -#define SP_MESH(obj) (dynamic_cast<SPMesh*>((SPObject*)obj)) -#define SP_IS_MESH(obj) (dynamic_cast<const SPMesh*>((SPObject*)obj) != NULL) - -/** Mesh gradient. */ -class SPMesh : public SPGradient { -public: - SPMesh(); - virtual ~SPMesh(); - - SVGLength x; // Upper left corner of mesh - SVGLength y; // Upper right corner of mesh - SPMeshType type; - bool type_set; - virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); - -protected: - virtual void build(SPDocument *document, Inkscape::XML::Node *repr); - virtual void set(unsigned key, char const *value); - virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags); -}; - -#endif /* !SP_MESH_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-object.cpp b/src/sp-object.cpp index 0cd7b371e..da4367d5b 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -61,6 +61,10 @@ using std::strstr; # define debug(f, a...) /* */ #endif +// Define to enable indented tracing of SPObject. +//#define OBJECT_TRACE +unsigned SPObject::indent_level = 0; + guint update_in_progress = 0; // guard against update-during-update Inkscape::XML::NodeEventVector object_event_vector = { @@ -182,6 +186,10 @@ void SPObject::update(SPCtx* /*ctx*/, unsigned int /*flags*/) { } void SPObject::modified(unsigned int /*flags*/) { +#ifdef OBJECT_TRACE + objectTrace( "SPObject::modified (default) (empty function)" ); + objectTrace( "SPObject::modified (default)", false ); +#endif //throw; } @@ -640,6 +648,10 @@ void SPObject::order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node * / } void SPObject::build(SPDocument *document, Inkscape::XML::Node *repr) { + +#ifdef OBJECT_TRACE + objectTrace( "SPObject::build" ); +#endif SPObject* object = this; /* Nothing specific here */ @@ -665,10 +677,17 @@ void SPObject::build(SPDocument *document, Inkscape::XML::Node *repr) { sp_object_unref(child, NULL); child->invoke_build(document, rchild, object->cloned); } + +#ifdef OBJECT_TRACE + objectTrace( "SPObject::build", false ); +#endif } void SPObject::invoke_build(SPDocument *document, Inkscape::XML::Node *repr, unsigned int cloned) { +#ifdef OBJECT_TRACE + objectTrace( "SPObject::invoke_build" ); +#endif debug("id=%p, typename=%s", this, g_type_name_from_instance((GTypeInstance*)this)); //g_assert(object != NULL); @@ -728,6 +747,10 @@ void SPObject::invoke_build(SPDocument *document, Inkscape::XML::Node *repr, uns /* Signalling (should be connected AFTER processing derived methods */ sp_repr_add_listener(repr, &object_event_vector, this); + +#ifdef OBJECT_TRACE + objectTrace( "SPObject::invoke_build", false ); +#endif } int SPObject::getIntAttribute(char const *key, int def) @@ -835,6 +858,13 @@ void SPObject::repr_order_changed(Inkscape::XML::Node * /*repr*/, Inkscape::XML: } void SPObject::set(unsigned int key, gchar const* value) { + +#ifdef OBJECT_TRACE + std::stringstream temp; + temp << "SPObject::set: " << key << " " << (value?value:"null"); + objectTrace( temp.str() ); +#endif + g_assert(key != SP_ATTR_INVALID); SPObject* object = this; @@ -918,6 +948,9 @@ void SPObject::set(unsigned int key, gchar const* value) { default: break; } +#ifdef OBJECT_TRACE + objectTrace( "SPObject::set", false ); +#endif } void SPObject::setKeyValue(unsigned int key, gchar const *value) @@ -982,6 +1015,10 @@ static gchar const *sp_xml_get_space_string(unsigned int space) } Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { +#ifdef OBJECT_TRACE + objectTrace( "SPObject::write" ); +#endif + if (!repr && (flags & SP_OBJECT_WRITE_BUILD)) { repr = this->getRepr()->duplicate(doc); if (!( flags & SP_OBJECT_WRITE_EXT )) { @@ -1050,38 +1087,68 @@ Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML sp_style_unset_property_attrs (this); } +#ifdef OBJECT_TRACE + objectTrace( "SPObject::write", false ); +#endif return repr; } Inkscape::XML::Node * SPObject::updateRepr(unsigned int flags) { +#ifdef OBJECT_TRACE + objectTrace( "SPObject::updateRepr 1" ); +#endif + if ( !cloned ) { Inkscape::XML::Node *repr = getRepr(); if (repr) { +#ifdef OBJECT_TRACE + objectTrace( "SPObject::updateRepr 1", false ); +#endif return updateRepr(repr->document(), repr, flags); } else { g_critical("Attempt to update non-existent repr"); +#ifdef OBJECT_TRACE + objectTrace( "SPObject::updateRepr 1", false ); +#endif return NULL; } } else { /* cloned objects have no repr */ +#ifdef OBJECT_TRACE + objectTrace( "SPObject::updateRepr 1", false ); +#endif return NULL; } } Inkscape::XML::Node * SPObject::updateRepr(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned int flags) { +#ifdef OBJECT_TRACE + objectTrace( "SPObject::updateRepr 2" ); +#endif + g_assert(doc != NULL); if (cloned) { /* cloned objects have no repr */ +#ifdef OBJECT_TRACE + objectTrace( "SPObject::updateRepr 2", false ); +#endif return NULL; } if (!(flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = getRepr(); } + +#ifdef OBJECT_TRACE + Inkscape::XML::Node *node = write(doc, repr, flags); + objectTrace( "SPObject::updateRepr 2", false ); + return node; +#else return this->write(doc, repr, flags); +#endif } @@ -1101,6 +1168,10 @@ void SPObject::requestDisplayUpdate(unsigned int flags) g_return_if_fail((flags & SP_OBJECT_MODIFIED_FLAG) || (flags & SP_OBJECT_CHILD_MODIFIED_FLAG)); g_return_if_fail(!((flags & SP_OBJECT_MODIFIED_FLAG) && (flags & SP_OBJECT_CHILD_MODIFIED_FLAG))); +#ifdef OBJECT_TRACE + objectTrace( "SPObject::requestDisplayUpdate" ); +#endif + bool already_propagated = (!(this->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))); this->uflags |= flags; @@ -1115,12 +1186,21 @@ void SPObject::requestDisplayUpdate(unsigned int flags) document->requestModified(); } } + +#ifdef OBJECT_TRACE + objectTrace( "SPObject::requestDisplayUpdate", false ); +#endif + } void SPObject::updateDisplay(SPCtx *ctx, unsigned int flags) { g_return_if_fail(!(flags & ~SP_OBJECT_MODIFIED_CASCADE)); +#ifdef OBJECT_TRACE + objectTrace( "SPObject::updateDisplay" ); +#endif + update_in_progress ++; #ifdef SP_OBJECT_DEBUG_CASCADE @@ -1161,6 +1241,10 @@ void SPObject::updateDisplay(SPCtx *ctx, unsigned int flags) } update_in_progress --; + +#ifdef OBJECT_TRACE + objectTrace( "SPObject::updateDisplay", false ); +#endif } void SPObject::requestModified(unsigned int flags) @@ -1173,6 +1257,10 @@ void SPObject::requestModified(unsigned int flags) g_return_if_fail((flags & SP_OBJECT_MODIFIED_FLAG) || (flags & SP_OBJECT_CHILD_MODIFIED_FLAG)); g_return_if_fail(!((flags & SP_OBJECT_MODIFIED_FLAG) && (flags & SP_OBJECT_CHILD_MODIFIED_FLAG))); +#ifdef OBJECT_TRACE + objectTrace( "SPObject::requestModified" ); +#endif + bool already_propagated = (!(this->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))); this->mflags |= flags; @@ -1187,6 +1275,9 @@ void SPObject::requestModified(unsigned int flags) document->requestModified(); } } +#ifdef OBJECT_TRACE + objectTrace( "SPObject::requestModified", false ); +#endif } void SPObject::emitModified(unsigned int flags) @@ -1194,6 +1285,10 @@ void SPObject::emitModified(unsigned int flags) /* only the MODIFIED_CASCADE flag is legal here */ g_return_if_fail(!(flags & ~SP_OBJECT_MODIFIED_CASCADE)); +#ifdef OBJECT_TRACE + objectTrace( "SPObject::emitModified", true, flags ); +#endif + #ifdef SP_OBJECT_DEBUG_CASCADE g_print("Modified %s:%s %x %x %x\n", g_type_name_from_instance((GTypeInstance *) this), getId(), flags, this->uflags, this->mflags); #endif @@ -1210,6 +1305,10 @@ void SPObject::emitModified(unsigned int flags) _modified_signal.emit(this, flags); sp_object_unref(this); + +#ifdef OBJECT_TRACE + objectTrace( "SPObject::emitModified", false ); +#endif } gchar const *SPObject::getTagName(SPException *ex) const @@ -1248,10 +1347,12 @@ void SPObject::setAttribute(gchar const *key, gchar const *value, SPException *e //XML Tree being used here. getRepr()->setAttribute(key, value, false); } + void SPObject::setAttribute(char const *key, Glib::ustring const &value, SPException *ex) { setAttribute(key, value.empty() ? NULL : value.c_str(), ex); } + void SPObject::setAttribute(Glib::ustring const &key, Glib::ustring const &value, SPException *ex) { setAttribute( key.empty() ? NULL : key.c_str(), @@ -1536,6 +1637,34 @@ void SPObject::recursivePrintTree( unsigned level ) } } +// Function to allow tracing of program flow through SPObject and derived classes. +// To trace function, add at entrance ('in' = true) and exit of function ('in' = false). +void SPObject::objectTrace( std::string text, bool in, unsigned flags ) { + if( in ) { + for (unsigned i = 0; i < indent_level; ++i) { + std::cout << " "; + } + std::cout << text << ":" + << " entrance: " + << (id?id:"null") + << " uflags: " << uflags + << " mflags: " << mflags + << " flags: " << flags << std::endl; + ++indent_level; + } else { + --indent_level; + for (unsigned i = 0; i < indent_level; ++i) { + std::cout << " "; + } + std::cout << text << ":" + << " exit: " + << (id?id:"null") + << " uflags: " << uflags + << " mflags: " << mflags + << " flags: " << flags << std::endl; + } +} + /* Local Variables: mode:c++ diff --git a/src/sp-object.h b/src/sp-object.h index 1c6212664..ac3d0c851 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -861,6 +861,8 @@ public: virtual void read_content(); void recursivePrintTree(unsigned level = 0); // For debugging + static unsigned indent_level; + void objectTrace( std::string, bool in=true, unsigned flags=0 ); }; diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp index 40107096f..88dad5354 100644 --- a/src/sp-rect.cpp +++ b/src/sp-rect.cpp @@ -28,6 +28,7 @@ #define noRECT_VERBOSE +//#define OBJECT_TRACE SPRect::SPRect() : SPShape() { } @@ -36,6 +37,10 @@ SPRect::~SPRect() { } void SPRect::build(SPDocument* doc, Inkscape::XML::Node* repr) { +#ifdef OBJECT_TRACE + objectTrace( "SPRect::build" ); +#endif + SPShape::build(doc, repr); this->readAttr("x"); @@ -44,9 +49,20 @@ void SPRect::build(SPDocument* doc, Inkscape::XML::Node* repr) { this->readAttr("height"); this->readAttr("rx"); this->readAttr("ry"); + +#ifdef OBJECT_TRACE + objectTrace( "SPRect::build", false ); +#endif } void SPRect::set(unsigned key, gchar const *value) { + +#ifdef OBJECT_TRACE + std::stringstream temp; + temp << "SPRect::set: " << key << " " << (value?value:"null"); + objectTrace( temp.str() ); +#endif + /* fixme: We need real error processing some time */ // We must update the SVGLengths immediately or nodes may be misplaced after they are moved. @@ -104,9 +120,17 @@ void SPRect::set(unsigned key, gchar const *value) { SPShape::set(key, value); break; } +#ifdef OBJECT_TRACE + objectTrace( "SPRect::set", false ); +#endif } void SPRect::update(SPCtx* ctx, unsigned int flags) { + +#ifdef OBJECT_TRACE + objectTrace( "SPRect::update", true, flags ); +#endif + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx); @@ -127,9 +151,17 @@ void SPRect::update(SPCtx* ctx, unsigned int flags) { } SPShape::update(ctx, flags); +#ifdef OBJECT_TRACE + objectTrace( "SPRect::update", false, flags ); +#endif } Inkscape::XML::Node * SPRect::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + +#ifdef OBJECT_TRACE + objectTrace( "SPRect::write", true, flags ); +#endif + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:rect"); } @@ -151,6 +183,10 @@ Inkscape::XML::Node * SPRect::write(Inkscape::XML::Document *xml_doc, Inkscape:: this->set_shape(); // evaluate SPCurve SPShape::write(xml_doc, repr, flags); +#ifdef OBJECT_TRACE + objectTrace( "SPRect::write", false, flags ); +#endif + return repr; } diff --git a/src/sp-stop.cpp b/src/sp-stop.cpp index d31946b94..58746c951 100644 --- a/src/sp-stop.cpp +++ b/src/sp-stop.cpp @@ -114,6 +114,7 @@ void SPStop::set(unsigned int key, const gchar* value) { // std::cout << "Got Curve" << std::endl; //curve->unref(); //} + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index ed9ec3b0a..7ba6df978 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -134,10 +134,10 @@ void ActionAlign::do_action(SPDesktop *desktop, int index) switch (AlignTarget(prefs->getInt("/dialogs/align/align-to", 6))) { case LAST: - focus = SP_ITEM(*selected.begin()); + focus = SP_ITEM(*--(selected.end())); break; case FIRST: - focus = SP_ITEM(*--(selected.end())); + focus = SP_ITEM(*selected.begin()); break; case BIGGEST: focus = selection->largestItem(horiz); diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 670e4c8b5..64a5d9866 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -145,6 +145,13 @@ Export::Export (void) : browse_image(Gtk::StockID(Gtk::Stock::INDEX), Gtk::ICON_SIZE_BUTTON), batch_box(false, 5), batch_export(_("B_atch export all selected objects"), _("Export each selected object into its own PNG file, using export hints if any (caution, overwrites without asking!)")), + interlacing(_("Use interlacing"),_("Enables ADAM7 interlacing for PNG output. This results in slightly heavier images, but big images will look better sooner when loading the file")), + bitdepth_label(_("Bit depth")), + bitdepth_cb(), + zlib_label(_("Compression")), + zlib_compression(), + pHYs_label(_("pHYs dpi")), + pHYs_sb(pHYs_adj, 1.0, 2), hide_box(false, 5), hide_export(_("Hide a_ll except selected"), _("In the exported image, hide all objects except those that are selected")), closeWhenDone(_("Close when complete"), _("Once the export completes, close this dialog")), @@ -321,6 +328,34 @@ Export::Export (void) : button_box.pack_start(closeWhenDone, true, true, 0 ); button_box.pack_end(export_button, false, false, 0); + /*Advanced*/ + Gtk::Label *label_advanced = Gtk::manage(new Gtk::Label(_("Advanced"),1)); + expander.set_label_widget(*label_advanced); + const char* const modes_list[]={"Gray_1", "Gray_2","Gray_4","Gray_8","Gray_16","RGB_8","RGB_16","GrayAlpha_8","GrayAlpha_16","RGBA_8","RGBA_16"}; + for(int i=0; i<11; ++i) + bitdepth_cb.append(modes_list[i]); + bitdepth_cb.set_active_text("RGBA_8"); + bitdepth_cb.set_hexpand(); + const char* const zlist[]={"Z_NO_COMPRESSION","Z_BEST_SPEED","2","3","4","5","Z_DEFAULT_COMPRESSION","7","8","Z_BEST_COMPRESSION"}; + for(int i=0; i<10; ++i) + zlib_compression.append(zlist[i]); + zlib_compression.set_active_text("Z_DEFAULT_COMPRESSION"); + pHYs_adj = Gtk::Adjustment::create(0, 0, 100000, 0.1, 1.0, 0); + pHYs_sb.set_adjustment(pHYs_adj); + pHYs_sb.set_width_chars(7); + pHYs_sb.set_tooltip_text( _("Will force-set the physical dpi for the png file. Set this to 72 if you're planning to work on your png with Photoshop") ); + zlib_compression.set_hexpand(); + auto table = new Gtk::Grid(); + gtk_container_add(GTK_CONTAINER(expander.gobj()), (GtkWidget*)(table->gobj())); + table->attach(interlacing,0,0,1,1); + table->attach(bitdepth_label,0,1,1,1); + table->attach(bitdepth_cb,1,1,1,1); + table->attach(zlib_label,0,2,1,1); + table->attach(zlib_compression,1,2,1,1); + table->attach(pHYs_label,0,3,1,1); + table->attach(pHYs_sb,1,3,1,1); + table->show(); + /* Main dialog */ Gtk::Box *contents = _getContents(); contents->set_spacing(0); @@ -329,6 +364,7 @@ Export::Export (void) : contents->pack_start(hide_box); contents->pack_end(button_box, false, 0); contents->pack_end(_prog, Gtk::PACK_EXPAND_WIDGET); + contents->pack_end(expander, FALSE, FALSE,0); /* Signal handlers */ filename_entry.signal_changed().connect( sigc::mem_fun(*this, &Export::onFilenameModified) ); @@ -943,6 +979,18 @@ void Export::onExport () bool exportSuccessful = false; bool hide = hide_export.get_active (); + + // Advanced parameters + bool do_interlace = (interlacing.get_active()); + float pHYs = 0; + int zlib = zlib_compression.get_active_row_number() ; + const char* const modes_list[]={"Gray_1", "Gray_2","Gray_4","Gray_8","Gray_16","RGB_8","RGB_16","GrayAlpha_8","GrayAlpha_16","RGBA_8","RGBA_16"}; + int colortypes[] = {0,0,0,0,0,2,2,4,4,6,6}; //keep in sync with modes_list in Export constructor. values are from libpng doc. + int bitdepths[] = {1,2,4,8,16,8,16,8,16,8,16}; + int color_type = colortypes[bitdepth_cb.get_active_row_number()] ; + int bit_depth = bitdepths[bitdepth_cb.get_active_row_number()] ; + + if (batch_export.get_active ()) { // Batch export of selected objects @@ -987,6 +1035,7 @@ void Export::onExport () if (dpi == 0.0) { dpi = getValue(xdpi_adj); } + pHYs = (pHYs_adj->get_value() > 0.01) ? pHYs_adj->get_value() : dpi; Geom::OptRect area = item->desktopVisualBounds(); if (area) { @@ -1003,11 +1052,12 @@ void Export::onExport () std::vector<SPItem*> x; std::vector<SPItem*> selected(desktop->getSelection()->items().begin(), desktop->getSelection()->items().end()); if (!sp_export_png_file (doc, path.c_str(), - *area, width, height, dpi, dpi, + *area, width, height, pHYs, pHYs, nv->pagecolor, onProgressCallback, (void*)prog_dlg, TRUE, // overwrite without asking - hide ? selected : x + hide ? selected : x, + do_interlace, color_type, bit_depth, zlib )) { gchar * error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile); @@ -1049,6 +1099,7 @@ void Export::onExport () float const y1 = getValuePx(y1_adj); float const xdpi = getValue(xdpi_adj); float const ydpi = getValue(ydpi_adj); + pHYs = (pHYs_adj->get_value() > 0.01) ? pHYs_adj->get_value() : xdpi; unsigned long int const width = int(getValue(bmwidth_adj) + 0.5); unsigned long int const height = int(getValue(bmheight_adj) + 0.5); @@ -1094,12 +1145,13 @@ void Export::onExport () std::vector<SPItem*> x; std::vector<SPItem*> selected(desktop->getSelection()->items().begin(), desktop->getSelection()->items().end()); ExportResult status = sp_export_png_file(desktop->getDocument(), path.c_str(), - Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1)), width, height, xdpi, ydpi, + Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1)), width, height, pHYs, pHYs, //previously xdpi, ydpi. nv->pagecolor, onProgressCallback, (void*)prog_dlg, FALSE, - hide ? selected : x - ); + hide ? selected : x, + do_interlace, color_type, bit_depth, zlib + ); if (status == EXPORT_ERROR) { gchar * safeFile = Inkscape::IO::sanitizeString(path.c_str()); gchar * error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile); diff --git a/src/ui/dialog/export.h b/src/ui/dialog/export.h index a1c44714b..112f42312 100644 --- a/src/ui/dialog/export.h +++ b/src/ui/dialog/export.h @@ -13,6 +13,9 @@ #define SP_EXPORT_H #include <gtkmm/progressbar.h> +#include <gtkmm/expander.h> +#include <gtkmm/grid.h> +#include <gtkmm/comboboxtext.h> #include "ui/dialog/desktop-tracker.h" #include "ui/widget/panel.h" @@ -314,6 +317,17 @@ private: Inkscape::UI::Widget::CheckButton closeWhenDone; + /* Advanced */ + Gtk::Expander expander; + Inkscape::UI::Widget::CheckButton interlacing; + Gtk::Label bitdepth_label; + Gtk::ComboBoxText bitdepth_cb; + Gtk::Label zlib_label; + Gtk::ComboBoxText zlib_compression; + Gtk::Label pHYs_label; + Glib::RefPtr<Gtk::Adjustment> pHYs_adj; + Gtk::SpinButton pHYs_sb; + /* Export Button widgets */ Gtk::HBox button_box; Gtk::Button export_button; diff --git a/src/ui/dialog/xml-tree.cpp b/src/ui/dialog/xml-tree.cpp index eae33ff83..d05c52531 100644 --- a/src/ui/dialog/xml-tree.cpp +++ b/src/ui/dialog/xml-tree.cpp @@ -790,7 +790,8 @@ void XmlTree::on_attr_row_changed(SPXMLViewAttrList *attributes, const gchar * n void XmlTree::on_attr_unselect_row_clear_text() { attr_name.set_text(""); - attr_value.get_buffer()->set_text("", 0); + // Set text with empty Glib::ustring + attr_value.get_buffer()->set_text( Glib::ustring() ); } void XmlTree::onNameChanged() diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index a084a8fd9..16df225e0 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -871,6 +871,7 @@ bool GradientTool::root_handler(GdkEvent* event) { return ret; } +// Creates a new linear or radial gradient. static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*state*/, guint32 etime) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index f2cf8c4a2..aac8239f3 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -47,7 +47,7 @@ // Mesh specific #include "ui/tools/mesh-tool.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "display/sp-ctrlcurve.h" using Inkscape::DocumentUndo; @@ -161,9 +161,9 @@ void MeshTool::selection_changed(Inkscape::Selection* /*sel*/) { // if (style && (style->fill.isPaintserver())) { // SPPaintServer *server = item->style->getFillPaintServer(); - // if ( SP_IS_MESH(server) ) { + // if ( SP_IS_MESHGRADIENT(server) ) { - // SPMesh *mg = SP_MESH(server); + // SPMeshGradient *mg = SP_MESHGRADIENT(server); // guint rows = 0;//mg->array.patches.size(); // for ( guint i = 0; i < rows; ++i ) { @@ -265,14 +265,18 @@ sp_mesh_context_select_prev (ToolBase *event_context) Returns true if mouse cursor over mesh edge. */ static bool -sp_mesh_context_is_over_line (MeshTool *rc, SPItem *item, Geom::Point event_p) +sp_mesh_context_is_over_line (MeshTool *rc, SPCtrlLine *line, Geom::Point event_p) { + if (!SP_IS_CTRLCURVE(line) ) { + return false; + } + SPDesktop *desktop = SP_EVENT_CONTEXT (rc)->desktop; //Translate mouse point into proper coord system rc->mousepoint_doc = desktop->w2d(event_p); - SPCtrlCurve *curve = SP_CTRLCURVE(item); + SPCtrlCurve *curve = SP_CTRLCURVE(line); Geom::BezierCurveN<3> b( curve->p0, curve->p1, curve->p2, curve->p3 ); Geom::Coord coord = b.nearestTime( rc->mousepoint_doc ); // Coord == double Geom::Point nearest = b( coord ); @@ -326,8 +330,8 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation ) SPDocument *doc = NULL; GrDrag *drag = rc->_grdrag; - std::map<SPMesh*, std::vector<guint> > points; - std::map<SPMesh*, SPItem*> items; + std::map<SPMeshGradient*, std::vector<guint> > points; + std::map<SPMeshGradient*, SPItem*> items; // Get list of selected draggers for each mesh. // For all selected draggers @@ -341,7 +345,7 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation ) if( d->point_type != POINT_MG_CORNER ) continue; // Find the gradient - SPMesh *gradient = SP_MESH( getGradient (d->item, d->fill_or_stroke) ); + SPMeshGradient *gradient = SP_MESHGRADIENT( getGradient (d->item, d->fill_or_stroke) ); // Collect points together for same gradient points[gradient].push_back( d->point_i ); @@ -350,8 +354,8 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation ) } // Loop over meshes. - for( std::map<SPMesh*, std::vector<guint> >::const_iterator iter = points.begin(); iter != points.end(); ++iter) { - SPMesh *mg = SP_MESH( iter->first ); + for( std::map<SPMeshGradient*, std::vector<guint> >::const_iterator iter = points.begin(); iter != points.end(); ++iter) { + SPMeshGradient *mg = SP_MESHGRADIENT( iter->first ); if( iter->second.size() > 0 ) { guint noperation = 0; switch (operation) { @@ -425,6 +429,7 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation ) /** Handles all keyboard and mouse input for meshs. +Note: node/handle events are take care of elsewhere. */ bool MeshTool::root_handler(GdkEvent* event) { static bool dragging; @@ -454,12 +459,10 @@ bool MeshTool::root_handler(GdkEvent* event) { if ( event->button.button == 1 ) { // Are we over a mesh line? bool over_line = false; - SPCtrlCurve *line = NULL; if (! drag->lines.empty()) { for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) { - line = (SPCtrlCurve*) (*l); - over_line |= sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); + over_line |= sp_mesh_context_is_over_line (this, *l, Geom::Point(event->motion.x, event->motion.y)); } } @@ -594,7 +597,7 @@ bool MeshTool::root_handler(GdkEvent* event) { if (!drag->lines.empty()) { for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() ; ++l) { - over_line |= sp_mesh_context_is_over_line (this, (SPItem*)(*l), Geom::Point(event->motion.x, event->motion.y)); + over_line |= sp_mesh_context_is_over_line (this, *l, Geom::Point(event->motion.x, event->motion.y)); } } @@ -625,8 +628,7 @@ bool MeshTool::root_handler(GdkEvent* event) { if (!drag->lines.empty()) { for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) { - line = (SPCtrlLine*)(*l); - over_line = sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); + over_line = sp_mesh_context_is_over_line (this, *l, Geom::Point(event->motion.x, event->motion.y)); if (over_line) { break; @@ -925,6 +927,7 @@ bool MeshTool::root_handler(GdkEvent* event) { return ret; } +// Creates a new mesh gradient. static void sp_mesh_end_drag(MeshTool &rc) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; Inkscape::Selection *selection = desktop->getSelection(); diff --git a/src/ui/widget/selected-style.cpp b/src/ui/widget/selected-style.cpp index fd83a62c9..301a3b2e0 100644 --- a/src/ui/widget/selected-style.cpp +++ b/src/ui/widget/selected-style.cpp @@ -25,7 +25,7 @@ #include "sp-namedview.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "sp-pattern.h" #include "ui/dialog/dialog-manager.h" #include "ui/dialog/fill-and-stroke.h" @@ -1010,7 +1010,7 @@ SelectedStyle::update() place->set_tooltip_text(__rgradient[i]); _mode[i] = SS_RGRADIENT; #ifdef WITH_MESH - } else if (SP_IS_MESH(server)) { + } else if (SP_IS_MESHGRADIENT(server)) { SPGradient *vector = SP_GRADIENT(server)->getVector(); sp_gradient_image_set_gradient(SP_GRADIENT_IMAGE(_gradient_preview_m[i]), vector); place->add(_gradient_box_m[i]); diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp index fb540b5f5..0e689fee0 100644 --- a/src/widgets/mesh-toolbar.cpp +++ b/src/widgets/mesh-toolbar.cpp @@ -41,7 +41,7 @@ #include "ui/tools/gradient-tool.h" #include "ui/tools/mesh-tool.h" #include "gradient-drag.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "gradient-chemistry.h" #include "ui/icon-names.h" @@ -70,7 +70,7 @@ static bool blocked = false; * Get the current selection and dragger status from the desktop */ void ms_read_selection( Inkscape::Selection *selection, - SPMesh *&ms_selected, + SPMeshGradient *&ms_selected, bool &ms_selected_multi, SPMeshType &ms_type, bool &ms_type_multi ) @@ -87,9 +87,9 @@ void ms_read_selection( Inkscape::Selection *selection, if (style && (style->fill.isPaintserver())) { SPPaintServer *server = item->style->getFillPaintServer(); - if ( SP_IS_MESH(server) ) { + if ( SP_IS_MESHGRADIENT(server) ) { - SPMesh *gradient = SP_MESH(server); // ->getVector(); + SPMeshGradient *gradient = SP_MESHGRADIENT(server); // ->getVector(); SPMeshType type = gradient->type; if (gradient != ms_selected) { @@ -112,9 +112,9 @@ void ms_read_selection( Inkscape::Selection *selection, if (style && (style->stroke.isPaintserver())) { SPPaintServer *server = item->style->getStrokePaintServer(); - if ( SP_IS_MESH(server) ) { + if ( SP_IS_MESHGRADIENT(server) ) { - SPMesh *gradient = SP_MESH(server); // ->getVector(); + SPMeshGradient *gradient = SP_MESHGRADIENT(server); // ->getVector(); SPMeshType type = gradient->type; if (gradient != ms_selected) { @@ -164,7 +164,7 @@ static void ms_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe // // Hide/show handles? // } - SPMesh *ms_selected = 0; + SPMeshGradient *ms_selected = 0; SPMeshType ms_type = SP_MESH_TYPE_COONS; bool ms_selected_multi = false; bool ms_type_multi = false; @@ -203,9 +203,9 @@ static void ms_defs_modified(SPObject * /*defs*/, guint /*flags*/, GObject *widg ms_tb_selection_changed(NULL, widget); } -void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMesh *&ms_selected) +void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMeshGradient *&ms_selected) { - SPMesh *gradient = 0; + SPMeshGradient *gradient = 0; auto itemlist= selection->items(); for(auto i=itemlist.begin();i!=itemlist.end();++i){ @@ -220,8 +220,8 @@ void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMesh *&ms_sel server = item->style->getStrokePaintServer(); } - if ( SP_IS_MESH(server) ) { - gradient = SP_MESH(server); + if ( SP_IS_MESHGRADIENT(server) ) { + gradient = SP_MESHGRADIENT(server); } } @@ -295,7 +295,7 @@ static void ms_type_changed(EgeSelectOneAction *act, GtkWidget *widget) SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(G_OBJECT(widget), "desktop")); Inkscape::Selection *selection = desktop->getSelection(); - SPMesh *gradient = 0; + SPMeshGradient *gradient = 0; ms_get_dt_selected_gradient(selection, gradient); if (gradient) { diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 01118f337..ddac90730 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -33,7 +33,7 @@ #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "sp-mesh.h" +#include "sp-mesh-gradient.h" #include "sp-stop.h" /* fixme: Move it from dialogs to here */ #include "gradient-selector.h" @@ -1221,7 +1221,7 @@ SPPaintSelector::Mode SPPaintSelector::getModeForStyle(SPStyle const & style, Fi } else if (SP_IS_RADIALGRADIENT(server)) { mode = MODE_GRADIENT_RADIAL; #ifdef WITH_MESH - } else if (SP_IS_MESH(server)) { + } else if (SP_IS_MESHGRADIENT(server)) { mode = MODE_GRADIENT_MESH; #endif } else if (SP_IS_PATTERN(server)) { |
