Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
drawing-paintserver.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <utility>
5
6#include "cairo-utils.h"
7#include "colors/color.h"
8
9namespace Inkscape {
10
12
14 : color(std::move(color)) {}
15
17{
18 return ink_cairo_pattern_create(color, opacity);
19}
20
21void DrawingGradient::common_setup(cairo_pattern_t *pat, Geom::OptRect const &bbox, double opacity) const
22{
23 // set spread type
24 switch (spread) {
26 cairo_pattern_set_extend(pat, CAIRO_EXTEND_REFLECT);
27 break;
29 cairo_pattern_set_extend(pat, CAIRO_EXTEND_REPEAT);
30 break;
32 default:
33 cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD);
34 break;
35 }
36
37 // set pattern transform matrix
38 auto gs2user = transform;
40 auto bbox2user = Geom::Affine(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top());
41 gs2user *= bbox2user;
42 }
43 ink_cairo_pattern_set_matrix(pat, gs2user.inverse());
44}
45
47{
48 auto pat = cairo_pattern_create_linear(x1, y1, x2, y2);
49
50 common_setup(pat, bbox, opacity);
51
52 // add stops
53 for (auto &stop : stops) {
54 // multiply stop opacity by paint opacity
55 if (stop.color.has_value()) {
56 ink_cairo_pattern_add_color_stop(pat, stop.offset, *stop.color, opacity);
57 }
58 }
59
60 return pat;
61}
62
64{
65 Geom::Point focus(fx, fy);
66 Geom::Point center(cx, cy);
67
68 double radius = r;
69 double focusr = fr;
70 double scale = 1.0;
71 double tolerance = cairo_get_tolerance(ct);
72
73 Geom::Affine gs2user = transform;
74
76 Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top());
77 gs2user *= bbox2user;
78 }
79
80 // we need to use vectors with the same direction to represent the transformed
81 // radius and the focus-center delta, because gs2user might contain non-uniform scaling
82 Geom::Point d(focus - center);
83 Geom::Point d_user(d.length(), 0);
84 Geom::Point r_user(radius, 0);
85 Geom::Point fr_user(focusr, 0);
86 d_user *= gs2user.withoutTranslation();
87 r_user *= gs2user.withoutTranslation();
88 fr_user *= gs2user.withoutTranslation();
89
90 double dx = d_user.x(), dy = d_user.y();
91 cairo_user_to_device_distance(ct, &dx, &dy);
92
93 // compute the tolerance distance in user space
94 // create a vector with the same direction as the transformed d,
95 // with the length equal to tolerance
96 double dl = hypot(dx, dy);
97 double tx = tolerance * dx / dl, ty = tolerance * dy / dl;
98 cairo_device_to_user_distance(ct, &tx, &ty);
99 double tolerance_user = hypot(tx, ty);
100
101 if (d_user.length() + tolerance_user > r_user.length()) {
102 scale = r_user.length() / d_user.length();
103
104 // nudge the focus slightly inside
105 scale *= 1.0 - 2.0 * tolerance / dl;
106 }
107
108 auto pat = cairo_pattern_create_radial(scale * d.x() + center.x(), scale * d.y() + center.y(), focusr, center.x(), center.y(), radius);
109
110 common_setup(pat, bbox, opacity);
111
112 // add stops
113 for (auto &stop : stops) {
114 // multiply stop opacity by paint opacity
115 if (stop.color.has_value()) {
116 ink_cairo_pattern_add_color_stop(pat, stop.offset, *stop.color, opacity);
117 }
118 }
119
120 return pat;
121}
122
124{
125#ifdef MESH_DEBUG
126 std::cout << "sp_meshgradient_create_pattern: " << bbox << " " << opacity << std::endl;
127#endif
128
129 auto pat = cairo_pattern_create_mesh();
130
131 for (int i = 0; i < rows; i++) {
132 for (int j = 0; j < cols; j++) {
133 auto &data = patchdata[i][j];
134
135 cairo_mesh_pattern_begin_patch(pat);
136 cairo_mesh_pattern_move_to(pat, data.points[0][0].x(), data.points[0][0].y());
137
138 for (int k = 0; k < 4; k++) {
139 switch (data.pathtype[k]) {
140 case 'l':
141 case 'L':
142 case 'z':
143 case 'Z':
144 cairo_mesh_pattern_line_to(pat, data.points[k][3].x(), data.points[k][3].y());
145 break;
146 case 'c':
147 case 'C':
148 cairo_mesh_pattern_curve_to(pat, data.points[k][1].x(), data.points[k][1].y(),
149 data.points[k][2].x(), data.points[k][2].y(),
150 data.points[k][3].x(), data.points[k][3].y());
151 break;
152 default:
153 // Shouldn't happen
154 std::cerr << "sp_mesh_create_pattern: path error" << std::endl;
155 }
156
157 if (data.tensorIsSet[k]) {
158 Geom::Point t = data.tensorpoints[k];
159 cairo_mesh_pattern_set_control_point(pat, k, t.x(), t.y());
160 }
161
162 cairo_mesh_pattern_set_corner_color_rgba(pat, k,
163 data.color[k][0],
164 data.color[k][1],
165 data.color[k][2],
166 data.opacity[k] * opacity);
167 }
168
169 cairo_mesh_pattern_end_patch(pat);
170 }
171 }
172
173 // set pattern transform matrix
174 Geom::Affine gs2user = transform;
176 Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top());
177 gs2user *= bbox2user;
178 }
180
181 return pat;
182}
183
184} // namespace Inkscape
185
186/*
187 Local Variables:
188 mode:c++
189 c-file-style:"stroustrup"
190 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
191 indent-tabs-mode:nil
192 fill-column:99
193 End:
194*/
195// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
double scale
Definition aa.cpp:228
void ink_cairo_pattern_add_color_stop(cairo_pattern_t *ptn, double offset, Inkscape::Colors::Color const &color, double opacity)
void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m)
cairo_pattern_t * ink_cairo_pattern_create(Inkscape::Colors::Color const &color, double opacity)
Cairo integration helpers.
3x3 matrix representing an affine transformation.
Definition affine.h:70
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
Affine withoutTranslation() const
Definition affine.h:169
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Two-dimensional point that doubles as a vector.
Definition point.h:66
Coord length() const
Compute the distance from origin.
Definition point.h:118
constexpr Coord y() const noexcept
Definition point.h:106
constexpr Coord x() const noexcept
Definition point.h:104
void common_setup(cairo_pattern_t *pat, Geom::OptRect const &bbox, double opacity) const
Perform some common initialization steps on the given Cairo pattern.
std::vector< SPGradientStop > stops
cairo_pattern_t * create_pattern(cairo_t *, Geom::OptRect const &bbox, double opacity) const override
Produce a pattern that can be used for painting with Cairo.
cairo_pattern_t * create_pattern(cairo_t *, Geom::OptRect const &bbox, double opacity) const override
Produce a pattern that can be used for painting with Cairo.
std::vector< std::vector< PatchData > > patchdata
cairo_pattern_t * create_pattern(cairo_t *ct, Geom::OptRect const &bbox, double opacity) const override
Produce a pattern that can be used for painting with Cairo.
std::vector< SPGradientStop > stops
DrawingSolidColor(Colors::Color color)
cairo_pattern_t * create_pattern(cairo_t *, Geom::OptRect const &, double opacity) const override
Produce a pattern that can be used for painting with Cairo.
Representation of paint servers used when rendering.
_cairo_pattern cairo_pattern_t
Helper class to stream background task notifications as a series of messages.
STL namespace.
struct _cairo cairo_t
Definition path-cairo.h:16
@ SP_GRADIENT_SPREAD_PAD
@ SP_GRADIENT_SPREAD_REPEAT
@ SP_GRADIENT_SPREAD_REFLECT
@ SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX
static const Point data[]