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