drawing-shape.cpp revision de843c4e0b086a164491232bcf99a51cb5f7dd68
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm/**
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * @file
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Shape (styled path) belonging to an SVG drawing.
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm *//*
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Authors:
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Krzysztof KosiƄski <tweenk.pl@gmail.com>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm *
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Copyright (C) 2011 Authors
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen * Released under GNU GPL, read the file 'COPYING' for more information
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen */
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include <glibmm.h>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include <2geom/curves.h>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include <2geom/pathvector.h>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include <2geom/path-sink.h>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include <2geom/svg-path-parser.h>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/cairo-utils.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/canvas-arena.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/canvas-bpath.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/curve.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/drawing.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/drawing-context.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/drawing-group.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/drawing-shape.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "helper/geom-curves.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "helper/geom.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "preferences.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "style.h"
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen#include "svg/svg.h"
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelennamespace Inkscape {
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmDrawingShape::DrawingShape(Drawing &drawing)
8c39cbeab9949a0a7d6ae66b768a7352019e42f8johanengelen : DrawingItem(drawing)
072916d0ef7dccd696b59381f50bcf776abccefbjohanengelen , _curve(NULL)
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud , _last_pick(NULL)
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud , _repick_after(0)
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud{}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmDrawingShape::~DrawingShape()
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (_curve)
8d9f5d586a04809427ce1df284a5720112177991cilix _curve->unref();
70eb1fc448cb08acf3468f80fa2296c03b32afd2cilix}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelenvoid
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelenDrawingShape::setPath(SPCurve *curve)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _markForRendering();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (_curve) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _curve->unref();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _curve = NULL;
072916d0ef7dccd696b59381f50bcf776abccefbjohanengelen }
8c39cbeab9949a0a7d6ae66b768a7352019e42f8johanengelen if (curve) {
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud _curve = curve;
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud curve->ref();
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _markForUpdate(STATE_ALL, false);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmvoid
8d9f5d586a04809427ce1df284a5720112177991cilixDrawingShape::setStyle(SPStyle *style)
8d9f5d586a04809427ce1df284a5720112177991cilix{
70eb1fc448cb08acf3468f80fa2296c03b32afd2cilix _nrstyle.set(style);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm DrawingItem::setStyle(style);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmunsigned
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmDrawingShape::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Geom::OptRect boundingbox;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
8c39cbeab9949a0a7d6ae66b768a7352019e42f8johanengelen unsigned beststate = STATE_ALL;
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // update markers
072916d0ef7dccd696b59381f50bcf776abccefbjohanengelen for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen i->update(area, ctx, flags, reset);
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen }
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen if (!(flags & STATE_RENDER)) {
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud /* We do not have to create rendering structures */
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud if (flags & STATE_BBOX) {
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen if (_curve) {
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud boundingbox = bounds_exact_transformed(_curve->get_pathvector(), ctx.ctm);
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud if (boundingbox) {
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen _bbox = boundingbox->roundOutwards();
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud } else {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _bbox = Geom::OptIntRect();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (beststate & STATE_BBOX) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen _bbox.unionWith(i->geometricBounds());
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen return (flags | _state);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen boundingbox = Geom::OptRect();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool outline = _drawing.outline();
8d9f5d586a04809427ce1df284a5720112177991cilix
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen // clear Cairo data to force update
8d9f5d586a04809427ce1df284a5720112177991cilix _nrstyle.update();
70eb1fc448cb08acf3468f80fa2296c03b32afd2cilix
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen if (_curve) {
70eb1fc448cb08acf3468f80fa2296c03b32afd2cilix boundingbox = bounds_exact_transformed(_curve->get_pathvector(), ctx.ctm);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (boundingbox && (_nrstyle.stroke.type != NRStyle::PAINT_NONE || outline)) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm float width, scale;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm scale = ctx.ctm.descrim();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm width = std::max(0.125f, _nrstyle.stroke_width * scale);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if ( fabs(_nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm boundingbox->expandBy(width);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // those pesky miters, now
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm float miterMax = width * _nrstyle.miter_limit;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if ( miterMax > 0.01 ) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // grunt mode. we should compute the various miters instead
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // (one for each point on the curve)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm boundingbox->expandBy(miterMax);
46c4893a7458eda6edcd064121bc000634af7a09johanengelen }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
a0334366488989ef25fb812d7030d298c0917c96johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _bbox = boundingbox ? boundingbox->roundOutwards() : Geom::OptIntRect();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (!_curve ||
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm !_style ||
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _curve->is_empty() ||
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm (( _nrstyle.fill.type != NRStyle::PAINT_NONE ) &&
eaa9bdc7bf7b73397e536edd47490d84e4420bd8bryce ( _nrstyle.stroke.type != NRStyle::PAINT_NONE && !outline) ))
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return STATE_ALL;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (beststate & STATE_BBOX) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _bbox.unionWith(i->geometricBounds());
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk }
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk return STATE_ALL;
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk}
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgkvoid
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgkDrawingShape::_renderFill(DrawingContext &dc)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Inkscape::DrawingContext::Save save(dc);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dc.transform(_ctm);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool has_fill = _nrstyle.prepareFill(dc, _item_bbox, _fill_pattern);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
5675f17bbbc00f2c970b4d4966ce55d86775f7a6johanengelen if( has_fill ) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dc.path(_curve->get_pathvector());
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _nrstyle.applyFill(dc);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dc.fillPreserve();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dc.newPath(); // clear path
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmvoid
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmDrawingShape::_renderStroke(DrawingContext &dc)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
5675f17bbbc00f2c970b4d4966ce55d86775f7a6johanengelen Inkscape::DrawingContext::Save save(dc);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dc.transform(_ctm);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool has_stroke = _nrstyle.prepareStroke(dc, _item_bbox, _stroke_pattern);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm has_stroke &= (_nrstyle.stroke_width != 0);
5675f17bbbc00f2c970b4d4966ce55d86775f7a6johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if( has_stroke ) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // TODO: remove segments outside of bbox when no dashes present
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dc.path(_curve->get_pathvector());
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _nrstyle.applyStroke(dc);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dc.strokePreserve();
ab5f33e91458710ed8dd2b2a1b3a53e4227d4856johanengelen dc.newPath(); // clear path
feb44ad276e996ca244e071f936c61b009bd73f4johanengelen }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
feb44ad276e996ca244e071f936c61b009bd73f4johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmvoid
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmDrawingShape::_renderMarkers(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // marker rendering
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm i->render(dc, area, flags, stop_at);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmunsigned
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmDrawingShape::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (!_curve || !_style) return RENDER_OK;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (!area.intersects(_bbox)) return RENDER_OK; // skip if not within bounding box
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool outline = _drawing.outline();
5675f17bbbc00f2c970b4d4966ce55d86775f7a6johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (outline) {
46c4893a7458eda6edcd064121bc000634af7a09johanengelen guint32 rgba = _drawing.outlinecolor;
46c4893a7458eda6edcd064121bc000634af7a09johanengelen
46c4893a7458eda6edcd064121bc000634af7a09johanengelen // paint-order doesn't matter
46c4893a7458eda6edcd064121bc000634af7a09johanengelen { Inkscape::DrawingContext::Save save(dc);
46c4893a7458eda6edcd064121bc000634af7a09johanengelen dc.transform(_ctm);
46c4893a7458eda6edcd064121bc000634af7a09johanengelen dc.path(_curve->get_pathvector());
46c4893a7458eda6edcd064121bc000634af7a09johanengelen }
46c4893a7458eda6edcd064121bc000634af7a09johanengelen { Inkscape::DrawingContext::Save save(dc);
46c4893a7458eda6edcd064121bc000634af7a09johanengelen dc.setSource(rgba);
46c4893a7458eda6edcd064121bc000634af7a09johanengelen dc.setLineWidth(0.5);
46c4893a7458eda6edcd064121bc000634af7a09johanengelen dc.setTolerance(0.5);
46c4893a7458eda6edcd064121bc000634af7a09johanengelen dc.stroke();
46c4893a7458eda6edcd064121bc000634af7a09johanengelen }
46c4893a7458eda6edcd064121bc000634af7a09johanengelen
46c4893a7458eda6edcd064121bc000634af7a09johanengelen _renderMarkers(dc, area, flags, stop_at);
46c4893a7458eda6edcd064121bc000634af7a09johanengelen return RENDER_OK;
46c4893a7458eda6edcd064121bc000634af7a09johanengelen
46c4893a7458eda6edcd064121bc000634af7a09johanengelen }
46c4893a7458eda6edcd064121bc000634af7a09johanengelen
46c4893a7458eda6edcd064121bc000634af7a09johanengelen if( _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_NORMAL ) {
46c4893a7458eda6edcd064121bc000634af7a09johanengelen // This is the most common case, special case so we don't call get_pathvector(), etc. twice
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // we assume the context has no path
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Inkscape::DrawingContext::Save save(dc);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dc.transform(_ctm);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
5675f17bbbc00f2c970b4d4966ce55d86775f7a6johanengelen // update fill and stroke paints.
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // this cannot be done during nr_arena_shape_update, because we need a Cairo context
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // to render svg:pattern
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool has_fill = _nrstyle.prepareFill(dc, _item_bbox, _fill_pattern);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool has_stroke = _nrstyle.prepareStroke(dc, _item_bbox, _stroke_pattern);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm has_stroke &= (_nrstyle.stroke_width != 0);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (has_fill || has_stroke) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // TODO: remove segments outside of bbox when no dashes present
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen dc.path(_curve->get_pathvector());
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen if (has_fill) {
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen _nrstyle.applyFill(dc);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen dc.fillPreserve();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen if (has_stroke) {
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen _nrstyle.applyStroke(dc);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen dc.strokePreserve();
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen }
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen dc.newPath(); // clear path
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen } // has fill or stroke pattern
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen }
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen _renderMarkers(dc, area, flags, stop_at);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return RENDER_OK;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // Handle different paint orders
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm for (unsigned i = 0; i < NRStyle::PAINT_ORDER_LAYERS; ++i) {
0fc5ce7045233dae7e15fdc86774370f1b1d73cbjohanengelen switch (_nrstyle.paint_order_layer[i]) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case NRStyle::PAINT_ORDER_FILL:
0fc5ce7045233dae7e15fdc86774370f1b1d73cbjohanengelen _renderFill(dc);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm break;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen case NRStyle::PAINT_ORDER_STROKE:
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen _renderStroke(dc);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm break;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen case NRStyle::PAINT_ORDER_MARKER:
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _renderMarkers(dc, area, flags, stop_at);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm break;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm default:
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // PAINT_ORDER_AUTO Should not happen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm break;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return RENDER_OK;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmvoid DrawingShape::_clipItem(DrawingContext &dc, Geom::IntRect const & /*area*/)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (!_curve) return;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Inkscape::DrawingContext::Save save(dc);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // handle clip-rule
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen if (_style) {
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen if (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) {
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen dc.setFillRule(CAIRO_FILL_RULE_EVEN_ODD);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm } else {
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen dc.setFillRule(CAIRO_FILL_RULE_WINDING);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen }
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen dc.transform(_ctm);
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen dc.path(_curve->get_pathvector());
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen dc.fill();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelenDrawingItem *
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelenDrawingShape::_pickItem(Geom::Point const &p, double delta, unsigned flags)
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen{
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen if (_repick_after > 0)
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen --_repick_after;
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen if (_repick_after > 0) // we are a slow, huge path
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen return _last_pick; // skip this pick, returning what was returned last time
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (!_curve) return NULL;
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen if (!_style) return NULL;
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool outline = _drawing.outline();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool pick_as_clip = flags & PICK_AS_CLIP;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (SP_SCALE24_TO_FLOAT(_style->opacity.value) == 0 && !outline && !pick_as_clip)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // fully transparent, no pick unless outline mode
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return NULL;
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm GTimeVal tstart, tfinish;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm g_get_current_time (&tstart);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm double width;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (pick_as_clip) {
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen width = 0; // no width should be applied to clip picking
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // this overrides display mode and stroke style considerations
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm } else if (outline) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm width = 0.5; // in outline mode, everything is stroked with the same 0.5px line width
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm } else if (_nrstyle.stroke.type != NRStyle::PAINT_NONE && _nrstyle.stroke.opacity > 1e-3) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // for normal picking calculate the distance corresponding top the stroke width
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // FIXME BUG: this is incorrect for transformed strokes
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen float const scale = _ctm.descrim();
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen width = std::max(0.125f, _nrstyle.stroke_width * scale) / 2;
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen } else {
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen width = 0;
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen }
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen double dist = Geom::infinity();
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen int wind = 0;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen bool needfill = pick_as_clip || (_nrstyle.fill.type != NRStyle::PAINT_NONE &&
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen _nrstyle.fill.opacity > 1e-3 && !outline);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen bool wind_evenodd = pick_as_clip ? (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) :
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen (_style->fill_rule.computed == SP_WIND_RULE_EVENODD);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen // actual shape picking
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen if (_drawing.arena()) {
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen Geom::Rect viewbox = _drawing.arena()->item.canvas->getViewbox();
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen viewbox.expandBy (width);
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen pathv_matrix_point_bbox_wind_distance(_curve->get_pathvector(), _ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, &viewbox);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen } else {
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen pathv_matrix_point_bbox_wind_distance(_curve->get_pathvector(), _ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, NULL);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen
f9504c822b72a774b910958446fd1e730235b7cbjoncruz g_get_current_time (&tfinish);
a0334366488989ef25fb812d7030d298c0917c96johanengelen glong this_pick = (tfinish.tv_sec - tstart.tv_sec) * 1000000 + (tfinish.tv_usec - tstart.tv_usec);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen //g_print ("pick time %lu\n", this_pick);
a0334366488989ef25fb812d7030d298c0917c96johanengelen
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen if (this_pick > 10000) { // slow picking, remember to skip several new picks
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen _repick_after = this_pick / 5000;
a0334366488989ef25fb812d7030d298c0917c96johanengelen }
a0334366488989ef25fb812d7030d298c0917c96johanengelen
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen // covered by fill?
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen if (needfill) {
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen if (wind_evenodd) {
f9504c822b72a774b910958446fd1e730235b7cbjoncruz if (wind & 0x1) {
a0334366488989ef25fb812d7030d298c0917c96johanengelen _last_pick = this;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen return this;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen } else {
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen if (wind != 0) {
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen _last_pick = this;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen return this;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen // close to the edge, as defined by strokewidth and delta?
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen // this ignores dashing (as if the stroke is solid) and always works as if caps are round
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen if (needfill || width > 0) { // if either fill or stroke visible,
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen if ((dist - width) < delta) {
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen _last_pick = this;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen return this;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen // if not picked on the shape itself, try its markers
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen DrawingItem *ret = i->pick(p, delta, flags & ~PICK_STICKY);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen if (ret) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _last_pick = this;
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen return this;
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen }
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen }
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen _last_pick = NULL;
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen return NULL;
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen}
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelenbool
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelenDrawingShape::_canClip()
a797dcb8e284cab19f60b3eff93a53a62abda263johanengelen{
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen return true;
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen}
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen} // end namespace Inkscape
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen/*
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen Local Variables:
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen mode:c++
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen c-file-style:"stroustrup"
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen indent-tabs-mode:nil
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen fill-column:99
bdd7add6c064afee52d2eabeaa18f745430e5a4djohanengelen End:
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen*/
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen