1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * feTile filter primitive renderer
4 *
5 * Authors:
6 * Felipe Corrêa da Silva Sanches <juca@members.fsf.org>
7 *
8 * Copyright (C) 2007 authors
9 *
10 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
11 */
12
13 #include <glib.h>
14
15 #include "display/cairo-utils.h"
16 #include "display/nr-filter-tile.h"
17 #include "display/nr-filter-slot.h"
18 #include "display/nr-filter-units.h"
19
20 namespace Inkscape {
21 namespace Filters {
22
23 FilterTile::FilterTile()
24 = default;
25
create()26 FilterPrimitive * FilterTile::create() {
27 return new FilterTile();
28 }
29
30 FilterTile::~FilterTile()
31 = default;
32
render_cairo(FilterSlot & slot)33 void FilterTile::render_cairo(FilterSlot &slot)
34 {
35 // This input source contains only the "rendering" tile.
36 cairo_surface_t *in = slot.getcairo(_input);
37
38 // For debugging
39 // static int i = 0;
40 // ++i;
41 // std::stringstream filename;
42 // filename << "dump." << i << ".png";
43 // cairo_surface_write_to_png( in, filename.str().c_str() );
44
45 // This is the feTile source area as determined by the input primitive area (see SVG spec).
46 Geom::Rect tile_area = slot.get_primitive_area(_input);
47
48 if( tile_area.width() == 0.0 || tile_area.height() == 0.0 ) {
49
50 slot.set(_output, in);
51 std::cerr << "FileTile::render_cairo: tile has zero width or height" << std::endl;
52
53 } else {
54
55 cairo_surface_t *out = ink_cairo_surface_create_identical(in);
56 // color_interpolation_filters for out same as in.
57 copy_cairo_surface_ci(in, out);
58 cairo_t *ct = cairo_create(out);
59
60 // The rectangle of the "rendering" tile.
61 Geom::Rect sa = slot.get_slot_area();
62
63 Geom::Affine trans = slot.get_units().get_matrix_user2pb();
64
65 // Create feTile tile ----------------
66
67 // Get tile area in pixbuf units (tile transformed).
68 Geom::Rect tt = tile_area * trans;
69
70 // Shift between "rendering" tile and feTile tile
71 Geom::Point shift = sa.min() - tt.min();
72
73 // Create feTile tile surface
74 cairo_surface_t *tile = cairo_surface_create_similar(in, cairo_surface_get_content(in),
75 tt.width(), tt.height());
76 cairo_t *ct_tile = cairo_create(tile);
77 cairo_set_source_surface(ct_tile, in, shift[Geom::X], shift[Geom::Y]);
78 cairo_paint(ct_tile);
79
80 // Paint tiles ------------------
81
82 // For debugging
83 // std::stringstream filename;
84 // filename << "tile." << i << ".png";
85 // cairo_surface_write_to_png( tile, filename.str().c_str() );
86
87 // Determine number of feTile rows and columns
88 Geom::Rect pr = filter_primitive_area( slot.get_units() );
89 int tile_cols = ceil( pr.width() / tile_area.width() );
90 int tile_rows = ceil( pr.height() / tile_area.height() );
91
92 // Do tiling (TO DO: restrict to slot area.)
93 for( int col=0; col < tile_cols; ++col ) {
94 for( int row=0; row < tile_rows; ++row ) {
95
96 Geom::Point offset( col*tile_area.width(), row*tile_area.height() );
97 offset *= trans;
98 offset[Geom::X] -= trans[4];
99 offset[Geom::Y] -= trans[5];
100
101 cairo_set_source_surface(ct, tile, offset[Geom::X], offset[Geom::Y]);
102 cairo_paint(ct);
103 }
104 }
105 slot.set(_output, out);
106
107 // Clean up
108 cairo_destroy(ct);
109 cairo_surface_destroy(out);
110 cairo_destroy(ct_tile);
111 cairo_surface_destroy(tile);
112 }
113 }
114
area_enlarge(Geom::IntRect & area,Geom::Affine const & trans)115 void FilterTile::area_enlarge(Geom::IntRect &area, Geom::Affine const &trans)
116 {
117 // Set to very large rectangle so we get tile source. It will be clipped later.
118
119 // Note, setting to infinite using Geom::IntRect::infinite() causes overflow/underflow problems.
120 Geom::IntCoord max = std::numeric_limits<Geom::IntCoord>::max()/4;
121 area = Geom::IntRect(-max,-max,max,max);
122 }
123
complexity(Geom::Affine const &)124 double FilterTile::complexity(Geom::Affine const &)
125 {
126 return 1.0;
127 }
128
129 } /* namespace Filters */
130 } /* namespace Inkscape */
131
132 /*
133 Local Variables:
134 mode:c++
135 c-file-style:"stroustrup"
136 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
137 indent-tabs-mode:nil
138 fill-column:99
139 End:
140 */
141 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
142