Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
nr-style.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
6 * Authors:
7 * Krzysztof KosiƄski <tweenk.pl@gmail.com>
8 *
9 * Copyright (C) 2010 Authors
10 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
11 */
12
13#include "display/nr-style.h"
14#include "style.h"
15
16#include "colors/manager.h"
17#include "display/cairo-utils.h"
21
23
24namespace Inkscape {
25
27{
28 server.reset();
30}
31
33{
34 clear();
35 type = PaintType::COLOR;
36 color = c;
37}
38
40{
41 clear();
42 if (ps) {
43 type = PaintType::SERVER;
44 server = ps->create_drawing_paintserver();
45 }
46}
47
49{
50 if (paint->isPaintserver()) {
51 SPPaintServer* server = paint->href->getObject();
52 if (server && server->isValid()) {
53 set(server);
54 } else if (paint->isColor()) {
55 set(paint->getColor());
56 } else {
57 clear();
58 }
59 } else if (paint->isColor()) {
60 set(paint->getColor());
61 } else if (paint->isNone()) {
62 clear();
63 } else if (paint->paintOrigin == SP_CSS_PAINT_ORIGIN_CONTEXT_FILL ||
65 // A marker in the defs section will result in ending up here.
66 // std::cerr << "NRStyleData::Paint::set: Double" << std::endl;
67 } else {
68 g_assert_not_reached();
69 }
70}
71
73 : fill()
74 , stroke()
75 , stroke_width(0.0)
76 , hairline(false)
77 , miter_limit(0.0)
78 , n_dash(0)
79 , dash_offset(0.0)
80 , fill_rule(CAIRO_FILL_RULE_EVEN_ODD)
81 , line_cap(CAIRO_LINE_CAP_BUTT)
82 , line_join(CAIRO_LINE_JOIN_MITER)
88 , phase_length(0.0)
89 , tspan_line_start(false)
90 , tspan_line_end(false)
91 , tspan_width(0)
92 , ascender(0)
93 , descender(0)
98 , font_size(0)
99{
101}
102
104{
105 return type == PaintType::SERVER && server && server->ditherable();
106}
107
108NRStyleData::NRStyleData(SPStyle const *style, SPStyle const *context_style)
109{
110 // Handle 'context-fill' and 'context-stroke': Work in progress
111 const SPIPaint *style_fill = &style->fill;
113 if (context_style) {
114 style_fill = &context_style->fill;
115 } else {
116 // A marker in the defs section will result in ending up here.
117 //std::cerr << "NRStyleData::set: 'context-fill': 'context_style' is NULL" << std::endl;
118 }
119 } else if (style_fill->paintOrigin == SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE) {
120 if (context_style) {
121 style_fill = &context_style->stroke;
122 } else {
123 //std::cerr << "NRStyleData::set: 'context-stroke': 'context_style' is NULL" << std::endl;
124 }
125 }
126
127 fill.set(style_fill);
128 fill.opacity = style->fill_opacity;
129
130 switch (style->fill_rule.computed) {
132 fill_rule = CAIRO_FILL_RULE_EVEN_ODD;
133 break;
135 fill_rule = CAIRO_FILL_RULE_WINDING;
136 break;
137 default:
138 g_assert_not_reached();
139 }
140
141 const SPIPaint *style_stroke = &style->stroke;
142 if (style_stroke->paintOrigin == SP_CSS_PAINT_ORIGIN_CONTEXT_FILL) {
143 if (context_style) {
144 style_stroke = &context_style->fill;
145 } else {
146 //std::cerr << "NRStyleData::set: 'context-fill': 'context_style' is NULL" << std::endl;
147 }
148 } else if (style_stroke->paintOrigin == SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE) {
149 if (context_style) {
150 style_stroke = &context_style->stroke;
151 } else {
152 //std::cerr << "NRStyleData::set: 'context-stroke': 'context_style' is NULL" << std::endl;
153 }
154 }
155
156 stroke.set(style_stroke);
157 stroke.opacity = SP_SCALE24_TO_FLOAT(style->stroke_opacity.value);
158 stroke_width = style->stroke_width.computed;
159 hairline = style->stroke_extensions.hairline;
160 switch (style->stroke_linecap.computed) {
162 line_cap = CAIRO_LINE_CAP_ROUND;
163 break;
165 line_cap = CAIRO_LINE_CAP_SQUARE;
166 break;
168 line_cap = CAIRO_LINE_CAP_BUTT;
169 break;
170 default:
171 g_assert_not_reached();
172 }
173 switch (style->stroke_linejoin.computed) {
175 line_join = CAIRO_LINE_JOIN_ROUND;
176 break;
178 line_join = CAIRO_LINE_JOIN_BEVEL;
179 break;
181 line_join = CAIRO_LINE_JOIN_MITER;
182 break;
183 default:
184 g_assert_not_reached();
185 }
186 miter_limit = style->stroke_miterlimit.value;
187
188 n_dash = style->stroke_dasharray.values.size();
189 if (n_dash > 0 && style->stroke_dasharray.is_valid()) {
190 dash_offset = style->stroke_dashoffset.computed;
191 dash.resize(n_dash);
192 for (int i = 0; i < n_dash; ++i) {
193 dash[i] = style->stroke_dasharray.values[i].computed;
194 }
195 } else {
196 dash_offset = 0.0;
197 dash.clear();
198 }
199
200 for (int i = 0; i < PAINT_ORDER_LAYERS; ++i) {
201 switch (style->paint_order.layer[i]) {
204 break;
207 break;
210 break;
213 break;
214 }
215 }
216
223
231
232 /* FIXME
233 The meaning of text-decoration-color in CSS3 for SVG is ambiguous (2014-05-06). Set
234 it for fill, for stroke, for both? Both would seem like the obvious choice but what happens
235 is that for text which is just fill (very common) it makes the lines fatter because it
236 enables stroke on the decorations when it wasn't present on the text. That contradicts the
237 usual behavior where the text and decorations by default have the same fill/stroke.
238
239 The behavior here is that if color is defined it is applied to text_decoration_fill/stroke
240 ONLY if the corresponding fill/stroke is also present.
241
242 Hopefully the standard will be clarified to resolve this issue.
243 */
244
245 // Unless explicitly set on an element, text decoration is inherited from
246 // closest ancestor where 'text-decoration' was set. That is, setting
247 // 'text-decoration' on an ancestor fixes the fill and stroke of the
248 // decoration to the fill and stroke values of that ancestor.
249 auto style_td = style;
250 if (style->text_decoration.style_td) style_td = style->text_decoration.style_td;
251 text_decoration_stroke.opacity = SP_SCALE24_TO_FLOAT(style_td->stroke_opacity.value);
252 text_decoration_stroke_width = style_td->stroke_width.computed;
253
254 // Priority is given in order:
255 // * text_decoration_fill
256 // * text_decoration_color (only if fill set)
257 // * fill
258 if (style_td->text_decoration_fill.set) {
259 text_decoration_fill.set(&(style_td->text_decoration_fill));
260 } else if (style_td->text_decoration_color.set) {
261 if(style->fill.isPaintserver() || style->fill.isColor()) {
262 // SVG sets color specifically
264 } else {
265 // No decoration fill because no text fill
267 }
268 } else {
269 // Pick color/pattern from text
270 text_decoration_fill.set(&style_td->fill);
271 }
272
273 if (style_td->text_decoration_stroke.set) {
274 text_decoration_stroke.set(&style_td->text_decoration_stroke);
275 } else if (style_td->text_decoration_color.set) {
276 if(style->stroke.isPaintserver() || style->stroke.isColor()) {
277 // SVG sets color specifically
279 } else {
280 // No decoration stroke because no text stroke
282 }
283 } else {
284 // Pick color/pattern from text
285 text_decoration_stroke.set(&style_td->stroke);
286 }
287
299 font_size = style->font_size.computed;
300 }
301
302 text_direction = style->direction.computed;
303}
304
306{
307 if (paint.type == NRStyleData::PaintType::SERVER && pattern) {
308 // If a DrawingPattern, then always regenerate the pattern, because it may depend on 'area'.
309 // Even if not, regenerating the pattern is a no-op because DrawingPattern has a cache.
310 return CairoPatternUniqPtr(pattern->renderPattern(rc, area, paint.opacity, dc.surface()->device_scale()));
311 }
312
313 // Otherwise, init or re-use cached pattern.
314 cp.inited.init([&] {
315 // Handle remaining non-DrawingPattern cases.
316 switch (paint.type) {
317 case NRStyleData::PaintType::SERVER:
318 if (paint.server) {
319 cp.pattern = CairoPatternUniqPtr(paint.server->create_pattern(dc.raw(), paintbox, paint.opacity));
320 ink_cairo_pattern_set_dither(cp.pattern.get(), rc.dithering && paint.server->ditherable());
321 } else {
322 std::cerr << "Null pattern detected" << std::endl;
323 cp.pattern = CairoPatternUniqPtr(cairo_pattern_create_rgba(0, 0, 0, 0));
324 }
325 break;
327 cp.pattern = CairoPatternUniqPtr(ink_cairo_pattern_create(paint.color->withOpacity(paint.opacity)));
328 break;
329 }
330 default:
331 cp.pattern.reset();
332 break;
333 }
334 });
335
336 return copy(cp.pattern);
337}
338
340{
341 data = std::move(data_);
342 invalidate();
343}
344
346{
347 return preparePaint(dc, rc, area, paintbox, pattern, data.fill, fill_pattern);
348}
349
351{
352 return preparePaint(dc, rc, area, paintbox, pattern, data.stroke, stroke_pattern);
353}
354
356{
357 return preparePaint(dc, rc, area, paintbox, pattern, data.text_decoration_fill, text_decoration_fill_pattern);
358}
359
361{
362 return preparePaint(dc, rc, area, paintbox, pattern, data.text_decoration_stroke, text_decoration_stroke_pattern);
363}
364
366{
367 dc.setSource(cp.get());
369}
370
372{
373 dc.setSource(cp.get());
374 // Fill rule does not matter, no intersections.
375}
376
378{
379 dc.setSource(cp.get());
380 if (data.hairline) {
381 dc.setHairline();
382 } else {
384 }
388 cairo_set_dash(dc.raw(), data.dash.empty() ? nullptr : data.dash.data(), data.dash.empty() ? 0 : data.n_dash, data.dash_offset); // fixme
389}
390
392{
393 dc.setSource(cp.get());
394 if (data.hairline) {
395 dc.setHairline();
396 } else {
398 }
399 dc.setLineCap(CAIRO_LINE_CAP_BUTT);
400 dc.setLineJoin(CAIRO_LINE_JOIN_MITER);
402 cairo_set_dash(dc.raw(), nullptr, 0, 0.0); // fixme (no dash)
403}
404
413
414} // namespace Inkscape
415
416/*
417 Local Variables:
418 mode:c++
419 c-file-style:"stroustrup"
420 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
421 indent-tabs-mode:nil
422 fill-column:99
423 End:
424*/
425// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
cairo_pattern_t * ink_cairo_pattern_create(Colors::Color const &color, bool to_srgb)
Cairo integration helpers.
Axis aligned, non-empty, generic rectangle.
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Minimal wrapper over Cairo.
void setLineCap(cairo_line_cap_t cap)
void setSource(cairo_pattern_t *source)
void setFillRule(cairo_fill_rule_t rule)
void setMiterLimit(double miter)
void setLineJoin(cairo_line_join_t join)
Drawing tree node used for rendering paints.
NRStyleData data
Definition nr-style.h:149
CachedPattern text_decoration_stroke_pattern
Definition nr-style.h:164
CachedPattern text_decoration_fill_pattern
Definition nr-style.h:163
void applyTextDecorationFill(DrawingContext &dc, CairoPatternUniqPtr const &cp) const
Definition nr-style.cpp:371
CachedPattern stroke_pattern
Definition nr-style.h:162
void applyStroke(DrawingContext &dc, CairoPatternUniqPtr const &cp) const
Definition nr-style.cpp:377
CairoPatternUniqPtr prepareFill(DrawingContext &dc, RenderContext &rc, Geom::IntRect const &area, Geom::OptRect const &paintbox, DrawingPattern const *pattern) const
Definition nr-style.cpp:345
CairoPatternUniqPtr prepareStroke(DrawingContext &dc, RenderContext &rc, Geom::IntRect const &area, Geom::OptRect const &paintbox, DrawingPattern const *pattern) const
Definition nr-style.cpp:350
CairoPatternUniqPtr preparePaint(DrawingContext &dc, RenderContext &rc, Geom::IntRect const &area, Geom::OptRect const &paintbox, DrawingPattern const *pattern, NRStyleData::Paint const &paint, CachedPattern const &cp) const
Definition nr-style.cpp:305
void applyTextDecorationStroke(DrawingContext &dc, CairoPatternUniqPtr const &cp) const
Definition nr-style.cpp:391
CairoPatternUniqPtr prepareTextDecorationFill(DrawingContext &dc, RenderContext &rc, Geom::IntRect const &area, Geom::OptRect const &paintbox, DrawingPattern const *pattern) const
Definition nr-style.cpp:355
CairoPatternUniqPtr prepareTextDecorationStroke(DrawingContext &dc, RenderContext &rc, Geom::IntRect const &area, Geom::OptRect const &paintbox, DrawingPattern const *pattern) const
Definition nr-style.cpp:360
CachedPattern fill_pattern
Definition nr-style.h:161
void applyFill(DrawingContext &dc, CairoPatternUniqPtr const &cp) const
Definition nr-style.cpp:365
void set(NRStyleData &&data)
Definition nr-style.cpp:339
Paint type internal to SPStyle.
bool isPaintserver() const
bool isColor() const
bool isNone() const
std::shared_ptr< SPPaintServerReference > href
SPPaintOrigin paintOrigin
Colors::Color const & getColor() const
virtual bool isValid() const
virtual std::unique_ptr< Inkscape::DrawingPaintServer > create_drawing_paintserver()
An SVG style object.
Definition style.h:45
T< SPAttr::TEXT_DECORATION_LINE, SPITextDecorationLine > text_decoration_line
CSS 3 2.1, 2.2, 2.3.
Definition style.h:191
T< SPAttr::TEXT_DECORATION_STYLE, SPITextDecorationStyle > text_decoration_style
Definition style.h:192
T< SPAttr::FILL, SPIPaint > fill
fill
Definition style.h:240
T< SPAttr::STROKE_DASHARRAY, SPIDashArray > stroke_dasharray
stroke-dasharray
Definition style.h:257
T< SPAttr::STROKE, SPIPaint > stroke
stroke
Definition style.h:247
SPITextDecorationData text_decoration_data
Definition style.h:197
T< SPAttr::PAINT_ORDER, SPIPaintOrder > paint_order
Definition style.h:222
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
Definition style.h:249
T< SPAttr::TEXT_DECORATION_COLOR, SPIColor > text_decoration_color
Definition style.h:193
T< SPAttr::TEXT_DECORATION, SPITextDecoration > text_decoration
text decoration (css2 16.3.1)
Definition style.h:188
T< SPAttr::DIRECTION, SPIEnum< SPCSSDirection > > direction
text direction (svg1.1)
Definition style.h:161
T< SPAttr::FILL_RULE, SPIEnum< SPWindRule > > fill_rule
fill-rule: 0 nonzero, 1 evenodd
Definition style.h:244
T< SPAttr::FILL_OPACITY, SPIScale24 > fill_opacity
fill-opacity
Definition style.h:242
T< SPAttr::STROKE_LINEJOIN, SPIEnum< SPStrokeJoinType > > stroke_linejoin
stroke-linejoin
Definition style.h:253
T< SPAttr::STROKE_OPACITY, SPIScale24 > stroke_opacity
stroke-opacity
Definition style.h:261
T< SPAttr::STROKE_MITERLIMIT, SPIFloat > stroke_miterlimit
stroke-miterlimit
Definition style.h:255
T< SPAttr::STROKE_LINECAP, SPIEnum< SPStrokeCapType > > stroke_linecap
stroke-linecap
Definition style.h:251
T< SPAttr::STROKE_DASHOFFSET, SPILength > stroke_dashoffset
stroke-dashoffset
Definition style.h:259
T< SPAttr::STROKE_EXTENSIONS, SPIStrokeExtensions > stroke_extensions
-inkscape-stroke
Definition style.h:263
T< SPAttr::FONT_SIZE, SPIFontSize > font_size
Size of the font.
Definition style.h:116
RectangularCluster rc
double c[8][4]
Cairo drawing context with Inkscape extensions.
Canvas belonging to SVG pattern.
Cairo surface that remembers its origin.
Helper class to stream background task notifications as a series of messages.
std::unique_ptr< cairo_pattern_t, CairoPatternFreer > CairoPatternUniqPtr
Definition nr-style.h:34
Style information for rendering.
static const Point data[]
void set(Colors::Color const &c)
Definition nr-style.cpp:32
std::unique_ptr< DrawingPaintServer > server
Definition nr-style.h:58
std::array< PaintOrderType, 3 > paint_order_layer
Definition nr-style.h:88
cairo_line_cap_t line_cap
Definition nr-style.h:77
cairo_fill_rule_t fill_rule
Definition nr-style.h:76
float text_decoration_stroke_width
Definition nr-style.h:117
std::vector< double > dash
Definition nr-style.h:74
cairo_line_join_t line_join
Definition nr-style.h:78
@ SP_WIND_RULE_EVENODD
Definition style-enums.h:26
@ SP_WIND_RULE_NONZERO
Definition style-enums.h:24
@ SP_STROKE_LINEJOIN_MITER
Definition style-enums.h:34
@ SP_STROKE_LINEJOIN_BEVEL
Definition style-enums.h:36
@ SP_STROKE_LINEJOIN_ROUND
Definition style-enums.h:35
@ SP_STROKE_LINECAP_SQUARE
Definition style-enums.h:43
@ SP_STROKE_LINECAP_ROUND
Definition style-enums.h:42
@ SP_STROKE_LINECAP_BUTT
Definition style-enums.h:41
constexpr size_t PAINT_ORDER_LAYERS
@ SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE
@ SP_CSS_PAINT_ORIGIN_CONTEXT_FILL
@ SP_CSS_PAINT_ORDER_STROKE
@ SP_CSS_PAINT_ORDER_MARKER
@ SP_CSS_PAINT_ORDER_FILL
@ SP_CSS_PAINT_ORDER_NORMAL
SPStyle - a style object for SPItem objects.