summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorMichael Soegtrop <MSoegtrop@yahoo.de>2017-06-05 13:01:17 +0000
committerMichael Soegtrop <MSoegtrop@yahoo.de>2017-06-05 13:01:17 +0000
commite7248b2fa042f42a5c4dd14cd86ab6a5b4524059 (patch)
tree9097520c54e355ded9bd0b4d6618af4e8dacdd91 /src/display
parentupdated to latest trunk (diff)
parent[Bug #1695016] Xaml export misses some radialGradients. (diff)
downloadinkscape-e7248b2fa042f42a5c4dd14cd86ab6a5b4524059.tar.gz
inkscape-e7248b2fa042f42a5c4dd14cd86ab6a5b4524059.zip
updated to latest trunk
(bzr r14876.2.4)
Diffstat (limited to 'src/display')
-rw-r--r--src/display/CMakeLists.txt4
-rw-r--r--src/display/Makefile_insert125
-rw-r--r--src/display/cairo-utils.cpp87
-rw-r--r--src/display/cairo-utils.h2
-rw-r--r--src/display/canvas-axonomgrid.cpp46
-rw-r--r--src/display/canvas-bpath.cpp34
-rw-r--r--src/display/canvas-bpath.h6
-rw-r--r--src/display/canvas-debug.cpp100
-rw-r--r--src/display/canvas-debug.h41
-rw-r--r--src/display/canvas-grid.cpp331
-rw-r--r--src/display/canvas-grid.h12
-rw-r--r--src/display/canvas-rotate.cpp288
-rw-r--r--src/display/canvas-rotate.h50
-rw-r--r--src/display/canvas-text.cpp2
-rw-r--r--src/display/curve.cpp26
-rw-r--r--src/display/curve.h2
-rw-r--r--src/display/drawing-group.cpp3
-rw-r--r--src/display/drawing-image.cpp10
-rw-r--r--src/display/drawing-item.cpp23
-rw-r--r--src/display/drawing-item.h4
-rw-r--r--src/display/drawing-shape.cpp12
-rw-r--r--src/display/drawing-text.cpp15
-rw-r--r--src/display/drawing.cpp6
-rw-r--r--src/display/drawing.h2
-rw-r--r--src/display/gnome-canvas-acetate.cpp8
-rw-r--r--src/display/guideline.cpp106
-rw-r--r--src/display/nr-filter-turbulence.cpp12
-rw-r--r--src/display/nr-filter-utils.h2
-rw-r--r--src/display/nr-filter.cpp5
-rw-r--r--src/display/nr-svgfonts.cpp75
-rw-r--r--src/display/nr-svgfonts.h3
-rw-r--r--src/display/snap-indicator.cpp4
-rw-r--r--src/display/sodipodi-ctrl.cpp74
-rw-r--r--src/display/sodipodi-ctrl.h2
-rw-r--r--src/display/sodipodi-ctrlrect.cpp262
-rw-r--r--src/display/sodipodi-ctrlrect.h11
-rw-r--r--src/display/sp-canvas.cpp178
-rw-r--r--src/display/sp-canvas.h17
-rw-r--r--src/display/sp-ctrlcurve.cpp2
-rw-r--r--src/display/sp-ctrlcurve.h3
-rw-r--r--src/display/sp-ctrlline.cpp3
-rw-r--r--src/display/sp-ctrlline.h2
42 files changed, 1288 insertions, 712 deletions
diff --git a/src/display/CMakeLists.txt b/src/display/CMakeLists.txt
index 0bf1d6e45..8eaaee99a 100644
--- a/src/display/CMakeLists.txt
+++ b/src/display/CMakeLists.txt
@@ -4,7 +4,9 @@ set(display_SRC
canvas-arena.cpp
canvas-axonomgrid.cpp
canvas-bpath.cpp
+ canvas-debug.cpp
canvas-grid.cpp
+ canvas-rotate.cpp
canvas-temporary-item-list.cpp
canvas-temporary-item.cpp
canvas-text.cpp
@@ -64,7 +66,9 @@ set(display_SRC
canvas-arena.h
canvas-axonomgrid.h
canvas-bpath.h
+ canvas-debug.h
canvas-grid.h
+ canvas-rotate.h
canvas-temporary-item-list.h
canvas-temporary-item.h
canvas-text.h
diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert
deleted file mode 100644
index 419852f7d..000000000
--- a/src/display/Makefile_insert
+++ /dev/null
@@ -1,125 +0,0 @@
-## Makefile.am fragment sourced by src/Makefile.am.
-
-display/canvas-arena.$(OBJEXT): helper/sp-marshal.h
-display/sp-canvas.$(OBJEXT): helper/sp-marshal.h
-
-ink_common_sources += \
- display/cairo-templates.h \
- display/cairo-utils.cpp \
- display/cairo-utils.h \
- display/canvas-arena.cpp \
- display/canvas-arena.h \
- display/canvas-axonomgrid.cpp \
- display/canvas-axonomgrid.h \
- display/canvas-bpath.cpp \
- display/canvas-bpath.h \
- display/canvas-grid.cpp \
- display/canvas-grid.h \
- display/canvas-temporary-item.cpp \
- display/canvas-temporary-item.h \
- display/canvas-temporary-item-list.cpp \
- display/canvas-temporary-item-list.h \
- display/canvas-text.cpp \
- display/canvas-text.h \
- display/curve.cpp \
- display/curve.h \
- display/drawing.cpp \
- display/drawing.h \
- display/drawing-context.cpp \
- display/drawing-context.h \
- display/drawing-group.cpp \
- display/drawing-group.h \
- display/drawing-image.cpp \
- display/drawing-image.h \
- display/drawing-item.cpp \
- display/drawing-item.h \
- display/drawing-pattern.cpp \
- display/drawing-pattern.h \
- display/drawing-shape.cpp \
- display/drawing-shape.h \
- display/drawing-surface.cpp \
- display/drawing-surface.h \
- display/drawing-text.cpp \
- display/drawing-text.h \
- display/gnome-canvas-acetate.cpp \
- display/gnome-canvas-acetate.h \
- display/grayscale.cpp \
- display/grayscale.h \
- display/guideline.cpp \
- display/guideline.h \
- display/nr-3dutils.cpp \
- display/nr-3dutils.h \
- display/nr-filter-blend.cpp \
- display/nr-filter-blend.h \
- display/nr-filter-colormatrix.cpp \
- display/nr-filter-colormatrix.h \
- display/nr-filter-component-transfer.cpp \
- display/nr-filter-component-transfer.h \
- display/nr-filter-composite.cpp \
- display/nr-filter-composite.h \
- display/nr-filter-convolve-matrix.cpp \
- display/nr-filter-convolve-matrix.h \
- display/nr-filter.cpp \
- display/nr-filter-diffuselighting.cpp \
- display/nr-filter-diffuselighting.h \
- display/nr-filter-displacement-map.cpp \
- display/nr-filter-displacement-map.h \
- display/nr-filter-flood.cpp \
- display/nr-filter-flood.h \
- display/nr-filter-gaussian.cpp \
- display/nr-filter-gaussian.h \
- display/nr-filter.h \
- display/nr-filter-image.cpp \
- display/nr-filter-image.h \
- display/nr-filter-merge.cpp \
- display/nr-filter-merge.h \
- display/nr-filter-morphology.cpp \
- display/nr-filter-morphology.h \
- display/nr-filter-offset.cpp \
- display/nr-filter-offset.h \
- display/nr-filter-primitive.cpp \
- display/nr-filter-primitive.h \
- display/nr-filter-slot.cpp \
- display/nr-filter-slot.h \
- display/nr-filter-specularlighting.cpp \
- display/nr-filter-specularlighting.h \
- display/nr-filter-tile.cpp \
- display/nr-filter-tile.h \
- display/nr-filter-turbulence.cpp \
- display/nr-filter-turbulence.h \
- display/nr-filter-types.h \
- display/nr-filter-units.cpp \
- display/nr-filter-units.h \
- display/nr-filter-utils.h \
- display/nr-light.cpp \
- display/nr-light.h \
- display/nr-light-types.h \
- display/nr-style.cpp \
- display/nr-style.h \
- display/nr-svgfonts.cpp \
- display/nr-svgfonts.h \
- display/rendermode.h \
- display/snap-indicator.cpp \
- display/snap-indicator.h \
- display/sodipodi-ctrl.cpp \
- display/sodipodi-ctrl.h \
- display/sodipodi-ctrlrect.cpp \
- display/sodipodi-ctrlrect.h \
- display/sp-canvas.cpp \
- display/sp-canvas.h \
- display/sp-canvas-item.h \
- display/sp-canvas-group.h \
- display/sp-canvas-util.cpp \
- display/sp-canvas-util.h \
- display/sp-ctrlcurve.cpp \
- display/sp-ctrlcurve.h \
- display/sp-ctrlline.cpp \
- display/sp-ctrlline.h \
- display/sp-ctrlquadr.cpp \
- display/sp-ctrlquadr.h
-
-# ######################
-# ### CxxTest stuff ####
-# ######################
-CXXTEST_TESTSUITES += \
- $(srcdir)/display/curve-test.h
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp
index 24a75de4c..8045007e7 100644
--- a/src/display/cairo-utils.cpp
+++ b/src/display/cairo-utils.cpp
@@ -290,7 +290,7 @@ Pixbuf *Pixbuf::create_from_file(std::string const &fn)
if (!g_file_test(fn.c_str(), G_FILE_TEST_EXISTS)) {
return NULL;
}
- struct stat stdir;
+ GStatBuf stdir;
int val = g_stat(fn.c_str(), &stdir);
if (val == 0 && stdir.st_mode & S_IFDIR){
return NULL;
@@ -1321,6 +1321,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/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp
index 14f36376f..589cc849d 100644
--- a/src/display/canvas-axonomgrid.cpp
+++ b/src/display/canvas-axonomgrid.cpp
@@ -19,12 +19,7 @@
#include <gtkmm/box.h>
#include <gtkmm/label.h>
-
-#if WITH_GTKMM_3_0
-# include <gtkmm/grid.h>
-#else
-# include <gtkmm/table.h>
-#endif
+#include <gtkmm/grid.h>
#include <glibmm/i18n.h>
@@ -47,7 +42,6 @@
#include "2geom/line.h"
#include "2geom/angle.h"
#include "helper/mathfns.h"
-#include "round.h"
#include "util/units.h"
using Inkscape::Util::unit_table;
@@ -94,15 +88,10 @@ namespace Inkscape {
#define SPACE_SIZE_X 15
#define SPACE_SIZE_Y 10
static inline void
-#if WITH_GTKMM_3_0
attach_all(Gtk::Grid &table, Gtk::Widget const *const arr[], unsigned size, int start = 0)
-#else
-attach_all(Gtk::Table &table, Gtk::Widget const *const arr[], unsigned size, int start = 0)
-#endif
{
for (unsigned i=0, r=start; i<size/sizeof(Gtk::Widget*); i+=2) {
if (arr[i] && arr[i+1]) {
-#if WITH_GTKMM_3_0
(const_cast<Gtk::Widget&>(*arr[i])).set_hexpand();
(const_cast<Gtk::Widget&>(*arr[i])).set_valign(Gtk::ALIGN_CENTER);
table.attach(const_cast<Gtk::Widget&>(*arr[i]), 1, r, 1, 1);
@@ -110,44 +99,28 @@ attach_all(Gtk::Table &table, Gtk::Widget const *const arr[], unsigned size, int
(const_cast<Gtk::Widget&>(*arr[i+1])).set_hexpand();
(const_cast<Gtk::Widget&>(*arr[i+1])).set_valign(Gtk::ALIGN_CENTER);
table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 2, r, 1, 1);
-#else
- table.attach (const_cast<Gtk::Widget&>(*arr[i]), 1, 2, r, r+1,
- Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
- table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 2, 3, r, r+1,
- Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
-#endif
} else {
if (arr[i+1]) {
-#if WITH_GTKMM_3_0
(const_cast<Gtk::Widget&>(*arr[i+1])).set_hexpand();
(const_cast<Gtk::Widget&>(*arr[i+1])).set_valign(Gtk::ALIGN_CENTER);
table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 1, r, 2, 1);
-#else
- table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 1, 3, r, r+1,
- Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
-#endif
} else if (arr[i]) {
Gtk::Label& label = reinterpret_cast<Gtk::Label&> (const_cast<Gtk::Widget&>(*arr[i]));
+#if GTK_CHECK_VERSION(3,16,0)
+ label.set_xalign(0.0);
+ label.set_yalign(0.5);
+#else
label.set_alignment (0.0);
-#if WITH_GTKMM_3_0
+#endif
label.set_hexpand();
label.set_valign(Gtk::ALIGN_CENTER);
table.attach(label, 0, r, 3, 1);
-#else
- table.attach (label, 0, 3, r, r+1,
- Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
-#endif
} else {
Gtk::HBox *space = Gtk::manage (new Gtk::HBox);
space->set_size_request (SPACE_SIZE_X, SPACE_SIZE_Y);
-#if WITH_GTKMM_3_0
space->set_halign(Gtk::ALIGN_CENTER);
space->set_valign(Gtk::ALIGN_CENTER);
table.attach(*space, 0, r, 1, 1);
-#else
- table.attach (*space, 0, 1, r, r+1,
- (Gtk::AttachOptions)0, (Gtk::AttachOptions)0,0,0);
-#endif
}
}
++r;
@@ -342,14 +315,9 @@ CanvasAxonomGrid::onReprAttrChanged(Inkscape::XML::Node */*repr*/, gchar const *
Gtk::Widget *
CanvasAxonomGrid::newSpecificWidget()
{
-#if WITH_GTKMM_3_0
- Gtk::Grid *table = Gtk::manage(new Gtk::Grid());
+ auto table = Gtk::manage(new Gtk::Grid());
table->set_row_spacing(2);
table->set_column_spacing(2);
-#else
- Gtk::Table * table = Gtk::manage( new Gtk::Table(1,1) );
- table->set_spacings(2);
-#endif
_wr.setUpdating (true);
diff --git a/src/display/canvas-bpath.cpp b/src/display/canvas-bpath.cpp
index 46b59d25a..fc6b79b43 100644
--- a/src/display/canvas-bpath.cpp
+++ b/src/display/canvas-bpath.cpp
@@ -53,6 +53,7 @@ sp_canvas_bpath_init (SPCanvasBPath * bpath)
bpath->stroke_linejoin = SP_STROKE_LINEJOIN_MITER;
bpath->stroke_linecap = SP_STROKE_LINECAP_BUTT;
bpath->stroke_miterlimit = 11.0;
+ bpath->phantom_line = false;
}
static void sp_canvas_bpath_destroy(SPCanvasItem *object)
@@ -71,7 +72,7 @@ static void sp_canvas_bpath_update(SPCanvasItem *item, Geom::Affine const &affin
{
SPCanvasBPath *cbp = SP_CANVAS_BPATH(item);
- item->canvas->requestRedraw((int)item->x1, (int)item->y1, (int)item->x2, (int)item->y2);
+ item->canvas->requestRedraw((int)item->x1 - 1, (int)item->y1 - 1, (int)item->x2 + 1 , (int)item->y2 + 1);
if (reinterpret_cast<SPCanvasItemClass *>(sp_canvas_bpath_parent_class)->update) {
reinterpret_cast<SPCanvasItemClass *>(sp_canvas_bpath_parent_class)->update(item, affine, flags);
@@ -86,10 +87,10 @@ static void sp_canvas_bpath_update(SPCanvasItem *item, Geom::Affine const &affin
Geom::OptRect bbox = bounds_exact_transformed(cbp->curve->get_pathvector(), affine);
if (bbox) {
- item->x1 = (int)bbox->min()[Geom::X] - 1;
- item->y1 = (int)bbox->min()[Geom::Y] - 1;
- item->x2 = (int)bbox->max()[Geom::X] + 1;
- item->y2 = (int)bbox->max()[Geom::Y] + 1;
+ item->x1 = (int)floor(bbox->min()[Geom::X]) - 1;
+ item->y1 = (int)floor(bbox->min()[Geom::Y]) - 1;
+ item->x2 = (int)ceil(bbox->max()[Geom::X]) + 1;
+ item->y2 = (int)ceil(bbox->max()[Geom::Y]) + 1;
} else {
item->x1 = 0;
item->y1 = 0;
@@ -131,7 +132,21 @@ sp_canvas_bpath_render (SPCanvasItem *item, SPCanvasBuf *buf)
cairo_fill_preserve(buf->ct);
}
- if (dostroke) {
+ if (dostroke && cbp->phantom_line) {
+ ink_cairo_set_source_rgba32(buf->ct, 0xffffff4d);
+ cairo_set_line_width(buf->ct, 2);
+ if (cbp->dashes[0] != 0 && cbp->dashes[1] != 0) {
+ cairo_set_dash (buf->ct, cbp->dashes, 2, 0);
+ }
+ cairo_stroke(buf->ct);
+ cairo_set_tolerance(buf->ct, 0.5);
+ cairo_new_path(buf->ct);
+ feed_pathvector_to_cairo (buf->ct, cbp->curve->get_pathvector(), cbp->affine, area,
+ /* optimized_stroke = */ !dofill, 1);
+ ink_cairo_set_source_rgba32(buf->ct, cbp->stroke_rgba);
+ cairo_set_line_width(buf->ct, 1);
+ cairo_stroke(buf->ct);
+ } else if (dostroke) {
ink_cairo_set_source_rgba32(buf->ct, cbp->stroke_rgba);
cairo_set_line_width(buf->ct, 1);
if (cbp->dashes[0] != 0 && cbp->dashes[1] != 0) {
@@ -167,24 +182,25 @@ sp_canvas_bpath_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_
}
SPCanvasItem *
-sp_canvas_bpath_new (SPCanvasGroup *parent, SPCurve *curve)
+sp_canvas_bpath_new (SPCanvasGroup *parent, SPCurve *curve, bool phantom_line)
{
g_return_val_if_fail (parent != NULL, NULL);
g_return_val_if_fail (SP_IS_CANVAS_GROUP (parent), NULL);
SPCanvasItem *item = sp_canvas_item_new (parent, SP_TYPE_CANVAS_BPATH, NULL);
- sp_canvas_bpath_set_bpath (SP_CANVAS_BPATH (item), curve);
+ sp_canvas_bpath_set_bpath (SP_CANVAS_BPATH (item), curve, phantom_line);
return item;
}
void
-sp_canvas_bpath_set_bpath (SPCanvasBPath *cbp, SPCurve *curve)
+sp_canvas_bpath_set_bpath (SPCanvasBPath *cbp, SPCurve *curve, bool phantom_line)
{
g_return_if_fail (cbp != NULL);
g_return_if_fail (SP_IS_CANVAS_BPATH (cbp));
+ cbp->phantom_line = phantom_line;
if (cbp->curve) {
cbp->curve = cbp->curve->unref();
}
diff --git a/src/display/canvas-bpath.h b/src/display/canvas-bpath.h
index 72eca6eeb..686eb7c5a 100644
--- a/src/display/canvas-bpath.h
+++ b/src/display/canvas-bpath.h
@@ -80,7 +80,7 @@ struct SPCanvasBPath {
SPStrokeJoinType stroke_linejoin;
SPStrokeCapType stroke_linecap;
gdouble stroke_miterlimit;
-
+ bool phantom_line;
/* State */
Shape *fill_shp;
Shape *stroke_shp;
@@ -92,9 +92,9 @@ struct SPCanvasBPathClass {
GType sp_canvas_bpath_get_type (void);
-SPCanvasItem *sp_canvas_bpath_new (SPCanvasGroup *parent, SPCurve *curve);
+SPCanvasItem *sp_canvas_bpath_new (SPCanvasGroup *parent, SPCurve *curve, bool phantom_line = false);
-void sp_canvas_bpath_set_bpath (SPCanvasBPath *cbp, SPCurve *curve);
+void sp_canvas_bpath_set_bpath (SPCanvasBPath *cbp, SPCurve *curve, bool phantom_line = false);
void sp_canvas_bpath_set_fill (SPCanvasBPath *cbp, guint32 rgba, SPWindRule rule);
void sp_canvas_bpath_set_stroke (SPCanvasBPath *cbp, guint32 rgba, gdouble width, SPStrokeJoinType join, SPStrokeCapType cap, double dash=0, double gap=0);
diff --git a/src/display/canvas-debug.cpp b/src/display/canvas-debug.cpp
new file mode 100644
index 000000000..1748029e9
--- /dev/null
+++ b/src/display/canvas-debug.cpp
@@ -0,0 +1,100 @@
+/*
+ * A simple surface for debugging the canvas. Shows how tiles are drawn.
+ *
+ * Author:
+ * Tavmjong Bah <tavmjong@free.fr>
+ *
+ * Copyright (C) 2017 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "inkscape.h"
+#include "desktop.h"
+
+#include "canvas-debug.h"
+#include "sp-canvas.h"
+#include "cairo-utils.h"
+#include "ui/event-debug.h"
+
+namespace {
+
+static void sp_canvas_debug_destroy(SPCanvasItem *item);
+static void sp_canvas_debug_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
+static void sp_canvas_debug_render (SPCanvasItem *item, SPCanvasBuf *buf);
+static int sp_canvas_debug_event (SPCanvasItem *item, GdkEvent *event);
+
+} // namespace
+
+G_DEFINE_TYPE(SPCanvasDebug, sp_canvas_debug, SP_TYPE_CANVAS_ITEM);
+
+static void sp_canvas_debug_class_init (SPCanvasDebugClass *klass)
+{
+ klass->destroy = sp_canvas_debug_destroy;
+ klass->update = sp_canvas_debug_update;
+ klass->render = sp_canvas_debug_render;
+ klass->event = sp_canvas_debug_event;
+}
+
+static void sp_canvas_debug_init (SPCanvasDebug *debug)
+{
+ debug->pickable = true; // So we can receive events.
+}
+
+namespace {
+static void sp_canvas_debug_destroy (SPCanvasItem *object)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (SP_IS_CANVAS_DEBUG (object));
+
+ if (SP_CANVAS_ITEM_CLASS(sp_canvas_debug_parent_class)->destroy) {
+ SP_CANVAS_ITEM_CLASS(sp_canvas_debug_parent_class)->destroy(object);
+ }
+}
+
+static void sp_canvas_debug_update( SPCanvasItem *item, Geom::Affine const &/*affine*/, unsigned int /*flags*/ )
+{
+ // We cover the entire canvas
+ item->x1 = -G_MAXINT;
+ item->y1 = -G_MAXINT;
+ item->x2 = G_MAXINT;
+ item->y2 = G_MAXINT;
+}
+
+static void sp_canvas_debug_render( SPCanvasItem *item, SPCanvasBuf *buf)
+{
+ if (!buf->ct) {
+ return;
+ }
+
+ cairo_set_line_width (buf->ct, 2);
+
+ // Draw box around buffer (for debugging)
+ cairo_new_path (buf->ct);
+ cairo_move_to (buf->ct, 0, 0);
+ cairo_line_to (buf->ct, buf->rect.width(), 0);
+ cairo_line_to (buf->ct, buf->rect.width(), buf->rect.height());
+ cairo_line_to (buf->ct, 0, buf->rect.height());
+ cairo_close_path (buf->ct);
+ ink_cairo_set_source_rgba32 (buf->ct, 0xff7f7f7f);
+ cairo_stroke (buf->ct);
+}
+
+static int sp_canvas_debug_event (SPCanvasItem *item, GdkEvent *event)
+{
+ ui_dump_event (event, Glib::ustring("sp_canvas_debug_event"));
+ return false; // We don't use any events...
+}
+
+} // namespace
+
+/*
+ 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/display/canvas-debug.h b/src/display/canvas-debug.h
new file mode 100644
index 000000000..d5a166da9
--- /dev/null
+++ b/src/display/canvas-debug.h
@@ -0,0 +1,41 @@
+#ifndef SEEN_SP_CANVAS_DEBUG_H
+#define SEEN_SP_CANVAS_DEBUG_H
+
+/*
+ * A simple surface for debugging the canvas. Shows how tiles are drawn.
+ *
+ * Author:
+ * Tavmjong Bah <tavmjong@free.fr>
+ *
+ * Copyright (C) 2017 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "sp-canvas-item.h"
+
+class SPItem;
+
+#define SP_TYPE_CANVAS_DEBUG (sp_canvas_debug_get_type ())
+#define SP_CANVAS_DEBUG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CANVAS_DEBUG, SPCanvasDebug))
+#define SP_IS_CANVAS_DEBUG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_CANVAS_DEBUG))
+
+struct SPCanvasDebug : public SPCanvasItem {
+};
+
+GType sp_canvas_debug_get_type (void);
+
+struct SPCanvasDebugClass : public SPCanvasItemClass{};
+
+#endif // SEEN_SP_CANVAS_DEBUG_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 :
diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp
index decf93626..4243d3365 100644
--- a/src/display/canvas-grid.cpp
+++ b/src/display/canvas-grid.cpp
@@ -5,6 +5,7 @@
* Copyright (C) Lauris Kaplinski 2000
* Abhishek Sharma
* Jon A. Cruz <jon@joncruz.org>
+ * Copyright (C) Tavmong Bah 2017 <tavmjong@free.fr>
*/
/* As a general comment, I am not exactly proud of how things are done.
@@ -19,12 +20,7 @@
#include <gtkmm/box.h>
#include <gtkmm/label.h>
-
-#if WITH_GTKMM_3_0
-# include <gtkmm/grid.h>
-#else
-# include <gtkmm/table.h>
-#endif
+#include <gtkmm/grid.h>
#include <glibmm/i18n.h>
@@ -144,7 +140,7 @@ grid_canvasitem_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned
};
CanvasGrid::CanvasGrid(SPNamedView * nv, Inkscape::XML::Node * in_repr, SPDocument *in_doc, GridType type)
- : visible(true), gridtype(type)
+ : visible(true), gridtype(type), legacy(false), pixel(false)
{
repr = in_repr;
doc = in_doc;
@@ -400,15 +396,10 @@ void CanvasGrid::setOrigin(Geom::Point const &origin_px)
**/
#define SPACE_SIZE_X 15
#define SPACE_SIZE_Y 10
-#if WITH_GTKMM_3_0
static inline void attach_all(Gtk::Grid &table, Gtk::Widget const *const arr[], unsigned size, int start = 0)
-#else
-static inline void attach_all(Gtk::Table &table, Gtk::Widget const *const arr[], unsigned size, int start = 0)
-#endif
{
for (unsigned i=0, r=start; i<size/sizeof(Gtk::Widget*); i+=2) {
if (arr[i] && arr[i+1]) {
-#if WITH_GTKMM_3_0
(const_cast<Gtk::Widget&>(*arr[i])).set_hexpand();
(const_cast<Gtk::Widget&>(*arr[i])).set_valign(Gtk::ALIGN_CENTER);
table.attach(const_cast<Gtk::Widget&>(*arr[i]), 1, r, 1, 1);
@@ -416,44 +407,28 @@ static inline void attach_all(Gtk::Table &table, Gtk::Widget const *const arr[],
(const_cast<Gtk::Widget&>(*arr[i+1])).set_hexpand();
(const_cast<Gtk::Widget&>(*arr[i+1])).set_valign(Gtk::ALIGN_CENTER);
table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 2, r, 1, 1);
-#else
- table.attach (const_cast<Gtk::Widget&>(*arr[i]), 1, 2, r, r+1,
- Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
- table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 2, 3, r, r+1,
- Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
-#endif
} else {
if (arr[i+1]) {
-#if WITH_GTKMM_3_0
(const_cast<Gtk::Widget&>(*arr[i+1])).set_hexpand();
(const_cast<Gtk::Widget&>(*arr[i+1])).set_valign(Gtk::ALIGN_CENTER);
table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 1, r, 2, 1);
-#else
- table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 1, 3, r, r+1,
- Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
-#endif
} else if (arr[i]) {
Gtk::Label& label = reinterpret_cast<Gtk::Label&> (const_cast<Gtk::Widget&>(*arr[i]));
+#if GTK_CHECK_VERSION(3,16,0)
+ label.set_xalign(0.0);
+ label.set_yalign(0.5);
+#else
label.set_alignment (0.0);
-#if WITH_GTKMM_3_0
+#endif
label.set_hexpand();
label.set_valign(Gtk::ALIGN_CENTER);
table.attach(label, 0, r, 3, 1);
-#else
- table.attach (label, 0, 3, r, r+1,
- Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
-#endif
} else {
Gtk::HBox *space = Gtk::manage (new Gtk::HBox);
space->set_size_request (SPACE_SIZE_X, SPACE_SIZE_Y);
-#if WITH_GTKMM_3_0
space->set_halign(Gtk::ALIGN_CENTER);
space->set_valign(Gtk::ALIGN_CENTER);
table.attach(*space, 0, r, 1, 1);
-#else
- table.attach (*space, 0, 1, r, r+1,
- (Gtk::AttachOptions)0, (Gtk::AttachOptions)0,0,0);
-#endif
}
}
++r;
@@ -559,6 +534,10 @@ CanvasXYGrid::readRepr()
if( q.unit->type == UNIT_TYPE_LINEAR ) {
// Legacy grid not in 'user units'
origin[Geom::X] = q.value("px");
+ legacy = true;
+ if (q.unit->abbr == "px" ) {
+ pixel = true;
+ }
} else {
// Grid in 'user units'
origin[Geom::X] = q.quantity * scale_x;
@@ -572,6 +551,10 @@ CanvasXYGrid::readRepr()
if( q.unit->type == UNIT_TYPE_LINEAR ) {
// Legacy grid not in 'user units'
origin[Geom::Y] = q.value("px");
+ legacy = true;
+ if (q.unit->abbr == "px" ) {
+ pixel = true;
+ }
} else {
// Grid in 'user units'
origin[Geom::Y] = q.quantity * scale_y;
@@ -590,6 +573,10 @@ CanvasXYGrid::readRepr()
if( q.unit->type == UNIT_TYPE_LINEAR ) {
// Legacy grid not in 'user units'
spacing[Geom::X] = q.value("px");
+ legacy = true;
+ if (q.unit->abbr == "px" ) {
+ pixel = true;
+ }
} else {
// Grid in 'user units'
spacing[Geom::X] = q.quantity * scale_x;
@@ -609,6 +596,10 @@ CanvasXYGrid::readRepr()
if( q.unit->type == UNIT_TYPE_LINEAR ) {
// Legacy grid not in 'user units'
spacing[Geom::Y] = q.value("px");
+ legacy = true;
+ if (q.unit->abbr == "px" ) {
+ pixel = true;
+ }
} else {
// Grid in 'user units'
spacing[Geom::Y] = q.quantity * scale_y;
@@ -684,14 +675,9 @@ CanvasXYGrid::onReprAttrChanged(Inkscape::XML::Node */*repr*/, gchar const */*ke
Gtk::Widget *
CanvasXYGrid::newSpecificWidget()
{
-#if WITH_GTKMM_3_0
- Gtk::Grid * table = Gtk::manage( new Gtk::Grid() );
+ auto table = Gtk::manage( new Gtk::Grid() );
table->set_row_spacing(2);
table->set_column_spacing(2);
-#else
- Gtk::Table * table = Gtk::manage( new Gtk::Table(1,1) );
- table->set_spacings(2);
-#endif
Inkscape::UI::Widget::RegisteredUnitMenu *_rumg = Gtk::manage( new Inkscape::UI::Widget::RegisteredUnitMenu(
_("Grid _units:"), "units", _wr, repr, doc) );
@@ -834,25 +820,41 @@ CanvasXYGrid::updateWidgets()
*/
}
+// For correcting old SVG Inkscape files
+void
+CanvasXYGrid::Scale (Geom::Scale const &scale ) {
+ origin *= scale;
+ spacing *= scale;
+ // Write out in 'user-units'
+ Inkscape::SVGOStringStream os_x, os_y, ss_x, ss_y;
+ os_x << origin[Geom::X];
+ os_y << origin[Geom::Y];
+ ss_x << spacing[Geom::X];
+ ss_y << spacing[Geom::Y];
+ repr->setAttribute("originx", os_x.str().c_str());
+ repr->setAttribute("originy", os_y.str().c_str());
+ repr->setAttribute("spacingx", ss_x.str().c_str());
+ repr->setAttribute("spacingy", ss_y.str().c_str());
+}
void
CanvasXYGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/)
{
ow = origin * affine;
- sw = spacing * affine;
- sw -= Geom::Point(affine[4], affine[5]);
+ sw[0] = Geom::Point(spacing[0], 0) * affine.withoutTranslation();
+ sw[1] = Geom::Point(0, spacing[1]) * affine.withoutTranslation();
+ // Find suitable grid spacing for display
for(int dim = 0; dim < 2; dim++) {
gint scaling_factor = empspacing;
if (scaling_factor <= 1)
scaling_factor = 5;
- scaled[dim] = FALSE;
- sw[dim] = fabs (sw[dim]);
- while (sw[dim] < 8.0) {
- scaled[dim] = TRUE;
+ scaled[dim] = false;
+ while (fabs(sw[dim].length()) < 8.0) {
+ scaled[dim] = true;
sw[dim] *= scaling_factor;
/* First pass, go up to the major line spacing, then
keep increasing by two. */
@@ -862,49 +864,45 @@ CanvasXYGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/)
}
-static void
-grid_hline (SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba)
-{
- if ((y < buf->rect.top()) || (y >= buf->rect.bottom()))
- return;
-
- cairo_move_to(buf->ct, 0.5 + xs, 0.5 + y);
- cairo_line_to(buf->ct, 0.5 + xe, 0.5 + y);
- ink_cairo_set_source_rgba32(buf->ct, rgba);
- cairo_stroke(buf->ct);
-}
-
-static void
-grid_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba)
+// Find intersections of line with rectangle. There should be zero or two.
+// If line is degenerate with rectangle side, two corner points are returned.
+static std::vector<Geom::Point>
+intersect_line_rectangle( Geom::Line const &line, Geom::Rect const &rect )
{
- if ((x < buf->rect.left()) || (x >= buf->rect.right()))
- return;
-
- cairo_move_to(buf->ct, 0.5 + x, 0.5 + ys);
- cairo_line_to(buf->ct, 0.5 + x, 0.5 + ye);
- ink_cairo_set_source_rgba32(buf->ct, rgba);
- cairo_stroke(buf->ct);
+ std::vector<Geom::Point> intersections;
+ for (unsigned i = 0; i < 4; ++i) {
+ Geom::LineSegment side( rect.corner(i), rect.corner((i+1)%4) );
+ try {
+ Geom::OptCrossing oc = Geom::intersection(line, side);
+ if (oc) {
+ intersections.push_back( line.pointAt((*oc).ta));
+ }
+ } catch (Geom::InfiniteSolutions) {
+ intersections.clear();
+ intersections.push_back( side.pointAt(0) );
+ intersections.push_back( side.pointAt(1) );
+ return intersections;
+ }
+ }
+ return intersections;
}
-static void
-grid_dot (SPCanvasBuf *buf, gint x, gint y, guint32 rgba)
-{
- if ( (y < buf->rect.top()) || (y >= buf->rect.bottom())
- || (x < buf->rect.left()) || (x >= buf->rect.right()) )
- return;
-
- cairo_rectangle(buf->ct, x, y, 1, 1);
- ink_cairo_set_source_rgba32(buf->ct, rgba);
- cairo_fill(buf->ct);
+// Find the signed distance of a point to a line. The distance is negative if
+// the point lies to the left of the line considering the line's versor.
+static double
+signed_distance( Geom::Point const &point, Geom::Line const &line ) {
+ Geom::Coord t = line.nearestTime( point );
+ Geom::Point p = line.pointAt(t);
+ double distance = Geom::distance( p, point );
+ if ( Geom::cross( Geom::Line( p, point ).versor(), line.versor() ) < 0.0 ) {
+ distance = -distance;
+ }
+ return distance;
}
void
CanvasXYGrid::Render (SPCanvasBuf *buf)
{
- gdouble const sxg = floor ((buf->rect.left() - ow[Geom::X]) / sw[Geom::X]) * sw[Geom::X] + ow[Geom::X];
- gint const xlinestart = round((sxg - ow[Geom::X]) / sw[Geom::X]);
- gdouble const syg = floor ((buf->rect.top() - ow[Geom::Y]) / sw[Geom::Y]) * sw[Geom::Y] + ow[Geom::Y];
- gint const ylinestart = round((syg - ow[Geom::Y]) / sw[Geom::Y]);
// no_emphasize_when_zoomedout determines color (minor or major) when only major grid lines/dots shown.
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -921,75 +919,128 @@ CanvasXYGrid::Render (SPCanvasBuf *buf)
cairo_set_line_width(buf->ct, 1.0);
cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE);
- if (!render_dotted) {
- // Line grid
- gint ylinenum;
- gdouble y;
- for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) {
- gint const y0 = round(y);
- if (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) {
- grid_hline (buf, y0, buf->rect.left(), buf->rect.right() - 1, color);
- } else {
- grid_hline (buf, y0, buf->rect.left(), buf->rect.right() - 1, _empcolor);
- }
- }
+ for (unsigned dim = 0; dim < 2; ++dim) {
- gint xlinenum;
- gdouble x;
- for (x = sxg, xlinenum = xlinestart; x < buf->rect.right(); x += sw[Geom::X], xlinenum++) {
- gint const ix = round(x);
- if (!scaled[Geom::X] && (xlinenum % empspacing) != 0) {
- grid_vline (buf, ix, buf->rect.top(), buf->rect.bottom(), color);
- } else {
- grid_vline (buf, ix, buf->rect.top(), buf->rect.bottom(), _empcolor);
+ // std::cout << "\n " << (dim==0?"Horizontal":"Vertical") << " ------------" << std::endl;
+
+ // Construct an axis line through origin with direction normal to grid spacing.
+ Geom::Line axis = Geom::Line::from_origin_and_vector( ow, sw[dim] );
+ Geom::Line orth = Geom::Line::from_origin_and_vector( ow, sw[(dim+1)%2] );
+
+ double spacing = sw[(dim+1)%2].length(); // Spacing between grid lines.
+ double dash = sw[dim].length(); // Total length of dash pattern.
+
+ // std::cout << " axis: " << axis.origin() << ", " << axis.vector() << std::endl;
+ // std::cout << " spacing: " << spacing << std::endl;
+ // std::cout << " dash period: " << dash << std::endl;
+
+ // Find the minimum and maximum distances of the buffer corners from axis.
+ double min = 1000000;
+ double max = -1000000;
+ for (unsigned c = 0; c < 4; ++c) {
+
+ // We need signed distance... lib2geom offers only positive distance.
+ double distance = signed_distance( buf->rect.corner(c), axis );
+
+ // Correct it for coordinate flips (inverts handedness).
+ if (Geom::cross( axis.vector(), orth.vector() ) > 0 ) {
+ distance = -distance;
}
+
+ if (distance < min)
+ min = distance;
+ if (distance > max)
+ max = distance;
}
- } else {
- // Dotted grid
- gint ylinenum;
- gdouble y;
-
- // alpha needs to be larger than in the line case to maintain a similar visual impact but
- // setting it to the maximal value makes the dots dominant in some cases. Solution,
- // increase the alpha by a factor of 4. This then allows some user adjustment.
- guint32 _empdot = (_empcolor & 0xff) << 2;
- if (_empdot > 0xff)
- _empdot = 0xff;
- _empdot += (_empcolor & 0xffffff00);
-
- guint32 _colordot = (color & 0xff) << 2;
- if (_colordot > 0xff)
- _colordot = 0xff;
- _colordot += (color & 0xffffff00);
-
- for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) {
- gint const iy = round(y);
-
- gint xlinenum;
- gdouble x;
- for (x = sxg, xlinenum = xlinestart; x < buf->rect.right(); x += sw[Geom::X], xlinenum++) {
- gint const ix = round(x);
- if ( (!scaled[Geom::X] && (xlinenum % empspacing) != 0)
- || (!scaled[Geom::Y] && (ylinenum % empspacing) != 0)
- || ((scaled[Geom::X] || scaled[Geom::Y]) && no_emp_when_zoomed_out) )
- {
- // Minor point: dot only
- grid_dot (buf, ix, iy, _colordot); // | (guint32)0x000000FF); // put alpha to max value
+ int start = floor( min/spacing );
+ int stop = floor( max/spacing );
+
+ // std::cout << " rect: " << buf->rect << std::endl;
+ // std::cout << " min: " << min << " max: " << max << std::endl;
+ // std::cout << " start: " << start << " stop: " << stop << std::endl;
+
+ // Loop over grid lines that intersected buf rectangle.
+ for (int j = start+1; j <= stop; ++j) {
+
+ Geom::Line grid_line = Geom::make_parallel_line( ow + j * sw[(dim+1)%2], axis );
+
+ std::vector<Geom::Point> x = intersect_line_rectangle( grid_line, buf->rect );
+
+ // If we have two intersections, grid line intersects buffer rectangle.
+ if (x.size() == 2 ) {
+
+ // Make sure lines are always drawn in the same direction (or dashes misplaced).
+ Geom::Line vector( x[0], x[1]);
+ if (Geom::dot( vector.vector(), axis.vector() ) < 0.0) {
+ std::swap(x[0], x[1]);
+ }
+
+ // Set up line.
+ cairo_move_to(buf->ct, x[0][Geom::X] + 0.5, x[0][Geom::Y] + 0.5);
+ cairo_line_to(buf->ct, x[1][Geom::X] + 0.5, x[1][Geom::Y] + 0.5);
+
+ // Set dash pattern and color.
+ if (render_dotted) {
+
+ // alpha needs to be larger than in the line case to maintain a similar
+ // visual impact but setting it to the maximal value makes the dots
+ // dominant in some cases. Solution, increase the alpha by a factor of
+ // 4. This then allows some user adjustment.
+ guint32 _empdot = (_empcolor & 0xff) << 2;
+ if (_empdot > 0xff)
+ _empdot = 0xff;
+ _empdot += (_empcolor & 0xffffff00);
+
+ guint32 _colordot = (color & 0xff) << 2;
+ if (_colordot > 0xff)
+ _colordot = 0xff;
+ _colordot += (color & 0xffffff00);
+
+ // Dash pattern must use spacing from orthogonal direction.
+ // Offset is to center dash on orthogonal lines.
+ double offset = fmod( signed_distance( x[0], orth ), sw[dim].length());
+ if (Geom::cross( axis.vector(), orth.vector() ) > 0 ) {
+ offset = -offset;
+ }
+
+ double dashes[2];
+ if (!scaled[dim] && (j % empspacing) != 0) {
+ // Minor lines
+ dashes[0] = 1;
+ dashes[1] = dash -1;
+ offset -= 0.5;
+ ink_cairo_set_source_rgba32(buf->ct, _colordot);
+ } else {
+ // Major lines
+ dashes[0] = 3;
+ dashes[1] = dash - 3;
+ offset -= 1.5; // Center dash on intersection.
+ ink_cairo_set_source_rgba32(buf->ct, _empdot);
+ }
+
+ cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_BUTT);
+ cairo_set_dash(buf->ct, dashes, 2, -offset);
+
} else {
- // Major point: small cross
- gint const pitch = 1;
- grid_dot (buf, ix-pitch, iy, _empcolor);
- grid_dot (buf, ix+pitch, iy, _empcolor);
- grid_dot (buf, ix, iy, _empdot ); // | (guint32)0x000000FF); // put alpha to max value
+ // Solid lines
- grid_dot (buf, ix, iy-pitch, _empcolor);
- grid_dot (buf, ix, iy+pitch, _empcolor);
+ // Set color
+ if (!scaled[dim] && (j % empspacing) != 0) {
+ ink_cairo_set_source_rgba32(buf->ct, color );
+ } else {
+ ink_cairo_set_source_rgba32(buf->ct, _empcolor );
+ }
}
- }
+ cairo_stroke(buf->ct);
+
+ } else {
+ std::cerr << "CanvasXYGrid::render: Grid line doesn't intersect!" << std::endl;
+ }
}
}
+
cairo_restore(buf->ct);
}
@@ -1028,7 +1079,7 @@ CanvasXYGridSnapper::_getSnapLines(Geom::Point const &p) const
if (getSnapVisibleOnly()) {
// Only snapping to visible grid lines
- spacing = grid->sw[i]; // this is the spacing of the visible grid lines measured in screen pixels
+ spacing = grid->sw[i].length(); // this is the spacing of the visible grid lines measured in screen pixels
// convert screen pixels to px
// FIXME: after we switch to snapping dist in screen pixels, this will be unnecessary
SPDesktop const *dt = _snapmanager->getDesktop();
diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h
index 557bd6dab..91fa43e69 100644
--- a/src/display/canvas-grid.h
+++ b/src/display/canvas-grid.h
@@ -101,6 +101,9 @@ public:
static void on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data);
+ bool isLegacy() const { return legacy; }
+ bool isPixel() const { return pixel; }
+
bool isVisible() const { return (isEnabled() &&visible); };
bool isEnabled() const;
@@ -118,7 +121,11 @@ protected:
GridType gridtype;
-private:
+ // For dealing with old Inkscape SVG files (pre 0.92)
+ bool legacy;
+ bool pixel;
+
+ private:
CanvasGrid(const CanvasGrid&);
CanvasGrid& operator=(const CanvasGrid&);
};
@@ -129,6 +136,7 @@ public:
CanvasXYGrid(SPNamedView * nv, Inkscape::XML::Node * in_repr, SPDocument * in_doc);
virtual ~CanvasXYGrid();
+ virtual void Scale (Geom::Scale const &scale);
virtual void Update (Geom::Affine const &affine, unsigned int flags);
virtual void Render (SPCanvasBuf *buf);
@@ -140,7 +148,7 @@ public:
be different in the X or Y direction, hence two
variables */
Geom::Point ow; /**< Transformed origin by the affine for the zoom */
- Geom::Point sw; /**< Transformed spacing by the affine for the zoom */
+ Geom::Point sw[2]; /**< Transformed spacing by the affine for the zoom */
protected:
virtual Gtk::Widget * newSpecificWidget();
diff --git a/src/display/canvas-rotate.cpp b/src/display/canvas-rotate.cpp
new file mode 100644
index 000000000..aaf6b962c
--- /dev/null
+++ b/src/display/canvas-rotate.cpp
@@ -0,0 +1,288 @@
+/*
+ * Temporary surface for previewing rotated canvas.
+ *
+ * Author:
+ * Tavmjong Bah <tavmjong@free.fr>
+ *
+ * Copyright (C) 2017 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "inkscape.h"
+#include "desktop.h"
+
+#include "canvas-rotate.h"
+#include "sp-canvas.h"
+#include "cairo-utils.h"
+#include "ui/event-debug.h"
+
+#include "2geom/point.h"
+#include "2geom/rect.h"
+
+#include <gtk/gtk.h>
+
+namespace {
+
+static void sp_canvas_rotate_destroy(SPCanvasItem *item);
+static void sp_canvas_rotate_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
+static void sp_canvas_rotate_render (SPCanvasItem *item, SPCanvasBuf *buf);
+static int sp_canvas_rotate_event (SPCanvasItem *item, GdkEvent *event);
+
+} // namespace
+
+void sp_canvas_rotate_paint (SPCanvasRotate *canvas_rotate, cairo_surface_t *background);
+
+G_DEFINE_TYPE(SPCanvasRotate, sp_canvas_rotate, SP_TYPE_CANVAS_ITEM);
+
+static void sp_canvas_rotate_class_init (SPCanvasRotateClass *klass)
+{
+ klass->destroy = sp_canvas_rotate_destroy;
+ //klass->update = sp_canvas_rotate_update;
+ //klass->render = sp_canvas_rotate_render;
+ klass->event = sp_canvas_rotate_event;
+}
+
+static void sp_canvas_rotate_init (SPCanvasRotate *rotate)
+{
+ rotate->pickable = true; // So we can receive events.
+ rotate->angle = 0.0;
+ rotate->start_angle = -1000;
+ rotate->surface_copy = NULL;
+ rotate->surface_rotated = NULL;
+}
+
+namespace {
+static void sp_canvas_rotate_destroy (SPCanvasItem *object)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (SP_IS_CANVAS_ROTATE (object));
+
+ if (SP_CANVAS_ITEM_CLASS(sp_canvas_rotate_parent_class)->destroy) {
+ SP_CANVAS_ITEM_CLASS(sp_canvas_rotate_parent_class)->destroy(object);
+ }
+}
+
+// NOT USED... TOO SLOW
+static void sp_canvas_rotate_update( SPCanvasItem *item, Geom::Affine const &/*affine*/, unsigned int /*flags*/ )
+{
+ SPCanvasRotate *cr = SP_CANVAS_ROTATE(item);
+
+ if (cr->surface_copy == NULL) {
+ // std::cout << "sp_canvas_rotate_update: surface_copy is NULL" << std::endl;
+ return;
+ }
+
+ // Destroy surface_rotated if it already exists.
+ if (cr->surface_rotated != NULL) {
+ cairo_surface_destroy (cr->surface_rotated);
+ cr->surface_rotated = NULL;
+ }
+
+ // Create rotated surface
+ cr->surface_rotated = ink_cairo_surface_create_identical(cr->surface_copy);
+ double width = cairo_image_surface_get_width (cr->surface_rotated);
+ double height = cairo_image_surface_get_height (cr->surface_rotated);
+ cairo_t *context = cairo_create( cr->surface_rotated );
+ cairo_set_operator( context, CAIRO_OPERATOR_SOURCE );
+ cairo_translate( context, width/2.0, height/2.0 );
+ cairo_rotate( context, Geom::rad_from_deg(-cr->angle) );
+ cairo_translate( context, -width/2.0, -height/2.0 );
+ cairo_set_source_surface( context, cr->surface_copy, 0, 0 );
+ cairo_paint( context );
+ cairo_destroy( context);
+
+ // We cover the entire canvas
+ item->x1 = -G_MAXINT;
+ item->y1 = -G_MAXINT;
+ item->x2 = G_MAXINT;
+ item->y2 = G_MAXINT;
+
+ item->canvas->requestRedraw(item->x1, item->y1, item->x2, item->y2);
+}
+
+// NOT USED... TOO SLOW
+static void sp_canvas_rotate_render( SPCanvasItem *item, SPCanvasBuf *buf)
+{
+ // std::cout << "sp_canvas_rotate_render:" << std::endl;
+ // std::cout << " buf->rect: " << buf->rect << std::endl;
+ // std::cout << " buf->canvas_rect: " << buf->canvas_rect << std::endl;
+ SPCanvasRotate *cr = SP_CANVAS_ROTATE(item);
+
+ if (!buf->ct) {
+ return;
+ }
+
+ if (cr->surface_rotated == NULL ) {
+ // std::cout << " surface_rotated is NULL" << std::endl;
+ return;
+ }
+
+ // Draw rotated canvas
+ cairo_save (buf->ct);
+ cairo_translate (buf->ct,
+ buf->canvas_rect.left() - buf->rect.left(),
+ buf->canvas_rect.top() - buf->rect.top() );
+ cairo_set_operator (buf->ct, CAIRO_OPERATOR_SOURCE );
+ cairo_set_source_surface (buf->ct, cr->surface_rotated, 0, 0 );
+ cairo_paint (buf->ct);
+ cairo_restore (buf->ct);
+
+
+ // Draw line from center to cursor
+ cairo_save (buf->ct);
+ cairo_translate (buf->ct, -buf->rect.left(), -buf->rect.top());
+ cairo_new_path (buf->ct);
+ cairo_move_to (buf->ct, cr->center[Geom::X], cr->center[Geom::Y]);
+ cairo_rel_line_to (buf->ct, cr->cursor[Geom::X], cr->cursor[Geom::Y]);
+ cairo_set_line_width (buf->ct, 2);
+ ink_cairo_set_source_rgba32 (buf->ct, 0xff00007f);
+ cairo_stroke (buf->ct);
+ cairo_restore (buf->ct);
+
+}
+
+static int sp_canvas_rotate_event (SPCanvasItem *item, GdkEvent *event)
+{
+ SPCanvasRotate *cr = SP_CANVAS_ROTATE(item);
+
+// ui_dump_event (event, Glib::ustring("sp_canvas_rotate_event"));
+
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Geom::Rect viewbox = desktop->canvas->getViewbox(); // Not SVG viewbox!
+ cr->center = viewbox.midpoint();
+
+ switch (event->type) {
+ case GDK_MOTION_NOTIFY:
+ {
+ Geom::Point cursor( event->motion.x, event->motion.y );
+
+ // Both cursor and center are in window coordinates
+ Geom::Point rcursor( cursor - cr->center );
+ double angle = Geom::deg_from_rad( Geom::atan2(rcursor) );
+
+ // Set start angle
+ if (cr->start_angle < -360) {
+ cr->start_angle = angle;
+ }
+
+ double rotation_snap = 15;
+
+ double delta_angle = cr->start_angle - angle;
+
+ if (event->motion.state & GDK_SHIFT_MASK &&
+ event->motion.state & GDK_CONTROL_MASK) {
+ delta_angle = 0;
+ } else if (event->motion.state & GDK_SHIFT_MASK) {
+ delta_angle = round(delta_angle/rotation_snap) * rotation_snap;
+ } else if (event->motion.state & GDK_CONTROL_MASK) {
+ // ?
+ } else if (event->motion.state & GDK_MOD1_MASK) {
+ // Decimal raw angle
+ } else {
+ delta_angle = floor(delta_angle);
+ }
+
+ cr->angle = delta_angle;
+
+ // Correct line for snapping of angle
+ double distance = rcursor.length();
+ cr->cursor = Geom::Point::polar( Geom::rad_from_deg(angle), distance );
+
+ // Update screen
+ // sp_canvas_item_request_update( item );
+ sp_canvas_rotate_paint (cr, cr->canvas->_backing_store);
+ break;
+ }
+ case GDK_BUTTON_RELEASE:
+
+ // Rotate the actual canvas
+ desktop->rotate_relative_center_point (desktop->w2d(cr->center),
+ Geom::rad_from_deg(cr->angle) );
+
+ // We're done
+ sp_canvas_item_ungrab (item, event->button.time);
+ sp_canvas_item_hide (item);
+
+ cr->start_angle = -1000;
+ if (cr->surface_copy != NULL) {
+ cairo_surface_destroy( cr->surface_copy );
+ cr->surface_copy = NULL;
+ }
+ if (cr->surface_rotated != NULL) {
+ cairo_surface_destroy( cr->surface_rotated );
+ cr->surface_rotated = NULL;
+ }
+ // sp_canvas_item_show (desktop->drawing);
+
+ break;
+ case GDK_KEY_PRESS:
+ // std::cout << " Key press: " << std::endl;
+ break;
+ case GDK_KEY_RELEASE:
+ // std::cout << " Key release: " << std::endl;
+ break;
+ default:
+ // ui_dump_event (event, "sp_canvas_rotate_event: unwanted event: ");
+ break;
+ }
+
+ if (event->type == GDK_KEY_PRESS) return false;
+
+ return true;
+}
+
+} // namespace
+
+void sp_canvas_rotate_start (SPCanvasRotate *canvas_rotate, cairo_surface_t *background)
+{
+ if (background == NULL) {
+ std::cerr << "sp_canvas_rotate_start: background is NULL!" << std::endl;
+ return;
+ }
+
+ canvas_rotate->angle = 0.0;
+
+ // Copy current background
+ canvas_rotate->surface_copy = ink_cairo_surface_copy( background );
+
+ // Paint canvas with background... since we are hiding drawing.
+ sp_canvas_item_request_update( canvas_rotate );
+}
+
+// Paint the canvas ourselves for speed....
+void sp_canvas_rotate_paint (SPCanvasRotate *canvas_rotate, cairo_surface_t *background)
+{
+ if (background == NULL) {
+ std::cerr << "sp_canvas_rotate_paint: background is NULL!" << std::endl;
+ return;
+ }
+
+ double width = cairo_image_surface_get_width (background);
+ double height = cairo_image_surface_get_height (background);
+
+ // Draw rotated canvas
+ cairo_t *context = cairo_create( background );
+
+ cairo_save (context);
+ cairo_set_operator( context, CAIRO_OPERATOR_SOURCE );
+ cairo_translate( context, width/2.0, height/2.0 );
+ cairo_rotate( context, Geom::rad_from_deg(-canvas_rotate->angle) );
+ cairo_translate( context, -width/2.0, -height/2.0 );
+ cairo_set_source_surface( context, canvas_rotate->surface_copy, 0, 0 );
+ cairo_paint( context );
+ cairo_restore( context );
+ cairo_destroy( context );
+
+ gtk_widget_queue_draw (GTK_WIDGET (canvas_rotate->canvas));
+}
+/*
+ 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/display/canvas-rotate.h b/src/display/canvas-rotate.h
new file mode 100644
index 000000000..8620dcced
--- /dev/null
+++ b/src/display/canvas-rotate.h
@@ -0,0 +1,50 @@
+#ifndef SEEN_SP_CANVAS_ROTATE_H
+#define SEEN_SP_CANVAS_ROTATE_H
+
+/*
+ * Temporary surface for previewing rotated canvas.
+ *
+ * Author:
+ * Tavmjong Bah <tavmjong@free.fr>
+ *
+ * Copyright (C) 2017 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "sp-canvas-item.h"
+#include "2geom/line.h"
+
+class SPItem;
+
+#define SP_TYPE_CANVAS_ROTATE (sp_canvas_rotate_get_type ())
+#define SP_CANVAS_ROTATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CANVAS_ROTATE, SPCanvasRotate))
+#define SP_IS_CANVAS_ROTATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_CANVAS_ROTATE))
+
+struct SPCanvasRotate : public SPCanvasItem {
+ Geom::Point center; // Center of screen
+ Geom::Point cursor; // Position of cursor relative to center (after angle snapping)
+ double angle; // Rotation angle in degrees
+ double start_angle; // Starting angle of cursor
+ cairo_surface_t *surface_copy; // Copy of original surface
+ cairo_surface_t *surface_rotated; // Copy of original surface, rotated
+};
+
+void sp_canvas_rotate_start( SPCanvasRotate *canvas_rotate, cairo_surface_t *background );
+
+GType sp_canvas_rotate_get_type (void);
+
+struct SPCanvasRotateClass : public SPCanvasItemClass{};
+
+#endif // SEEN_SP_CANVAS_ROTATE_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 :
diff --git a/src/display/canvas-text.cpp b/src/display/canvas-text.cpp
index 7c019caf5..efef018e6 100644
--- a/src/display/canvas-text.cpp
+++ b/src/display/canvas-text.cpp
@@ -84,6 +84,7 @@ sp_canvastext_render (SPCanvasItem *item, SPCanvasBuf *buf)
if (!buf->ct)
return;
+ cairo_select_font_face(buf->ct, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(buf->ct, cl->fontsize);
if (cl->background){
@@ -138,6 +139,7 @@ sp_canvastext_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned i
cairo_surface_t *tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
cairo_t* tmp_buf = cairo_create(tmp_surface);
+ cairo_select_font_face(tmp_buf, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(tmp_buf, cl->fontsize);
cairo_text_extents_t extents;
cairo_text_extents(tmp_buf, cl->text, &extents);
diff --git a/src/display/curve.cpp b/src/display/curve.cpp
index b6c387034..6e662b17b 100644
--- a/src/display/curve.cpp
+++ b/src/display/curve.cpp
@@ -302,6 +302,18 @@ SPCurve::is_empty() const
}
/**
+ * True if paths are in curve. If it only contains a path with only a moveto, the path is considered as unset FALSE
+ */
+bool
+SPCurve::is_unset() const
+{
+ if (get_segment_count()) {
+ return false;
+ }
+ return true;
+}
+
+/**
* True iff all subpaths are closed.
* Returns false if the curve is empty.
*/
@@ -323,6 +335,20 @@ SPCurve::is_closed() const
}
/**
+ * True if both curves are equal
+ */
+bool
+SPCurve::is_equal(SPCurve * other) const
+{
+ if(other == NULL) {
+ return false;
+ } else if(_pathv == other->get_pathvector()){
+ return true;
+ }
+ return false;
+}
+
+/**
* Return last pathsegment (possibly the closing path segment) of the last path in PathVector or NULL.
* If the last path is empty (contains only a moveto), the function returns NULL
*/
diff --git a/src/display/curve.h b/src/display/curve.h
index 42b899210..8375e1105 100644
--- a/src/display/curve.h
+++ b/src/display/curve.h
@@ -43,7 +43,9 @@ public:
size_t nodes_in_path() const;
bool is_empty() const;
+ bool is_unset() const;
bool is_closed() const;
+ bool is_equal(SPCurve * other) const;
Geom::Curve const * last_segment() const;
Geom::Path const * last_path() const;
Geom::Curve const * first_segment() const;
diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp
index 1a9cbfdcc..018f23e74 100644
--- a/src/display/drawing-group.cpp
+++ b/src/display/drawing-group.cpp
@@ -95,6 +95,7 @@ DrawingGroup::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigne
if (stop_at == NULL) {
// normal rendering
for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ i->setAntialiasing(_antialias);
i->render(dc, area, flags, stop_at);
}
} else {
@@ -103,10 +104,12 @@ DrawingGroup::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigne
if (&*i == stop_at) return RENDER_OK; // do not render the stop_at item at all
if (i->isAncestorOf(stop_at)) {
// render its ancestors without masks, opacity or filters
+ i->setAntialiasing(_antialias);
i->render(dc, area, flags | RENDER_FILTER_BACKGROUND, stop_at);
// stop further rendering
return RENDER_OK;
} else {
+ i->setAntialiasing(_antialias);
i->render(dc, area, flags, stop_at);
}
}
diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp
index e23c89c59..508fcc503 100644
--- a/src/display/drawing-image.cpp
+++ b/src/display/drawing-image.cpp
@@ -116,16 +116,22 @@ unsigned DrawingImage::_renderItem(DrawingContext &dc, Geom::IntRect const &/*ar
if (_style) {
// See: http://www.w3.org/TR/SVG/painting.html#ImageRenderingProperty
// http://www.w3.org/TR/css4-images/#the-image-rendering
+ // It's back in CSS Images 3 now.
// style.h/style.cpp
switch (_style->image_rendering.computed) {
case SP_CSS_IMAGE_RENDERING_AUTO:
- // Do nothing
- break;
case SP_CSS_IMAGE_RENDERING_OPTIMIZEQUALITY:
+ case SP_CSS_IMAGE_RENDERING_CRISPEDGES:
+ // CSS 3 defines:
+ // 'auto' to use smoothing
+ // 'optimize-quality' as alias for auto
+ // We don't have special rendering for 'crisp-edges' yet
+ // so follow what browsers do.
// In recent Cairo, BEST used Lanczos3, which is prohibitively slow
dc.patternSetFilter( CAIRO_FILTER_GOOD );
break;
case SP_CSS_IMAGE_RENDERING_OPTIMIZESPEED:
+ case SP_CSS_IMAGE_RENDERING_PIXELATED:
default:
dc.patternSetFilter( CAIRO_FILTER_NEAREST );
break;
diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp
index 89ca66dc4..c4af81efc 100644
--- a/src/display/drawing-item.cpp
+++ b/src/display/drawing-item.cpp
@@ -132,7 +132,7 @@ DrawingItem::DrawingItem(Drawing &drawing)
, _propagate(0)
// , _renders_opacity(0)
, _pick_children(0)
- , _antialias(1)
+ , _antialias(2)
, _isolation(SP_CSS_ISOLATION_AUTO)
, _mix_blend_mode(SP_CSS_BLEND_NORMAL)
{}
@@ -291,7 +291,7 @@ DrawingItem::setOpacity(float opacity)
}
void
-DrawingItem::setAntialiasing(bool a)
+DrawingItem::setAntialiasing(unsigned a)
{
if (_antialias != a) {
_antialias = a;
@@ -699,10 +699,21 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
Geom::OptIntRect carea = Geom::intersect(area, _drawbox);
if (!carea) return RENDER_OK;
- if (_antialias) {
- cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_DEFAULT);
- } else {
- cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_NONE);
+ switch(_antialias){
+ case 0:
+ cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_NONE);
+ break;
+ case 1:
+ cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_FAST);
+ break;
+ case 2:
+ cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_GOOD);
+ break;
+ case 3:
+ cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_BEST);
+ break;
+ default: // should not happen
+ g_assert_not_reached();
}
// render from cache if possible
diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h
index 3c593ceaa..21f6ffacc 100644
--- a/src/display/drawing-item.h
+++ b/src/display/drawing-item.h
@@ -115,7 +115,7 @@ public:
virtual void setStyle(SPStyle *style, SPStyle *context_style = NULL);
virtual void setChildrenStyle(SPStyle *context_style);
void setOpacity(float opacity);
- void setAntialiasing(bool a);
+ void setAntialiasing(unsigned a);
void setIsolation(unsigned isolation); // CSS Compositing and Blending
void setBlendMode(unsigned blend_mode);
void setTransform(Geom::Affine const &trans);
@@ -222,7 +222,7 @@ protected:
//unsigned _renders_opacity : 1; ///< Whether object needs temporary surface for opacity
unsigned _pick_children : 1; ///< For groups: if true, children are returned from pick(),
/// otherwise the group is returned
- unsigned _antialias : 1; ///< Whether to use antialiasing
+ unsigned _antialias : 2; ///< antialiasing level (NONE/FAST/GOOD(DEFAULT)/BEST)
unsigned _isolation : 1;
unsigned _mix_blend_mode : 4;
diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp
index 63efb3c0d..d7329e670 100644
--- a/src/display/drawing-shape.cpp
+++ b/src/display/drawing-shape.cpp
@@ -180,6 +180,10 @@ DrawingShape::_renderStroke(DrawingContext &dc)
if( has_stroke ) {
// TODO: remove segments outside of bbox when no dashes present
dc.path(_curve->get_pathvector());
+ if (_style && _style->vector_effect.computed == SP_VECTOR_EFFECT_NON_SCALING_STROKE) {
+ dc.restore();
+ dc.save();
+ }
_nrstyle.applyStroke(dc);
dc.strokePreserve();
dc.newPath(); // clear path
@@ -231,20 +235,24 @@ DrawingShape::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigne
Inkscape::DrawingContext::Save save(dc);
dc.transform(_ctm);
+
// update fill and stroke paints.
// this cannot be done during nr_arena_shape_update, because we need a Cairo context
// to render svg:pattern
bool has_fill = _nrstyle.prepareFill(dc, _item_bbox, _fill_pattern);
bool has_stroke = _nrstyle.prepareStroke(dc, _item_bbox, _stroke_pattern);
has_stroke &= (_nrstyle.stroke_width != 0);
-
if (has_fill || has_stroke) {
- // TODO: remove segments outside of bbox when no dashes present
dc.path(_curve->get_pathvector());
+ // TODO: remove segments outside of bbox when no dashes present
if (has_fill) {
_nrstyle.applyFill(dc);
dc.fillPreserve();
}
+ if (_style && _style->vector_effect.computed == SP_VECTOR_EFFECT_NON_SCALING_STROKE) {
+ dc.restore();
+ dc.save();
+ }
if (has_stroke) {
_nrstyle.applyStroke(dc);
dc.strokePreserve();
diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp
index f0d83abfd..21af7b200 100644
--- a/src/display/drawing-text.cpp
+++ b/src/display/drawing-text.cpp
@@ -269,7 +269,7 @@ void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphas
int dashes[16]={
8, 7, 6, 5,
4, 3, 2, 1,
- -8, -7, -6, -5
+ -8, -7, -6, -5,
-4, -3, -2, -1
};
int dots[16]={
@@ -592,17 +592,24 @@ unsigned DrawingText::_renderItem(DrawingContext &dc, Geom::IntRect const &/*are
{
Inkscape::DrawingContext::Save save(dc);
dc.transform(_ctm);
-
if (has_fill && fill_first) {
_nrstyle.applyFill(dc);
dc.fillPreserve();
}
-
+ }
+ {
+ Inkscape::DrawingContext::Save save(dc);
+ if (!_style || !(_style->vector_effect.computed == SP_VECTOR_EFFECT_NON_SCALING_STROKE)) {
+ dc.transform(_ctm);
+ }
if (has_stroke) {
_nrstyle.applyStroke(dc);
dc.strokePreserve();
}
-
+ }
+ {
+ Inkscape::DrawingContext::Save save(dc);
+ dc.transform(_ctm);
if (has_fill && !fill_first) {
_nrstyle.applyFill(dc);
dc.fillPreserve();
diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp
index eadd7e528..71fb94be0 100644
--- a/src/display/drawing.cpp
+++ b/src/display/drawing.cpp
@@ -167,10 +167,14 @@ Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned fl
}
void
-Drawing::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags)
+Drawing::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, int antialiasing)
{
if (_root) {
+ int prev_a = _root->_antialias;
+ if(antialiasing >= 0)
+ _root->setAntialiasing(antialiasing);
_root->render(dc, area, flags);
+ _root->setAntialiasing(prev_a);
}
if (colorMode() == COLORMODE_GRAYSCALE) {
diff --git a/src/display/drawing.h b/src/display/drawing.h
index 0c12b1510..e472c8f5b 100644
--- a/src/display/drawing.h
+++ b/src/display/drawing.h
@@ -68,7 +68,7 @@ public:
void setGrayscaleMatrix(double value_matrix[20]);
void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = DrawingItem::STATE_ALL, unsigned reset = 0);
- void render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags = 0);
+ void render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags = 0, int antialiasing = -1);
DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags);
sigc::signal<void, DrawingItem *> signal_request_update;
diff --git a/src/display/gnome-canvas-acetate.cpp b/src/display/gnome-canvas-acetate.cpp
index 9147a1bbf..297d69068 100644
--- a/src/display/gnome-canvas-acetate.cpp
+++ b/src/display/gnome-canvas-acetate.cpp
@@ -14,11 +14,13 @@
*/
#include "gnome-canvas-acetate.h"
+#include "ui/event-debug.h"
static void sp_canvas_acetate_destroy(SPCanvasItem *object);
static void sp_canvas_acetate_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
static double sp_canvas_acetate_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
+static int sp_canvas_acetate_event( SPCanvasItem *item, GdkEvent *event);
G_DEFINE_TYPE(SPCanvasAcetate, sp_canvas_acetate, SP_TYPE_CANVAS_ITEM);
@@ -29,6 +31,7 @@ static void sp_canvas_acetate_class_init (SPCanvasAcetateClass *klass)
item_class->destroy = sp_canvas_acetate_destroy;
item_class->update = sp_canvas_acetate_update;
item_class->point = sp_canvas_acetate_point;
+ // item_class->event = sp_canvas_acetate_event;
}
static void sp_canvas_acetate_init (SPCanvasAcetate */*acetate*/)
@@ -60,3 +63,8 @@ static double sp_canvas_acetate_point( SPCanvasItem *item, Geom::Point /*p*/, SP
return 0.0;
}
+// static int sp_canvas_acetate_event( SPCanvasItem *item, GdkEvent *event)
+// {
+// ui_dump_event (event, "sp_canvas_acetate_event");
+// return 0; // ?
+// }
diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp
index 126fcf87c..cde10f6c2 100644
--- a/src/display/guideline.cpp
+++ b/src/display/guideline.cpp
@@ -10,12 +10,15 @@
* Copyright (C) 2000-2002 Lauris Kaplinski
* Copyright (C) 2007 Johan Engelen
* Copyright (C) 2009 Maximilian Albert
+ * Copyright (C) 2017 Tavmjong Bah
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <2geom/coord.h>
#include <2geom/transforms.h>
+#include <2geom/line.h>
+
#include "sp-canvas-util.h"
#include "guideline.h"
#include "display/cairo-utils.h"
@@ -29,8 +32,6 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf);
static double sp_guideline_point(SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
-static void sp_guideline_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, guint32 rgba);
-
G_DEFINE_TYPE(SPGuideLine, sp_guideline, SP_TYPE_CANVAS_ITEM);
static void sp_guideline_class_init(SPGuideLineClass *c)
@@ -48,7 +49,7 @@ static void sp_guideline_init(SPGuideLine *gl)
gl->locked = false;
gl->normal_to_line = Geom::Point(0,1);
- gl->angle = 3.14159265358979323846/2;
+ gl->angle = M_PI_2;
gl->point_on_line = Geom::Point(0,0);
gl->sensitive = 0;
@@ -76,10 +77,6 @@ static void sp_guideline_destroy(SPCanvasItem *object)
static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf)
{
- //TODO: the routine that renders the label of a specific guideline sometimes
- // ends up erasing the labels of the other guidelines.
- // Maybe we should render all labels everytime.
-
SPGuideLine const *gl = SP_GUIDELINE (item);
cairo_save(buf->ct);
@@ -89,8 +86,9 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf)
cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE);
cairo_set_font_size(buf->ct, 10);
- Geom::Point normal_dt = /*unit_vector*/(gl->normal_to_line * gl->affine.withoutTranslation()); // note that normal_dt does not have unit length
- Geom::Point point_on_line_dt = gl->point_on_line * gl->affine;
+ // normal_dt does not have unit length
+ Geom::Point normal_dt = gl->normal_to_line * gl->affine.withoutTranslation();
+ Geom::Point point_on_line_dt = gl->point_on_line * gl->affine;
if (gl->label) {
int px = round(point_on_line_dt[Geom::X]);
@@ -104,55 +102,54 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf)
cairo_restore(buf->ct);
}
- if ( Geom::are_near(normal_dt[Geom::Y], 0.) ) { // is vertical?
+ // Draw guide.
+ // Special case horizontal and vertical lines so they snap to pixels.
+ // Don't use isHorizontal()/isVertical() as they test only exact matches.
+ if ( Geom::are_near(normal_dt[Geom::Y], 0.0) ) { // Vertical?
+
int position = round(point_on_line_dt[Geom::X]);
cairo_move_to(buf->ct, position + 0.5, buf->rect.top() + 0.5);
cairo_line_to(buf->ct, position + 0.5, buf->rect.bottom() - 0.5);
cairo_stroke(buf->ct);
- } else if ( Geom::are_near(normal_dt[Geom::X], 0.) ) { // is horizontal?
+
+ } else if ( Geom::are_near(normal_dt[Geom::X], 0.0) ) { // Horizontal?
+
int position = round(point_on_line_dt[Geom::Y]);
cairo_move_to(buf->ct, buf->rect.left() + 0.5, position + 0.5);
cairo_line_to(buf->ct, buf->rect.right() - 0.5, position + 0.5);
cairo_stroke(buf->ct);
- } else {
- // render angled line. Once intersection has been detected, draw from there.
- Geom::Point parallel_to_line( normal_dt.ccw() );
-
- //try to intersect with left vertical of rect
- double y_intersect_left = (buf->rect.left() - point_on_line_dt[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + point_on_line_dt[Geom::Y];
- if ( (y_intersect_left >= buf->rect.top()) && (y_intersect_left <= buf->rect.bottom()) ) {
- // intersects with left vertical!
- double y_intersect_right = (buf->rect.right() - point_on_line_dt[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + point_on_line_dt[Geom::Y];
- sp_guideline_drawline (buf, buf->rect.left(), static_cast<gint>(round(y_intersect_left)), buf->rect.right(), static_cast<gint>(round(y_intersect_right)), gl->rgba);
- goto end;
- }
- //try to intersect with right vertical of rect
- double y_intersect_right = (buf->rect.right() - point_on_line_dt[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + point_on_line_dt[Geom::Y];
- if ( (y_intersect_right >= buf->rect.top()) && (y_intersect_right <= buf->rect.bottom()) ) {
- // intersects with right vertical!
- sp_guideline_drawline (buf, buf->rect.right(), static_cast<gint>(round(y_intersect_right)), buf->rect.left(), static_cast<gint>(round(y_intersect_left)), gl->rgba);
- goto end;
- }
+ } else {
- //try to intersect with top horizontal of rect
- double x_intersect_top = (buf->rect.top() - point_on_line_dt[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + point_on_line_dt[Geom::X];
- if ( (x_intersect_top >= buf->rect.left()) && (x_intersect_top <= buf->rect.right()) ) {
- // intersects with top horizontal!
- double x_intersect_bottom = (buf->rect.bottom() - point_on_line_dt[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + point_on_line_dt[Geom::X];
- sp_guideline_drawline (buf, static_cast<gint>(round(x_intersect_top)), buf->rect.top(), static_cast<gint>(round(x_intersect_bottom)), buf->rect.bottom(), gl->rgba);
- goto end;
+ Geom::Line guide =
+ Geom::Line::from_origin_and_vector( point_on_line_dt, Geom::rot90(normal_dt) );
+
+ // Find intersections of guide with buf rectangle. There should be zero or two.
+ std::vector<Geom::Point> intersections;
+ for (unsigned i = 0; i < 4; ++i) {
+ Geom::LineSegment side( buf->rect.corner(i), buf->rect.corner((i+1)%4) );
+ try {
+ Geom::OptCrossing oc = Geom::intersection(guide, side);
+ if (oc) {
+ intersections.push_back( guide.pointAt((*oc).ta));
+ }
+ } catch (Geom::InfiniteSolutions) {
+ // Shouldn't happen as we have already taken care of horizontal/vertical guides.
+ std::cerr << "sp_guideline_render: Error: Infinite intersections." << std::endl;
+ }
}
- //try to intersect with bottom horizontal of rect
- double x_intersect_bottom = (buf->rect.bottom() - point_on_line_dt[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + point_on_line_dt[Geom::X];
- if ( (x_intersect_top >= buf->rect.left()) && (x_intersect_top <= buf->rect.right()) ) {
- // intersects with bottom horizontal!
- sp_guideline_drawline (buf, static_cast<gint>(round(x_intersect_bottom)), buf->rect.bottom(), static_cast<gint>(round(x_intersect_top)), buf->rect.top(), gl->rgba);
- goto end;
+ if (intersections.size() == 2) {
+ double x0 = intersections[0][Geom::X];
+ double x1 = intersections[1][Geom::X];
+ double y0 = intersections[0][Geom::Y];
+ double y1 = intersections[1][Geom::Y];
+ cairo_move_to(buf->ct, x0, y0);
+ cairo_line_to(buf->ct, x1, y1);
+ cairo_stroke(buf->ct);
}
}
- end:
+
cairo_restore(buf->ct);
}
@@ -179,15 +176,10 @@ static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine,
}
gl->affine = affine;
- Geom::Point pol_transformed = gl->point_on_line * affine;
- if (gl->is_horizontal()) {
- sp_canvas_update_bbox (item, -1000000, round(pol_transformed[Geom::Y] - 16), 1000000, round(pol_transformed[Geom::Y] + 1));
- } else if (gl->is_vertical()) {
- sp_canvas_update_bbox (item, round(pol_transformed[Geom::X]), -1000000, round(pol_transformed[Geom::X] + 16), 1000000);
- } else {
- //TODO: labels in angled guidelines are not showing up for some reason.
- sp_canvas_update_bbox (item, -1000000, -1000000, 1000000, 1000000);
- }
+
+ // Rotated canvas requires large bbox for all guides.
+ sp_canvas_update_bbox (item, -1000000, -1000000, 1000000, 1000000);
+
}
// Returns 0.0 if point is on the guideline
@@ -276,14 +268,6 @@ void sp_guideline_delete(SPGuideLine *gl)
sp_canvas_item_destroy(SP_CANVAS_ITEM(gl));
}
-static void
-sp_guideline_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, guint32 /*rgba*/)
-{
- cairo_move_to(buf->ct, x0 + 0.5, y0 + 0.5);
- cairo_line_to(buf->ct, x1 + 0.5, y1 + 0.5);
- cairo_stroke(buf->ct);
-}
-
/*
Local Variables:
mode:c++
diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp
index 19dedb67c..1397c0f34 100644
--- a/src/display/nr-filter-turbulence.cpp
+++ b/src/display/nr-filter-turbulence.cpp
@@ -286,15 +286,7 @@ private:
static int const BSize = 0x100;
static int const BMask = 0xff;
-#ifdef CPP11 // GCC 4.6.1 (currently used on Windows) does not correctly set __cplusplus in C++11 mode, so configure with -DCPP11 to make this work in C++11 mode
static double constexpr PerlinOffset = 4096.0;
-#else
-#if (__cplusplus < 201103L)
- static double const PerlinOffset;
-#else
- static double constexpr PerlinOffset = 4096.0;
-#endif
-#endif
Geom::Rect _tile;
Geom::Point _baseFreq;
@@ -311,10 +303,6 @@ private:
bool _fractalnoise;
};
-#if !defined(CPP11) && __cplusplus < 201103L
- double const TurbulenceGenerator::PerlinOffset = 4096.0;
-#endif
-
FilterTurbulence::FilterTurbulence()
: gen(new TurbulenceGenerator())
, XbaseFrequency(0)
diff --git a/src/display/nr-filter-utils.h b/src/display/nr-filter-utils.h
index 35a74d7c1..52b6bd11a 100644
--- a/src/display/nr-filter-utils.h
+++ b/src/display/nr-filter-utils.h
@@ -14,8 +14,6 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "round.h"
-
namespace Inkscape {
namespace Filters {
diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp
index 789758d9c..d430553d4 100644
--- a/src/display/nr-filter.cpp
+++ b/src/display/nr-filter.cpp
@@ -48,11 +48,6 @@
#include "sp-filter-units.h"
#include "preferences.h"
-#if defined (SOLARIS) && (SOLARIS == 8)
-#include "round.h"
-using Inkscape::round;
-#endif
-
namespace Inkscape {
namespace Filters {
diff --git a/src/display/nr-svgfonts.cpp b/src/display/nr-svgfonts.cpp
index 011f51977..fd092aed8 100644
--- a/src/display/nr-svgfonts.cpp
+++ b/src/display/nr-svgfonts.cpp
@@ -197,21 +197,27 @@ SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t */*scaled_font*/,
bool is_horizontal_text = true; //TODO
_utf8 = (char*) utf8;
+ double font_height = units_per_em();
while(g_utf8_get_char(_utf8)){
len = 0;
for (i=0; i < (unsigned long) this->glyphs.size(); i++){
//check whether is there a glyph declared on the SVG document
// that matches with the text string in its current position
if ( (len = size_of_substring(this->glyphs[i]->unicode.c_str(), _utf8)) ){
- for(SPObject* node = this->font->children;previous_unicode && node;node=node->next){
+ for(auto& node: font->children) {
+ if (!previous_unicode) {
+ break;
+ }
//apply glyph kerning if appropriate
- SPHkern *hkern = dynamic_cast<SPHkern *>(node);
- if (hkern && is_horizontal_text && MatchHKerningRule(hkern, this->glyphs[i], previous_unicode, previous_glyph_name) ){
- x -= (hkern->k / 1000.0);//TODO: use here the height of the font
+ SPHkern *hkern = dynamic_cast<SPHkern *>(&node);
+ if (hkern && is_horizontal_text &&
+ MatchHKerningRule(hkern, this->glyphs[i], previous_unicode, previous_glyph_name) ){
+ x -= (hkern->k / font_height);
}
- SPVkern *vkern = dynamic_cast<SPVkern *>(node);
- if (vkern && !is_horizontal_text && MatchVKerningRule(vkern, this->glyphs[i], previous_unicode, previous_glyph_name) ){
- y -= (vkern->k / 1000.0);//TODO: use here the "height" of the font
+ SPVkern *vkern = dynamic_cast<SPVkern *>(&node);
+ if (vkern && !is_horizontal_text &&
+ MatchVKerningRule(vkern, this->glyphs[i], previous_unicode, previous_glyph_name) ){
+ y -= (vkern->k / font_height);
}
}
previous_unicode = const_cast<char*>(this->glyphs[i]->unicode.c_str());//used for kerning checking
@@ -221,8 +227,15 @@ SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t */*scaled_font*/,
(*glyphs)[count++].y = y;
//advance glyph coordinates:
- if (is_horizontal_text) x+=(this->font->horiz_adv_x/1000.0);//TODO: use here the height of the font
- else y+=(this->font->vert_adv_y/1000.0);//TODO: use here the "height" of the font
+ if (is_horizontal_text) {
+ if (this->glyphs[i]->horiz_adv_x != 0) {
+ x+=(this->glyphs[i]->horiz_adv_x/font_height);
+ } else {
+ x+=(this->font->horiz_adv_x/font_height);
+ }
+ } else {
+ y+=(this->font->vert_adv_y/font_height);
+ }
_utf8+=len; //advance 'len' bytes in our string pointer
//continue;
goto raptorz;
@@ -235,8 +248,8 @@ SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t */*scaled_font*/,
(*glyphs)[count++].y = y;
//advance glyph coordinates:
- if (is_horizontal_text) x+=(this->font->horiz_adv_x/1000.0);//TODO: use here the height of the font
- else y+=(this->font->vert_adv_y/1000.0);//TODO: use here the "height" of the font
+ if (is_horizontal_text) x+=(this->font->horiz_adv_x/font_height);//TODO: use here the height of the font
+ else y+=(this->font->vert_adv_y/font_height);//TODO: use here the "height" of the font
_utf8 = g_utf8_next_char(_utf8); //advance 1 char in our string pointer
}
@@ -252,9 +265,7 @@ SvgFont::render_glyph_path(cairo_t* cr, Geom::PathVector* pathv){
cairo_new_path(cr);
//adjust scale of the glyph
-// Geom::Scale s(1.0/((SPFont*) node->parent)->horiz_adv_x);
- Geom::Scale s(1.0/1000);//TODO: use here the units-per-em attribute?
-
+ Geom::Scale s(1.0/units_per_em());
Geom::Rect area( Geom::Point(0,0), Geom::Point(1,1) ); //I need help here! (reaction: note that the 'area' parameter is an *optional* rect, so you can pass an empty Geom::OptRect() )
feed_pathvector_to_cairo (cr, *pathv, s, area, false, 0);
@@ -270,11 +281,11 @@ SvgFont::glyph_modified(SPObject* /* blah */, unsigned int /* bleh */){
Geom::PathVector
SvgFont::flip_coordinate_system(SPFont* spfont, Geom::PathVector pathv){
- double units_per_em = 1000;
- for (SPObject *obj = spfont->children; obj; obj = obj->next){
- if (dynamic_cast<SPFontFace *>(obj)) {
+ double units_per_em = 1024;
+ for(auto& obj: spfont->children) {
+ if (dynamic_cast<SPFontFace *>(&obj)) {
//XML Tree being directly used here while it shouldn't be.
- sp_repr_get_double(obj->getRepr(), "units_per_em", &units_per_em);
+ sp_repr_get_double(obj.getRepr(), "units_per_em", &units_per_em);
}
}
@@ -339,19 +350,19 @@ SvgFont::scaled_font_render_glyph (cairo_scaled_font_t */*scaled_font*/,
if (node->hasChildren()){
//render the SVG described on this glyph's child nodes.
- for(node = node->children; node; node=node->next){
+ for(auto& child: node->children) {
{
- SPPath *path = dynamic_cast<SPPath *>(node);
+ SPPath *path = dynamic_cast<SPPath *>(&child);
if (path) {
pathv = path->_curve->get_pathvector();
pathv = flip_coordinate_system(spfont, pathv);
render_glyph_path(cr, &pathv);
}
}
- if (dynamic_cast<SPObjectGroup *>(node)) {
+ if (dynamic_cast<SPObjectGroup *>(&child)) {
g_warning("TODO: svgfonts: render OBJECTGROUP");
}
- SPUse *use = dynamic_cast<SPUse *>(node);
+ SPUse *use = dynamic_cast<SPUse *>(&child);
if (use) {
SPItem* item = use->ref->getObject();
SPPath *path = dynamic_cast<SPPath *>(item);
@@ -374,12 +385,12 @@ SvgFont::scaled_font_render_glyph (cairo_scaled_font_t */*scaled_font*/,
cairo_font_face_t*
SvgFont::get_font_face(){
if (!this->userfont) {
- for(SPObject* node = this->font->children;node;node=node->next){
- SPGlyph *glyph = dynamic_cast<SPGlyph *>(node);
+ for(auto& node: font->children) {
+ SPGlyph *glyph = dynamic_cast<SPGlyph *>(&node);
if (glyph) {
glyphs.push_back(glyph);
}
- SPMissingGlyph *missing = dynamic_cast<SPMissingGlyph *>(node);
+ SPMissingGlyph *missing = dynamic_cast<SPMissingGlyph *>(&node);
if (missing) {
missingglyph = missing;
}
@@ -395,6 +406,20 @@ void SvgFont::refresh(){
this->userfont = NULL;
}
+double SvgFont::units_per_em() {
+ double units_per_em = 1024;
+ for (auto& obj: font->children) {
+ if (dynamic_cast<SPFontFace *>(&obj)) {
+ //XML Tree being directly used here while it shouldn't be.
+ sp_repr_get_double(obj.getRepr(), "units-per-em", &units_per_em);
+ }
+ }
+ if (units_per_em <= 0.0) {
+ units_per_em = 1024;
+ }
+ return units_per_em;
+}
+
/*
Local Variables:
mode:c++
diff --git a/src/display/nr-svgfonts.h b/src/display/nr-svgfonts.h
index 21ab3ed02..d4488fb17 100644
--- a/src/display/nr-svgfonts.h
+++ b/src/display/nr-svgfonts.h
@@ -52,7 +52,8 @@ private:
SPMissingGlyph* missingglyph;
sigc::connection glyph_modified_connection;
- bool drawing_expose_cb (Gtk::Widget *widget, GdkEventExpose *event, void* data);
+ double units_per_em();
+ //bool drawing_expose_cb (Gtk::Widget *widget, GdkEventExpose *event, void* data);
};
#endif //#ifndef NR_SVGFONTS_H_SEEN
diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp
index 17deea16d..f2271e0c6 100644
--- a/src/display/snap-indicator.cpp
+++ b/src/display/snap-indicator.cpp
@@ -287,7 +287,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap
} else if (p.getSource() != SNAPSOURCE_UNDEFINED) {
tooltip_str = g_strdup(source_name);
}
- double fontsize = prefs->getInt("/tools/measure/fontsize");
+ double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0);
if (tooltip_str) {
Geom::Point tooltip_pos = p.getPoint();
@@ -327,7 +327,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap
SP_CTRLRECT(box)->setDashed(true);
SP_CTRLRECT(box)->pickable = false; // See the extensive comment above
sp_canvas_item_move_to_z(box, 0);
- _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val);
+ _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val*1000.0);
}
}
}
diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp
index 327fbce1f..27b6988c5 100644
--- a/src/display/sodipodi-ctrl.cpp
+++ b/src/display/sodipodi-ctrl.cpp
@@ -18,6 +18,7 @@ enum {
ARG_MODE,
ARG_ANCHOR,
ARG_SIZE,
+ ARG_ANGLE,
ARG_FILLED,
ARG_FILL_COLOR,
ARG_STROKED,
@@ -53,7 +54,7 @@ sp_ctrl_class_init (SPCtrlClass *klass)
g_object_class_install_property (g_object_class,
ARG_SIZE, g_param_spec_double ("size", "size", "Size", 0.0, G_MAXDOUBLE, 8.0, (GParamFlags) G_PARAM_READWRITE));
g_object_class_install_property (g_object_class,
- ARG_PIXBUF, g_param_spec_pointer ("pixbuf", "pixbuf", "Pixbuf", (GParamFlags) G_PARAM_READWRITE));
+ ARG_ANGLE, g_param_spec_double ("angle", "angle", "Angle", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, (GParamFlags) G_PARAM_READWRITE));
g_object_class_install_property (g_object_class,
ARG_FILLED, g_param_spec_boolean ("filled", "filled", "Filled", TRUE, (GParamFlags) G_PARAM_READWRITE));
g_object_class_install_property (g_object_class,
@@ -62,6 +63,8 @@ sp_ctrl_class_init (SPCtrlClass *klass)
ARG_STROKED, g_param_spec_boolean ("stroked", "stroked", "Stroked", FALSE, (GParamFlags) G_PARAM_READWRITE));
g_object_class_install_property (g_object_class,
ARG_STROKE_COLOR, g_param_spec_int ("stroke_color", "stroke_color", "Stroke Color", G_MININT, G_MAXINT, 0x000000ff, (GParamFlags) G_PARAM_READWRITE));
+ g_object_class_install_property (g_object_class,
+ ARG_PIXBUF, g_param_spec_pointer ("pixbuf", "pixbuf", "Pixbuf", (GParamFlags) G_PARAM_READWRITE));
item_class->destroy = sp_ctrl_destroy;
item_class->update = sp_ctrl_update;
@@ -95,6 +98,9 @@ sp_ctrl_set_property(GObject *object, guint prop_id, const GValue *value, GParam
ctrl->height = ctrl->width;
ctrl->defined = (ctrl->width > 0);
break;
+ case ARG_ANGLE:
+ ctrl->angle = (double)g_value_get_double(value);
+ break;
case ARG_FILLED:
ctrl->filled = g_value_get_boolean(value);
break;
@@ -151,6 +157,10 @@ sp_ctrl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec
g_value_set_double(value, ctrl->width);
break;
+ case ARG_ANGLE:
+ g_value_set_double(value, ctrl->angle);
+ break;
+
case ARG_FILLED:
g_value_set_boolean(value, ctrl->filled);
break;
@@ -192,6 +202,7 @@ sp_ctrl_init (SPCtrl *ctrl)
ctrl->stroked = 0;
ctrl->fill_color = 0x000000ff;
ctrl->stroke_color = 0x000000ff;
+ ctrl->angle = 0.0;
new (&ctrl->box) Geom::IntRect(0,0,0,0);
ctrl->cache = NULL;
@@ -291,6 +302,23 @@ sp_ctrl_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item)
return 1e18;
}
+bool
+sp_point_inside_line(Geom::Point a, Geom::Point b, Geom::Point c, double tolerance = 0.1){
+ //http://stackoverflow.com/questions/328107/how-can-you-determine-a-point-is-between-two-other-points-on-a-line-segment
+ return Geom::are_near(Geom::distance(a,c) + Geom::distance(c,b) , Geom::distance(a,b), tolerance);
+}
+
+bool
+sp_point_inside_triangle(Geom::Point p1,Geom::Point p2,Geom::Point p3, Geom::Point point){
+ using Geom::X;
+ using Geom::Y;
+ double denominator = (p1[X]*(p2[Y] - p3[Y]) + p1[Y]*(p3[X] - p2[X]) + p2[X]*p3[Y] - p2[Y]*p3[X]);
+ double t1 = (point[X]*(p3[Y] - p1[Y]) + point[Y]*(p1[X] - p3[X]) - p1[X]*p3[Y] + p1[Y]*p3[X]) / denominator;
+ double t2 = (point[X]*(p2[Y] - p1[Y]) + point[Y]*(p1[X] - p2[X]) - p1[X]*p2[Y] + p1[Y]*p2[X]) / -denominator;
+ double see = t1 + t2;
+ return 0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1 && see <= 1;
+}
+
static void
sp_ctrl_build_cache (SPCtrl *ctrl)
{
@@ -316,7 +344,7 @@ sp_ctrl_build_cache (SPCtrl *ctrl)
} else {
stroke_color = fill_color;
}
-
+ gint32 stroke_color_smooth = SP_RGBA32_F_COMPOSE(SP_RGBA32_R_F(stroke_color), SP_RGBA32_G_F(stroke_color), SP_RGBA32_B_F(stroke_color), 0.15);
width = (ctrl->width * 2 +1);
height = (ctrl->height * 2 +1);
c = ctrl->width; // Only used for pre-set square drawing
@@ -325,7 +353,24 @@ sp_ctrl_build_cache (SPCtrl *ctrl)
if (ctrl->cache) delete[] ctrl->cache;
ctrl->cache = new guint32[size];
-
+ Geom::Point point;
+ Geom::Point p1;
+ Geom::Point p2;
+ Geom::Point p3;
+ if(ctrl->shape == SP_CTRL_SHAPE_TRIANGLE){
+ Geom::Affine m = Geom::Translate(Geom::Point(-width/2.0,-height/2.0));
+ m *= Geom::Rotate(-ctrl->angle);
+ m *= Geom::Translate(Geom::Point(width/2.0, height/2.0));
+ p1 = Geom::Point(0,height/2);
+ p2 = Geom::Point(width - (width/M_PI), height/M_PI);
+ p3 = Geom::Point(width - (width/M_PI), height-(height/M_PI));
+ p1 *= m;
+ p2 *= m;
+ p3 *= m;
+ p1 = p1.floor();
+ p2 = p2.floor();
+ p3 = p3.floor();
+ }
switch (ctrl->shape) {
case SP_CTRL_SHAPE_SQUARE:
p = ctrl->cache;
@@ -407,6 +452,29 @@ sp_ctrl_build_cache (SPCtrl *ctrl)
ctrl->build = TRUE;
break;
+ case SP_CTRL_SHAPE_TRIANGLE:
+ p = ctrl->cache;
+ for(y = 0; y < height; y++) {
+ for(x = 0; x < width; x++) {
+ point = Geom::Point(x,y);
+ if (sp_point_inside_triangle(p1, p2, p3, point)) {
+ p[(y*width)+x] = fill_color;
+ } else if (point == p1 || point == p2 || point == p3 || sp_point_inside_line(p1, p2, point, 0.2) ||
+ sp_point_inside_line(p3, p1, point, 0.2))
+ {
+ p[(y*width)+x] = stroke_color;
+ } else if (sp_point_inside_line(p1, p2, point, 0.5) ||
+ sp_point_inside_line(p3, p1, point, 0.5))
+ {
+ p[(y*width)+x] = stroke_color_smooth;
+ } else {
+ p[(y*width)+x] = 0;
+ }
+ }
+ }
+ ctrl->build = TRUE;
+ break;
+
case SP_CTRL_SHAPE_CROSS:
p = ctrl->cache;
for (y = 0; y < height; y++) {
diff --git a/src/display/sodipodi-ctrl.h b/src/display/sodipodi-ctrl.h
index ecdb896a7..ac5ac9442 100644
--- a/src/display/sodipodi-ctrl.h
+++ b/src/display/sodipodi-ctrl.h
@@ -22,6 +22,7 @@ typedef enum {
SP_CTRL_SHAPE_SQUARE,
SP_CTRL_SHAPE_DIAMOND,
SP_CTRL_SHAPE_CIRCLE,
+ SP_CTRL_SHAPE_TRIANGLE,
SP_CTRL_SHAPE_CROSS,
SP_CTRL_SHAPE_BITMAP,
SP_CTRL_SHAPE_IMAGE
@@ -46,6 +47,7 @@ struct SPCtrl : public SPCanvasItem {
guint stroked : 1;
guint32 fill_color;
guint32 stroke_color;
+ gdouble angle;
Geom::IntRect box; /* NB! x1 & y1 are included */
guint32 *cache;
diff --git a/src/display/sodipodi-ctrlrect.cpp b/src/display/sodipodi-ctrlrect.cpp
index ecc952c48..075e04e6d 100644
--- a/src/display/sodipodi-ctrlrect.cpp
+++ b/src/display/sodipodi-ctrlrect.cpp
@@ -6,9 +6,11 @@
* bulia byak <buliabyak@users.sf.net>
* Carl Hetherington <inkscape@carlh.net>
* Jon A. Cruz <jon@joncruz.org>
+ * Tavmjong Bah <tavmjong@free.fr>
*
* Copyright (C) 1999-2001 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
+ * Copyright (C) 2017 Tavmjong Bah
*
* Released under GNU GPL
*
@@ -18,6 +20,7 @@
#include "sp-canvas-util.h"
#include "display/cairo-utils.h"
#include "display/sp-canvas.h"
+#include <2geom/transforms.h>
/*
* Currently we do not have point method, as it should always be painted
@@ -76,14 +79,12 @@ void CtrlRect::init()
_dashed = false;
_checkerboard = false;
- _shadow = 0;
+ _shadow_width = 0;
_area = Geom::OptIntRect();
_rect = Geom::Rect(Geom::Point(0,0),Geom::Point(0,0));
- _shadow_size = 0;
-
_border_color = 0x000000ff;
_fill_color = 0xffffffff;
_shadow_color = 0x000000ff;
@@ -98,52 +99,120 @@ void CtrlRect::render(SPCanvasBuf *buf)
if (!_area) {
return;
}
- Geom::IntRect area = *_area;
- Geom::IntRect area_w_shadow (area[X].min(), area[Y].min(),
- area[X].max() + _shadow_size, area[Y].max() + _shadow_size);
- if ( area_w_shadow.intersects(buf->rect) )
+
+ Geom::IntRect area = *_area; // _area already includes space for shadow.
+ if ( area.intersects(buf->rect) )
{
- static double const dashes[2] = {4.0, 4.0};
+
cairo_save(buf->ct);
cairo_translate(buf->ct, -buf->rect.left(), -buf->rect.top());
- cairo_set_line_width(buf->ct, 1);
- if (_dashed) cairo_set_dash(buf->ct, dashes, 2, 0);
- cairo_rectangle(buf->ct, 0.5 + area[X].min(), 0.5 + area[Y].min(),
- area[X].max() - area[X].min(), area[Y].max() - area[Y].min());
+
+ // Get canvas rotation (scale is isotropic).
+ double rotation = atan2( _affine[1], _affine[0] );
+
+ // Are we axis aligned?
+ double mod_rot = fmod(rotation * M_2_PI, 1);
+ bool axis_aligned = Geom::are_near( mod_rot, 0 ) || Geom::are_near( mod_rot, 1.0 );
+
+ // Get the points we need transformed to window coordinates.
+ Geom::Point rect_transformed[4];
+ for (unsigned i = 0; i < 4; ++i) {
+ rect_transformed[i] = _rect.corner(i) * _affine;
+ }
+
+ // Draw shadow first. Shadow extends under rectangle to reduce aliasing effects.
+ if (_shadow_width > 0 && !_dashed) {
+
+ // Offset by half stroke width (_shadow_width is in window coordinates).
+ // Need to handle change in handedness with flips.
+ Geom::Point shadow( _shadow_width/2.0, (_affine.det()>0?-1:1)*_shadow_width/2.0 );
+ shadow *= Geom::Rotate( rotation );
+
+ if (axis_aligned) {
+ // Snap to pixel grid (add 0.5 to center on pixel).
+ cairo_move_to( buf->ct,
+ floor(rect_transformed[0][X]+shadow[X]+0.5) + 0.5,
+ floor(rect_transformed[0][Y]+shadow[Y]+0.5) + 0.5 );
+ cairo_line_to( buf->ct,
+ floor(rect_transformed[1][X]+shadow[X]+0.5) + 0.5,
+ floor(rect_transformed[1][Y]+shadow[Y]+0.5) + 0.5 );
+ cairo_line_to( buf->ct,
+ floor(rect_transformed[2][X]+shadow[X]+0.5) + 0.5,
+ floor(rect_transformed[2][Y]+shadow[Y]+0.5) + 0.5 );
+ } else {
+ cairo_move_to( buf->ct,
+ rect_transformed[0][X]+shadow[X],
+ rect_transformed[0][Y]+shadow[Y] );
+ cairo_line_to( buf->ct,
+ rect_transformed[1][X]+shadow[X],
+ rect_transformed[1][Y]+shadow[Y] );
+ cairo_line_to( buf->ct,
+ rect_transformed[2][X]+shadow[X],
+ rect_transformed[2][Y]+shadow[Y] );
+ }
+
+ ink_cairo_set_source_rgba32( buf->ct, _shadow_color );
+ cairo_set_line_width( buf->ct, _shadow_width + 1 );
+ cairo_stroke( buf->ct );
+ }
+
+ // Setup rectangle path
+ if (axis_aligned) {
+
+ // Snap to pixel grid
+ Geom::Rect outline( _rect.min() * _affine, _rect.max() * _affine);
+ // Check if there is a simpler way to go from 'outline' to 'int_rect'.
+ Geom::IntRect int_rect ( (int) floor(outline.min()[X] + 0.5),
+ (int) floor(outline.min()[Y] + 0.5),
+ (int) floor(outline.max()[X] + 0.5),
+ (int) floor(outline.max()[Y] + 0.5) );
+ cairo_rectangle (buf->ct,
+ 0.5 + int_rect[X].min(),
+ 0.5 + int_rect[Y].min(),
+ int_rect[X].max() - int_rect[X].min(),
+ int_rect[Y].max() - int_rect[Y].min() );
+ } else {
+
+ // Angled
+ cairo_move_to( buf->ct, rect_transformed[0][X], rect_transformed[0][Y] );
+ cairo_line_to( buf->ct, rect_transformed[1][X], rect_transformed[1][Y] );
+ cairo_line_to( buf->ct, rect_transformed[2][X], rect_transformed[2][Y] );
+ cairo_line_to( buf->ct, rect_transformed[3][X], rect_transformed[3][Y] );
+ cairo_close_path( buf->ct );
+ }
+
+ // This doesn't seem to be used anywhere. If it is, then we should
+ // probably rotate the coordinate system and fill using a cairo_rectangle().
if (_checkerboard) {
cairo_pattern_t *cb = ink_cairo_pattern_create_checkerboard();
cairo_set_source(buf->ct, cb);
cairo_pattern_destroy(cb);
cairo_fill_preserve(buf->ct);
}
+
if (_has_fill) {
ink_cairo_set_source_rgba32(buf->ct, _fill_color);
cairo_fill_preserve(buf->ct);
}
+ // Set up stroke.
ink_cairo_set_source_rgba32(buf->ct, _border_color);
- cairo_stroke(buf->ct);
+ cairo_set_line_width(buf->ct, 1);
+ static double const dashes[2] = {4.0, 4.0};
+ if (_dashed) cairo_set_dash(buf->ct, dashes, 2, 0);
- if (_shadow_size == 1) { // highlight the border by drawing it in _shadow_color
- if (_dashed) {
- cairo_set_dash(buf->ct, dashes, 2, 4);
- cairo_rectangle(buf->ct, 0.5 + area[X].min(), 0.5 + area[Y].min(),
- area[X].max() - area[X].min(), area[Y].max() - area[Y].min());
- } else {
- cairo_rectangle(buf->ct, -0.5 + area[X].min(), -0.5 + area[Y].min(),
- area[X].max() - area[X].min(), area[Y].max() - area[Y].min());
- }
- ink_cairo_set_source_rgba32(buf->ct, _shadow_color);
- cairo_stroke(buf->ct);
- } else if (_shadow_size > 1) { // fill the shadow
+ // Stroke rectangle.
+ cairo_stroke_preserve(buf->ct);
+
+ // Highlight the border by drawing it in _shadow_color.
+ if (_shadow_width == 1 && _dashed) {
ink_cairo_set_source_rgba32(buf->ct, _shadow_color);
- cairo_rectangle(buf->ct, 1 + area[X].max(), area[Y].min() + _shadow_size,
- _shadow_size, area[Y].max() - area[Y].min() + 1); // right shadow
- cairo_rectangle(buf->ct, area[X].min() + _shadow_size, 1 + area[Y].max(),
- area[X].max() - area[X].min() - _shadow_size + 1, _shadow_size);
- cairo_fill(buf->ct);
+ cairo_set_dash(buf->ct, dashes, 2, 4); // Dash offset by dash length.
+ cairo_stroke_preserve(buf->ct);
}
+
+ cairo_new_path( buf->ct ); // Clear path or get wierd artifacts.
cairo_restore(buf->ct);
}
}
@@ -158,124 +227,33 @@ void CtrlRect::update(Geom::Affine const &affine, unsigned int flags)
(SP_CANVAS_ITEM_CLASS(sp_ctrlrect_parent_class))->update(this, affine, flags);
}
- sp_canvas_item_reset_bounds(this);
+ // Note: There is no harm if 'area' is too large other than a possible small slow down in
+ // rendering speed.
- Geom::Rect bbox(_rect.min() * affine, _rect.max() * affine);
+ // Calculate an axis-aligned bounding box that include all of transformed _rect.
+ Geom::Rect bbox = _rect;
+ bbox *= affine;
- Geom::OptIntRect _area_old = _area;
- Geom::IntRect area ( (int) floor(bbox.min()[Geom::X] + 0.5),
- (int) floor(bbox.min()[Geom::Y] + 0.5),
- (int) floor(bbox.max()[Geom::X] + 0.5),
- (int) floor(bbox.max()[Geom::Y] + 0.5) );
- _area = area;
- Geom::IntRect area_old(0,0,0,0);
- if (_area_old) { // this weird construction is because the code below assumes _area_old to be 'valid'
- area_old = *_area_old;
- }
+ // Enlarge bbox by twice shadow size (to allow for shadow on any side with a 45deg rotation).
+ bbox.expandBy( 2.0 *_shadow_width );
- gint _shadow_size_old = _shadow_size;
- _shadow_size = _shadow;
-
- // FIXME: we don't process a possible change in _has_fill
- if (_has_fill) {
- if (_area_old) {
- canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].min() - 1,
- area_old[X].max() + _shadow_size + 1, area_old[Y].max() + _shadow_size + 1);
- }
- if (_area) {
- canvas->requestRedraw(area[X].min() - 1, area[Y].min() - 1,
- area[X].max() + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- }
- } else { // clear box, be smart about what part of the frame to redraw
-
- /* Top */
- if (area[Y].min() != area_old[Y].min()) { // different level, redraw fully old and new
- if (area_old[X].min() != area_old[X].max())
- canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].min() - 1,
- area_old[X].max() + 1, area_old[Y].min() + 1);
-
- if (area[X].min() != area[X].max())
- canvas->requestRedraw(area[X].min() - 1, area[Y].min() - 1,
- area[X].max() + 1, area[Y].min() + 1);
- } else { // same level, redraw only the ends
- if (area[X].min() != area_old[X].min()) {
- canvas->requestRedraw(MIN(area_old[X].min(),area[X].min()) - 1, area[Y].min() - 1,
- MAX(area_old[X].min(),area[X].min()) + 1, area[Y].min() + 1);
- }
- if (area[X].max() != area_old[X].max()) {
- canvas->requestRedraw(MIN(area_old[X].max(),area[X].max()) - 1, area[Y].min() - 1,
- MAX(area_old[X].max(),area[X].max()) + 1, area[Y].min() + 1);
- }
- }
-
- /* Left */
- if (area[X].min() != area_old[X].min()) { // different level, redraw fully old and new
- if (area_old[Y].min() != area_old[Y].max())
- canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].min() - 1,
- area_old[X].min() + 1, area_old[Y].max() + 1);
-
- if (area[Y].min() != area[Y].max())
- canvas->requestRedraw(area[X].min() - 1, area[Y].min() - 1,
- area[X].min() + 1, area[Y].max() + 1);
- } else { // same level, redraw only the ends
- if (area[Y].min() != area_old[Y].min()) {
- canvas->requestRedraw(area[X].min() - 1, MIN(area_old[Y].min(),area[Y].min()) - 1,
- area[X].min() + 1, MAX(area_old[Y].min(),area[Y].min()) + 1);
- }
- if (area[Y].max() != area_old[Y].max()) {
- canvas->requestRedraw(area[X].min() - 1, MIN(area_old[Y].max(),area[Y].max()) - 1,
- area[X].min() + 1, MAX(area_old[Y].max(),area[Y].max()) + 1);
- }
- }
-
- /* Right */
- if (area[X].max() != area_old[X].max() || _shadow_size_old != _shadow_size) {
- if (area_old[Y].min() != area_old[Y].max())
- canvas->requestRedraw(area_old[X].max() - 1, area_old[Y].min() - 1,
- area_old[X].max() + _shadow_size + 1, area_old[Y].max() + _shadow_size + 1);
-
- if (area[Y].min() != area[Y].max())
- canvas->requestRedraw(area[X].max() - 1, area[Y].min() - 1,
- area[X].max() + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- } else { // same level, redraw only the ends
- if (area[Y].min() != area_old[Y].min()) {
- canvas->requestRedraw(area[X].max() - 1, MIN(area_old[Y].min(),area[Y].min()) - 1,
- area[X].max() + _shadow_size + 1, MAX(area_old[Y].min(),area[Y].min()) + _shadow_size + 1);
- }
- if (area[Y].max() != area_old[Y].max()) {
- canvas->requestRedraw(area[X].max() - 1, MIN(area_old[Y].max(),area[Y].max()) - 1,
- area[X].max() + _shadow_size + 1, MAX(area_old[Y].max(),area[Y].max()) + _shadow_size + 1);
- }
- }
+ // Generate an integer rectangle that includes bbox.
+ Geom::OptIntRect _area_old = _area;
+ _area = bbox.roundOutwards();
- /* Bottom */
- if (area[Y].max() != area_old[Y].max() || _shadow_size_old != _shadow_size) {
- if (area_old[X].min() != area_old[X].max())
- canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].max() - 1,
- area_old[X].max() + _shadow_size + 1, area_old[Y].max() + _shadow_size + 1);
-
- if (area[X].min() != area[X].max())
- canvas->requestRedraw(area[X].min() - 1, area[Y].max() - 1,
- area[X].max() + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- } else { // same level, redraw only the ends
- if (area[X].min() != area_old[X].min()) {
- canvas->requestRedraw(MIN(area_old[X].min(),area[X].min()) - 1, area[Y].max() - 1,
- MAX(area_old[X].min(),area[X].min()) + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- }
- if (area[X].max() != area_old[X].max()) {
- canvas->requestRedraw(MIN(area_old[X].max(),area[X].max()) - 1, area[Y].max() - 1,
- MAX(area_old[X].max(),area[X].max()) + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- }
- }
- }
+ // std::cout << " _rect: " << _rect << std::endl;
+ // std::cout << " bbox: " << bbox << std::endl;
+ // std::cout << " area: " << *_area << std::endl;
- // update SPCanvasItem box
if (_area) {
- x1 = area[X].min() - 1;
- y1 = area[Y].min() - 1;
- x2 = area[X].max() + _shadow_size + 1;
- y2 = area[Y].max() + _shadow_size + 1;
+ Geom::IntRect area = *_area;
+ sp_canvas_update_bbox( this, area[X].min(), area[Y].min(), area[X].max(), area[Y].max() );
+ } else {
+ std::cerr << "CtrlRect::update: No area!!" << std::endl;
}
+
+ // At rendering stage, we need to know affine:
+ _affine = affine;
}
@@ -289,7 +267,7 @@ void CtrlRect::setColor(guint32 b, bool h, guint f)
void CtrlRect::setShadow(int s, guint c)
{
- _shadow = s;
+ _shadow_width = s;
_shadow_color = c;
_requestUpdate();
}
diff --git a/src/display/sodipodi-ctrlrect.h b/src/display/sodipodi-ctrlrect.h
index 08a085649..02fc85647 100644
--- a/src/display/sodipodi-ctrlrect.h
+++ b/src/display/sodipodi-ctrlrect.h
@@ -4,14 +4,17 @@
/**
* @file
* Simple non-transformed rectangle, usable for rubberband.
+ * Modified to work with rotated canvas.
*/
/*
* Authors:
* Lauris Kaplinski <lauris@ximian.com>
* Carl Hetherington <inkscape@carlh.net>
+ * Tavmjong Bah <tavjong@free.fr>
*
* Copyright (C) 1999-2001 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
+ * Copyright (C) 2017 Tavmjong Bah
*
* Released under GNU GPL
*
@@ -21,6 +24,7 @@
#include "sp-canvas-item.h"
#include <2geom/rect.h>
#include <2geom/int-rect.h>
+#include <2geom/transforms.h>
struct SPCanvasBuf;
@@ -48,23 +52,24 @@ private:
void _requestUpdate();
Geom::Rect _rect;
+ Geom::Affine _affine;
+
bool _has_fill;
bool _dashed;
bool _checkerboard;
Geom::OptIntRect _area;
- gint _shadow_size;
+ gint _shadow_width;
guint32 _border_color;
guint32 _fill_color;
guint32 _shadow_color;
- int _shadow;
};
struct CtrlRectClass : public SPCanvasItemClass {};
GType sp_ctrlrect_get_type();
-#endif // SEEN_RUBBERBAND_H
+#endif // SEEN_CTRLRECT_H
/*
Local Variables:
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 7d76fa043..d04c81ecb 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -21,25 +21,30 @@
# include <config.h>
#endif
+#include <gdkmm/devicemanager.h>
+#include <gdkmm/display.h>
#include <gdkmm/rectangle.h>
#include <cairomm/region.h>
#include "helper/sp-marshal.h"
#include <2geom/rect.h>
#include <2geom/affine.h>
-#include "display/cairo-utils.h"
#include "display/sp-canvas.h"
#include "display/sp-canvas-group.h"
+#include "display/rendermode.h"
+#include "display/cairo-utils.h"
#include "preferences.h"
#include "inkscape.h"
#include "sodipodi-ctrlrect.h"
#include "cms-system.h"
-#include "display/rendermode.h"
-#include "display/cairo-utils.h"
#include "debug/gdk-event-latency-tracker.h"
#include "desktop.h"
#include "color.h"
+#if GTK_CHECK_VERSION(3,20,0)
+# include <gdkmm/seat.h>
+#endif
+
using Inkscape::Debug::GdkEventLatencyTracker;
// gtk_check_version returns non-NULL on failure
@@ -61,6 +66,20 @@ struct SPCanvasGroupClass {
SPCanvasItemClass parent_class;
};
+static void ungrab_default_client_pointer(guint32 const time = GDK_CURRENT_TIME)
+{
+ auto const display = Gdk::Display::get_default();
+
+#if GTK_CHECK_VERSION(3,20,0)
+ auto const seat = display->get_default_seat();
+ seat->ungrab();
+#else
+ auto const dm = display->get_device_manager();
+ auto const device = dm->get_client_pointer();
+ device->ungrab(time);
+#endif
+}
+
/**
* A group of items.
*/
@@ -321,14 +340,7 @@ void sp_canvas_item_dispose(GObject *object)
if (item == item->canvas->_grabbed_item) {
item->canvas->_grabbed_item = NULL;
-
-#if GTK_CHECK_VERSION(3,0,0)
- GdkDeviceManager *dm = gdk_display_get_device_manager(gdk_display_get_default());
- GdkDevice *device = gdk_device_manager_get_client_pointer(dm);
- gdk_device_ungrab(device, GDK_CURRENT_TIME);
-#else
- gdk_pointer_ungrab (GDK_CURRENT_TIME);
-#endif
+ ungrab_default_client_pointer();
}
if (item == item->canvas->_focused_item) {
@@ -616,10 +628,22 @@ int sp_canvas_item_grab(SPCanvasItem *item, guint event_mask, GdkCursor *cursor,
// fixme: Top hack (Lauris)
// fixme: If we add key masks to event mask, Gdk will abort (Lauris)
- // fixme: But Canvas actualle does get key events, so all we need is routing these here
-#if GTK_CHECK_VERSION(3,0,0)
- GdkDeviceManager *dm = gdk_display_get_device_manager(gdk_display_get_default());
- GdkDevice *device = gdk_device_manager_get_client_pointer(dm);
+ // fixme: But Canvas actually does get key events, so all we need is routing these here
+ auto display = gdk_display_get_default();
+#if GTK_CHECK_VERSION(3,20,0)
+ auto seat = gdk_display_get_default_seat(display);
+ gdk_seat_grab(seat,
+ getWindow(item->canvas),
+ GDK_SEAT_CAPABILITY_ALL_POINTING,
+ FALSE,
+ cursor,
+ NULL,
+ NULL,
+ NULL);
+#else
+ auto dm = gdk_display_get_device_manager(display);
+ auto device = gdk_device_manager_get_client_pointer(dm);
+
gdk_device_grab(device,
getWindow(item->canvas),
GDK_OWNERSHIP_NONE,
@@ -627,10 +651,6 @@ int sp_canvas_item_grab(SPCanvasItem *item, guint event_mask, GdkCursor *cursor,
(GdkEventMask)(event_mask & (~(GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK))),
cursor,
etime);
-#else
- gdk_pointer_grab( getWindow(item->canvas), FALSE,
- (GdkEventMask)(event_mask & (~(GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK))),
- NULL, cursor, etime);
#endif
item->canvas->_grabbed_item = item;
@@ -657,14 +677,7 @@ void sp_canvas_item_ungrab(SPCanvasItem *item, guint32 etime)
}
item->canvas->_grabbed_item = NULL;
-
-#if GTK_CHECK_VERSION(3,0,0)
- GdkDeviceManager *dm = gdk_display_get_device_manager(gdk_display_get_default());
- GdkDevice *device = gdk_device_manager_get_client_pointer(dm);
- gdk_device_ungrab(device, etime);
-#else
- gdk_pointer_ungrab (etime);
-#endif
+ ungrab_default_client_pointer(etime);
}
/**
@@ -913,16 +926,9 @@ void sp_canvas_class_init(SPCanvasClass *klass)
widget_class->realize = SPCanvas::handle_realize;
widget_class->unrealize = SPCanvas::handle_unrealize;
-
-#if GTK_CHECK_VERSION(3,0,0)
widget_class->get_preferred_width = SPCanvas::handle_get_preferred_width;
widget_class->get_preferred_height = SPCanvas::handle_get_preferred_height;
widget_class->draw = SPCanvas::handle_draw;
-#else
- widget_class->size_request = SPCanvas::handle_size_request;
- widget_class->expose_event = SPCanvas::handle_expose;
-#endif
-
widget_class->size_allocate = SPCanvas::handle_size_allocate;
widget_class->button_press_event = SPCanvas::handle_button;
widget_class->button_release_event = SPCanvas::handle_button;
@@ -980,13 +986,7 @@ void SPCanvas::shutdownTransients()
if (_grabbed_item) {
_grabbed_item = NULL;
-#if GTK_CHECK_VERSION(3,0,0)
- GdkDeviceManager *dm = gdk_display_get_device_manager(gdk_display_get_default());
- GdkDevice *device = gdk_device_manager_get_client_pointer(dm);
- gdk_device_ungrab(device, GDK_CURRENT_TIME);
-#else
- gdk_pointer_ungrab(GDK_CURRENT_TIME);
-#endif
+ ungrab_default_client_pointer();
}
removeIdle();
}
@@ -1051,11 +1051,7 @@ void SPCanvas::handle_realize(GtkWidget *widget)
attributes.width = allocation.width;
attributes.height = allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.visual = gdk_visual_get_system();
-
-#if !GTK_CHECK_VERSION(3,0,0)
- attributes.colormap = gdk_colormap_get_system();
-#endif
+ attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default());
attributes.event_mask = (gtk_widget_get_events (widget) |
GDK_EXPOSURE_MASK |
@@ -1073,11 +1069,7 @@ void SPCanvas::handle_realize(GtkWidget *widget)
GDK_SCROLL_MASK |
GDK_FOCUS_CHANGE_MASK);
-#if GTK_CHECK_VERSION(3,0,0)
gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
-#else
- gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-#endif
GdkWindow *window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
gtk_widget_set_window (widget, window);
@@ -1086,18 +1078,8 @@ void SPCanvas::handle_realize(GtkWidget *widget)
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
if (prefs->getBool("/options/useextinput/value", true)) {
gtk_widget_set_events(widget, attributes.event_mask);
-#if !GTK_CHECK_VERSION(3,0,0)
- gtk_widget_set_extension_events(widget, GDK_EXTENSION_EVENTS_ALL);
- // TODO: Extension event stuff has been deprecated in GTK+ 3
-#endif
}
-#if !GTK_CHECK_VERSION(3,0,0)
- // This does nothing in GTK+ 3
- GtkStyle *style = gtk_widget_get_style (widget);
- gtk_widget_set_style (widget, gtk_style_attach (style, window));
-#endif
-
gtk_widget_set_realized (widget, TRUE);
}
@@ -1115,8 +1097,6 @@ void SPCanvas::handle_unrealize(GtkWidget *widget)
(* GTK_WIDGET_CLASS(sp_canvas_parent_class)->unrealize)(widget);
}
-
-#if GTK_CHECK_VERSION(3,0,0)
void SPCanvas::handle_get_preferred_width(GtkWidget *widget, gint *minimum_width, gint *natural_width)
{
static_cast<void>(SP_CANVAS (widget));
@@ -1130,16 +1110,6 @@ void SPCanvas::handle_get_preferred_height(GtkWidget *widget, gint *minimum_heig
*minimum_height = 256;
*natural_height = 256;
}
-#else
-void SPCanvas::handle_size_request(GtkWidget *widget, GtkRequisition *req)
-{
- static_cast<void>(SP_CANVAS (widget));
-
- req->width = 256;
- req->height = 256;
-}
-#endif
-
void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
{
@@ -1219,9 +1189,7 @@ int SPCanvas::emitEvent(GdkEvent *event)
break;
case GDK_SCROLL:
mask = GDK_SCROLL_MASK;
-#if GTK_CHECK_VERSION(3,0,0)
mask |= GDK_SMOOTH_SCROLL_MASK;
-#endif
break;
default:
mask = 0;
@@ -1503,13 +1471,9 @@ gint SPCanvas::handle_scroll(GtkWidget *widget, GdkEventScroll *event)
}
static inline void request_motions(GdkWindow *w, GdkEventMotion *event) {
-#if GTK_CHECK_VERSION(3,0,0)
gdk_window_get_device_position(w,
gdk_event_get_device((GdkEvent *)(event)),
NULL, NULL, NULL);
-#else
- gdk_window_get_pointer(w, NULL, NULL, NULL);
-#endif
gdk_event_request_motions(event);
}
@@ -1543,7 +1507,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
buf.buf = NULL;
buf.buf_rowstride = 0;
buf.rect = paint_rect;
- buf.visible_rect = canvas_rect;
+ buf.canvas_rect = canvas_rect;
buf.is_empty = true;
// create temporary surface
@@ -1607,7 +1571,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
}
struct PaintRectSetup {
- Geom::IntRect big_rect;
+ Geom::IntRect canvas_rect;
GTimeVal start_time;
int max_pixels;
Geom::Point mouse_loc;
@@ -1666,7 +1630,7 @@ int SPCanvas::paintRectInternal(PaintRectSetup const *setup, Geom::IntRect const
gdk_window_begin_paint_rect(window, &r);
*/
- paintSingleBuffer(this_rect, setup->big_rect, bw);
+ paintSingleBuffer(this_rect, setup->canvas_rect, bw);
//gdk_window_end_paint(window);
return 1;
}
@@ -1731,6 +1695,7 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
gtk_widget_get_allocation(GTK_WIDGET(this), &allocation);
+ // Find window rectangle in 'world coordinates'.
Geom::IntRect canvas_rect = Geom::IntRect::from_xywh(_x0, _y0,
allocation.width, allocation.height);
Geom::IntRect paint_rect(xx0, yy0, xx1, yy1);
@@ -1741,28 +1706,37 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
paint_rect = *area;
PaintRectSetup setup;
- setup.big_rect = paint_rect;
+ setup.canvas_rect = canvas_rect;
// Save the mouse location
gint x, y;
-#if GTK_CHECK_VERSION(3,0,0)
- GdkDeviceManager *dm = gdk_display_get_device_manager(gdk_display_get_default());
- GdkDevice *device = gdk_device_manager_get_client_pointer(dm);
+ auto const display = Gdk::Display::get_default();
- gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(this)),
- device,
- &x, &y, NULL);
+#if GTK_CHECK_VERSION(3,20,0)
+ auto const seat = display->get_default_seat();
+ auto const device = seat->get_pointer();
#else
- gdk_window_get_pointer(gtk_widget_get_window(GTK_WIDGET(this)), &x, &y, NULL);
+ auto const dm = display->get_device_manager();
+ auto const device = dm->get_client_pointer();
#endif
+ gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(this)),
+ device->gobj(),
+ &x, &y, NULL);
+
setup.mouse_loc = sp_canvas_window_to_world(this, Geom::Point(x,y));
+ static unsigned tile_multiplier = 0;
+ if (tile_multiplier == 0) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ tile_multiplier = prefs->getIntLimited("/options/rendering/tile-multiplier", 1, 1, 64);
+ }
+
if (_rendermode != Inkscape::RENDERMODE_OUTLINE) {
// use 256K as a compromise to not slow down gradients
// 256K is the cached buffer and we need 4 channels
- setup.max_pixels = 65536; // 256K/4
+ setup.max_pixels = 65536 * tile_multiplier; // 256K/4
} else {
// paths only, so 1M works faster
// 1M is the cached buffer and we need 4 channels
@@ -1818,21 +1792,6 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) {
return TRUE;
}
-#if !GTK_CHECK_VERSION(3,0,0)
-gboolean SPCanvas::handle_expose(GtkWidget *widget, GdkEventExpose *event)
-{
- cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));
-
- gdk_cairo_region (cr, event->region);
- cairo_clip (cr);
- gboolean result = SPCanvas::handle_draw(widget, cr);
-
- cairo_destroy (cr);
-
- return result;
-}
-#endif
-
gint SPCanvas::handle_key_event(GtkWidget *widget, GdkEventKey *event)
{
@@ -1965,10 +1924,16 @@ SPCanvasGroup *SPCanvas::getRoot()
return SP_CANVAS_GROUP(_root);
}
-void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling)
+/**
+ * Scroll screen to point 'c'. 'c' is measured in screen pixels.
+ */
+void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrolling)
{
GtkAllocation allocation;
+ double cx = c[Geom::X];
+ double cy = c[Geom::Y];
+
int ix = (int) round(cx); // ix and iy are the new canvas coordinates (integer screen pixels)
int iy = (int) round(cy); // cx might be negative, so (int)(cx + 0.5) will not do!
int dx = ix - _x0; // dx and dy specify the displacement (scroll) of the
@@ -1989,6 +1954,7 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll
cairo_translate(cr, -ix, -iy);
cairo_set_source(cr, _background);
cairo_paint(cr);
+
// Copy the old backing store contents
cairo_set_source_surface(cr, _backing_store, _x0, _y0);
cairo_rectangle(cr, _x0, _y0, allocation.width, allocation.height);
diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h
index 171fdaf67..a2cbe0b27 100644
--- a/src/display/sp-canvas.h
+++ b/src/display/sp-canvas.h
@@ -51,7 +51,7 @@ enum {
struct SPCanvasBuf {
cairo_t *ct;
Geom::IntRect rect;
- Geom::IntRect visible_rect;
+ Geom::IntRect canvas_rect; // visible window in world coordinates (i.e. offset by _x0, _y0)
unsigned char *buf;
int buf_rowstride;
@@ -70,8 +70,8 @@ GType sp_canvas_get_type() G_GNUC_CONST;
* Port of GnomeCanvas for inkscape needs.
*/
struct SPCanvas {
- /// Scrolls canvas to specific position (cx and cy are measured in screen pixels).
- void scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling = false);
+ /// Scrolls canvas to specific position (c is measured in screen pixels).
+ void scrollTo(Geom::Point const &c, unsigned int clear, bool is_scrolling = false);
/// Synchronously updates the canvas if necessary.
void updateNow();
@@ -145,12 +145,8 @@ public:
static void dispose(GObject *object);
static void handle_realize(GtkWidget *widget);
static void handle_unrealize(GtkWidget *widget);
-#if GTK_CHECK_VERSION(3,0,0)
static void handle_get_preferred_width(GtkWidget *widget, gint *min_w, gint *nat_w);
static void handle_get_preferred_height(GtkWidget *widget, gint *min_h, gint *nat_h);
-#else
- static void handle_size_request(GtkWidget *widget, GtkRequisition *req);
-#endif
static void handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
static gint handle_button(GtkWidget *widget, GdkEventButton *event);
@@ -162,9 +158,6 @@ public:
static gint handle_scroll(GtkWidget *widget, GdkEventScroll *event);
static gint handle_motion(GtkWidget *widget, GdkEventMotion *event);
static gboolean handle_draw(GtkWidget *widget, cairo_t *cr);
-#if !GTK_CHECK_VERSION(3,0,0)
- static gboolean handle_expose(GtkWidget *widget, GdkEventExpose *event);
-#endif
static gint handle_key_event(GtkWidget *widget, GdkEventKey *event);
static gint handle_crossing(GtkWidget *widget, GdkEventCrossing *event);
static gint handle_focus_in(GtkWidget *widget, GdkEventFocus *event);
@@ -181,8 +174,8 @@ public:
bool _is_dragging;
double _dx0;
double _dy0;
- int _x0; ///< World coordinate of the leftmost pixels
- int _y0; ///< World coordinate of the topmost pixels
+ int _x0; ///< World coordinate of the leftmost pixels of window
+ int _y0; ///< World coordinate of the topmost pixels of window
/// Image surface storing the contents of the widget
cairo_surface_t *_backing_store;
diff --git a/src/display/sp-ctrlcurve.cpp b/src/display/sp-ctrlcurve.cpp
index 2e0e8105b..79ef20d6c 100644
--- a/src/display/sp-ctrlcurve.cpp
+++ b/src/display/sp-ctrlcurve.cpp
@@ -47,6 +47,8 @@ sp_ctrlcurve_init(SPCtrlCurve *ctrlcurve)
// Points are initialized to 0,0
ctrlcurve->rgba = 0x0000ff7f;
ctrlcurve->item=NULL;
+ ctrlcurve->corner0 = -1;
+ ctrlcurve->corner1 = -1;
}
namespace {
diff --git a/src/display/sp-ctrlcurve.h b/src/display/sp-ctrlcurve.h
index 847944f38..56b3089d9 100644
--- a/src/display/sp-ctrlcurve.h
+++ b/src/display/sp-ctrlcurve.h
@@ -31,6 +31,9 @@ struct SPCtrlCurve : public SPCtrlLine {
Geom::Point const &q2, Geom::Point const &q3);
Geom::Point p0, p1, p2, p3;
+
+ int corner0; // Used to store index of corner for finding dragger.
+ int corner1;
};
GType sp_ctrlcurve_get_type();
diff --git a/src/display/sp-ctrlline.cpp b/src/display/sp-ctrlline.cpp
index 1bde540c0..c4ced2a33 100644
--- a/src/display/sp-ctrlline.cpp
+++ b/src/display/sp-ctrlline.cpp
@@ -52,6 +52,7 @@ static void sp_ctrlline_init(SPCtrlLine *ctrlline)
ctrlline->rgba = 0x0000ff7f;
ctrlline->s[Geom::X] = ctrlline->s[Geom::Y] = ctrlline->e[Geom::X] = ctrlline->e[Geom::Y] = 0.0;
ctrlline->item=NULL;
+ ctrlline->is_fill = true;
}
namespace {
@@ -84,7 +85,7 @@ void sp_ctrlline_render(SPCanvasItem *item, SPCanvasBuf *buf)
Geom::Point s = cl->s * cl->affine;
Geom::Point e = cl->e * cl->affine;
- ink_cairo_set_source_rgba32(buf->ct, 0xffffffbf);
+ ink_cairo_set_source_rgba32(buf->ct, 0xffffff7f);
cairo_set_line_width(buf->ct, 2);
cairo_new_path(buf->ct);
diff --git a/src/display/sp-ctrlline.h b/src/display/sp-ctrlline.h
index b2e222437..bac0cfa54 100644
--- a/src/display/sp-ctrlline.h
+++ b/src/display/sp-ctrlline.h
@@ -33,6 +33,8 @@ struct SPCtrlLine : public SPCanvasItem {
SPItem *item; // the item to which this line belongs in some sense; may be NULL for some users
+ bool is_fill; // fill or stroke... used with meshes.
+
guint32 rgba;
Geom::Point s;
Geom::Point e;