KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_gal_xor_mode.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
31
32#include <boost/test/unit_test.hpp>
33
34#include <gal/color4d.h>
35#include <cairo.h>
36#include <cmath>
37
38using namespace KIGFX;
39
40
41BOOST_AUTO_TEST_SUITE( GalXorMode )
42
43
44
47static COLOR4D getPixelColor( cairo_surface_t* surface, int x, int y )
48{
49 cairo_surface_flush( surface );
50
51 int stride = cairo_image_surface_get_stride( surface );
52 unsigned char* data = cairo_image_surface_get_data( surface );
53
54 unsigned char* pixel = data + y * stride + x * 4;
55
56 // Cairo ARGB32 format: B, G, R, A (little endian)
57 double b = pixel[0] / 255.0;
58 double g = pixel[1] / 255.0;
59 double r = pixel[2] / 255.0;
60 double a = pixel[3] / 255.0;
61
62 return COLOR4D( r, g, b, a );
63}
64
65
69static bool colorsApproxEqual( const COLOR4D& a, const COLOR4D& b, double tolerance = 0.02 )
70{
71 return std::abs( a.r - b.r ) < tolerance &&
72 std::abs( a.g - b.g ) < tolerance &&
73 std::abs( a.b - b.b ) < tolerance;
74}
75
76
81BOOST_AUTO_TEST_CASE( CairoDifferenceIdenticalColors )
82{
83 const int width = 100;
84 const int height = 100;
85
86 // Create destination surface (red background)
87 cairo_surface_t* destSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
88 cairo_t* destCtx = cairo_create( destSurface );
89
90 // Fill with solid red
91 cairo_set_source_rgba( destCtx, 1.0, 0.0, 0.0, 1.0 );
92 cairo_paint( destCtx );
93
94 // Create source surface (also red)
95 cairo_surface_t* srcSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
96 cairo_t* srcCtx = cairo_create( srcSurface );
97
98 // Fill with solid red (same as destination)
99 cairo_set_source_rgba( srcCtx, 1.0, 0.0, 0.0, 1.0 );
100 cairo_paint( srcCtx );
101
102 // Apply CAIRO_OPERATOR_DIFFERENCE: |src - dst| = |red - red| = black
103 cairo_set_operator( destCtx, CAIRO_OPERATOR_DIFFERENCE );
104 cairo_set_source_surface( destCtx, srcSurface, 0, 0 );
105 cairo_paint( destCtx );
106
107 // Check that the center pixel is black (identical colors cancel out)
108 COLOR4D result = getPixelColor( destSurface, 50, 50 );
109 COLOR4D expected( 0.0, 0.0, 0.0, 1.0 );
110
111 BOOST_CHECK_MESSAGE( colorsApproxEqual( result, expected ),
112 "Identical colors should cancel to black. Got: ("
113 << result.r << ", " << result.g << ", " << result.b << ")" );
114
115 // Cleanup
116 cairo_destroy( srcCtx );
117 cairo_surface_destroy( srcSurface );
118 cairo_destroy( destCtx );
119 cairo_surface_destroy( destSurface );
120}
121
122
126BOOST_AUTO_TEST_CASE( CairoDifferenceDifferentColors )
127{
128 const int width = 100;
129 const int height = 100;
130
131 // Create destination surface (red)
132 cairo_surface_t* destSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
133 cairo_t* destCtx = cairo_create( destSurface );
134
135 cairo_set_source_rgba( destCtx, 1.0, 0.0, 0.0, 1.0 ); // Red
136 cairo_paint( destCtx );
137
138 // Create source surface (green)
139 cairo_surface_t* srcSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
140 cairo_t* srcCtx = cairo_create( srcSurface );
141
142 cairo_set_source_rgba( srcCtx, 0.0, 1.0, 0.0, 1.0 ); // Green
143 cairo_paint( srcCtx );
144
145 // Apply CAIRO_OPERATOR_DIFFERENCE: |green - red| = (|0-1|, |1-0|, 0) = (1, 1, 0) = yellow
146 cairo_set_operator( destCtx, CAIRO_OPERATOR_DIFFERENCE );
147 cairo_set_source_surface( destCtx, srcSurface, 0, 0 );
148 cairo_paint( destCtx );
149
150 // Check that the result is yellow (difference of red and green)
151 COLOR4D result = getPixelColor( destSurface, 50, 50 );
152 COLOR4D expected( 1.0, 1.0, 0.0, 1.0 ); // Yellow
153
154 BOOST_CHECK_MESSAGE( colorsApproxEqual( result, expected ),
155 "Red - Green difference should be yellow. Got: ("
156 << result.r << ", " << result.g << ", " << result.b << ")" );
157
158 // Cleanup
159 cairo_destroy( srcCtx );
160 cairo_surface_destroy( srcSurface );
161 cairo_destroy( destCtx );
162 cairo_surface_destroy( destSurface );
163}
164
165
169BOOST_AUTO_TEST_CASE( CairoDifferenceNonOverlapping )
170{
171 const int width = 100;
172 const int height = 100;
173
174 // Create destination surface (transparent/black)
175 cairo_surface_t* destSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
176 cairo_t* destCtx = cairo_create( destSurface );
177
178 // Clear to black (no content)
179 cairo_set_source_rgba( destCtx, 0.0, 0.0, 0.0, 1.0 );
180 cairo_paint( destCtx );
181
182 // Create source surface (blue)
183 cairo_surface_t* srcSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
184 cairo_t* srcCtx = cairo_create( srcSurface );
185
186 cairo_set_source_rgba( srcCtx, 0.0, 0.0, 1.0, 1.0 ); // Blue
187 cairo_paint( srcCtx );
188
189 // Apply CAIRO_OPERATOR_DIFFERENCE: |blue - black| = blue
190 cairo_set_operator( destCtx, CAIRO_OPERATOR_DIFFERENCE );
191 cairo_set_source_surface( destCtx, srcSurface, 0, 0 );
192 cairo_paint( destCtx );
193
194 // Check that the result is blue (source on empty shows source)
195 COLOR4D result = getPixelColor( destSurface, 50, 50 );
196 COLOR4D expected( 0.0, 0.0, 1.0, 1.0 ); // Blue
197
198 BOOST_CHECK_MESSAGE( colorsApproxEqual( result, expected ),
199 "Blue on black should show blue. Got: ("
200 << result.r << ", " << result.g << ", " << result.b << ")" );
201
202 // Cleanup
203 cairo_destroy( srcCtx );
204 cairo_surface_destroy( srcSurface );
205 cairo_destroy( destCtx );
206 cairo_surface_destroy( destSurface );
207}
208
209
213BOOST_AUTO_TEST_CASE( CairoDifferencePartialOverlap )
214{
215 const int width = 100;
216 const int height = 100;
217
218 // Create destination surface with a red rectangle on the left half
219 cairo_surface_t* destSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
220 cairo_t* destCtx = cairo_create( destSurface );
221
222 // Clear to black
223 cairo_set_source_rgba( destCtx, 0.0, 0.0, 0.0, 1.0 );
224 cairo_paint( destCtx );
225
226 // Draw red rectangle on left half
227 cairo_set_source_rgba( destCtx, 1.0, 0.0, 0.0, 1.0 );
228 cairo_rectangle( destCtx, 0, 0, 50, 100 );
229 cairo_fill( destCtx );
230
231 // Create source surface with a red rectangle on the right half (partially overlapping)
232 cairo_surface_t* srcSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
233 cairo_t* srcCtx = cairo_create( srcSurface );
234
235 // Clear to black
236 cairo_set_source_rgba( srcCtx, 0.0, 0.0, 0.0, 1.0 );
237 cairo_paint( srcCtx );
238
239 // Draw red rectangle on right half (overlaps with left at x=25-50)
240 cairo_set_source_rgba( srcCtx, 1.0, 0.0, 0.0, 1.0 );
241 cairo_rectangle( srcCtx, 25, 0, 50, 100 );
242 cairo_fill( srcCtx );
243
244 // Apply CAIRO_OPERATOR_DIFFERENCE
245 cairo_set_operator( destCtx, CAIRO_OPERATOR_DIFFERENCE );
246 cairo_set_source_surface( destCtx, srcSurface, 0, 0 );
247 cairo_paint( destCtx );
248
249 // Check three regions:
250 // 1. Left-only (x=10): dest=red, src=black → |red-black| = red
251 // 2. Overlap (x=37): dest=red, src=red → |red-red| = black
252 // 3. Right-only (x=65): dest=black, src=red → |red-black| = red
253
254 COLOR4D leftOnly = getPixelColor( destSurface, 10, 50 );
255 COLOR4D overlap = getPixelColor( destSurface, 37, 50 );
256 COLOR4D rightOnly = getPixelColor( destSurface, 65, 50 );
257
258 COLOR4D expectedRed( 1.0, 0.0, 0.0, 1.0 );
259 COLOR4D expectedBlack( 0.0, 0.0, 0.0, 1.0 );
260
261 BOOST_CHECK_MESSAGE( colorsApproxEqual( leftOnly, expectedRed ),
262 "Left-only region should be red. Got: ("
263 << leftOnly.r << ", " << leftOnly.g << ", " << leftOnly.b << ")" );
264
265 BOOST_CHECK_MESSAGE( colorsApproxEqual( overlap, expectedBlack ),
266 "Overlap region should be black (canceled). Got: ("
267 << overlap.r << ", " << overlap.g << ", " << overlap.b << ")" );
268
269 BOOST_CHECK_MESSAGE( colorsApproxEqual( rightOnly, expectedRed ),
270 "Right-only region should be red. Got: ("
271 << rightOnly.r << ", " << rightOnly.g << ", " << rightOnly.b << ")" );
272
273 // Cleanup
274 cairo_destroy( srcCtx );
275 cairo_surface_destroy( srcSurface );
276 cairo_destroy( destCtx );
277 cairo_surface_destroy( destSurface );
278}
279
280
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
double r
Red component.
Definition color4d.h:393
double g
Green component.
Definition color4d.h:394
double b
Blue component.
Definition color4d.h:395
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:33
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
static COLOR4D getPixelColor(cairo_surface_t *surface, int x, int y)
Helper to get a pixel color from a Cairo ARGB32 surface.
static bool colorsApproxEqual(const COLOR4D &a, const COLOR4D &b, double tolerance=0.02)
Helper to check if two colors are approximately equal.
BOOST_AUTO_TEST_CASE(CairoDifferenceIdenticalColors)
Test that CAIRO_OPERATOR_DIFFERENCE correctly computes |src - dst| for identical overlapping colors (...
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
wxString result
Test unit parsing edge cases and error handling.