Bug Summary

File:home/HaikuArchives/ArtPaint/addons/AddOns/Saturation/Saturation.cpp
Warning:line 246, column 3
Value stored to 'saturation' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-haiku -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name Saturation.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /boot/system/lib/clang/12.0.1 -iquote ./ -iquote ../../UtilityClasses/ -iquote ./ -iquote ../../../artpaint/application -iquote ../../../artpaint/controls -iquote ../../../artpaint/layers -iquote ../../../artpaint/paintwindow -iquote ../../../artpaint/tools -iquote ../../../artpaint/viewmanipulators -iquote ../../../artpaint/windows -internal-isystem /system/develop/headers/c++ -internal-isystem /system/develop/headers/c++/x86_64-unknown-haiku -internal-isystem /system/develop/headers/c++/backward -O3 -fdeprecated-macro -fdebug-compilation-dir /boot/home/HaikuArchives/ArtPaint/addons/AddOns/Saturation -ferror-limit 19 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2022-07-02-122529-1240-1 -x c++ Saturation.cpp
1/*
2 * Copyright 2003, Heikki Suhonen
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Heikki Suhonen <heikki.suhonen@gmail.com>
7 *
8 */
9#include <Bitmap.h>
10#include <Catalog.h>
11#include <LayoutBuilder.h>
12#include <Slider.h>
13#include <StatusBar.h>
14#include <string.h>
15#include <Window.h>
16
17#include "AddOns.h"
18#include "ManipulatorInformer.h"
19#include "Saturation.h"
20#include "Selection.h"
21
22#undef B_TRANSLATION_CONTEXT"AddOns_Saturation"
23#define B_TRANSLATION_CONTEXT"AddOns_Saturation" "AddOns_Saturation"
24
25
26#ifdef __cplusplus201402L
27extern "C" {
28#endif
29 char name[255] = B_TRANSLATE_MARK("Saturation" B_UTF8_ELLIPSIS)("Saturation" "\xE2\x80\xA6");
30 char menu_help_string[255] = B_TRANSLATE_MARK("Adjusts color saturation.")("Adjusts color saturation.");
31 int32 add_on_api_version = ADD_ON_API_VERSION;
32 add_on_types add_on_type = COLOR_ADD_ON;
33#ifdef __cplusplus201402L
34}
35#endif
36
37
38Manipulator* instantiate_add_on(BBitmap *bm,ManipulatorInformer *i)
39{
40 delete i;
41 return new SaturationManipulator(bm);
42}
43
44
45
46SaturationManipulator::SaturationManipulator(BBitmap *bm)
47 : WindowGUIManipulator()
48{
49 preview_bitmap = NULL__null;
50 config_view = NULL__null;
51 copy_of_the_preview_bitmap = NULL__null;
52 luminance_image = NULL__null;
53
54 previous_settings.saturation = settings.saturation + 1;
55
56 SetPreviewBitmap(bm);
57}
58
59
60SaturationManipulator::~SaturationManipulator()
61{
62 delete copy_of_the_preview_bitmap;
63 delete config_view;
64 delete luminance_image;
65}
66
67
68BBitmap* SaturationManipulator::ManipulateBitmap(ManipulatorSettings *set,BBitmap *original,Selection *selection,BStatusBar *status_bar)
69{
70 SaturationManipulatorSettings *new_settings = dynamic_cast<SaturationManipulatorSettings*>(set);
71
72 if (new_settings == NULL__null)
73 return NULL__null;
74
75 if (original == NULL__null)
76 return NULL__null;
77
78 if (original == preview_bitmap) {
79 if ((*new_settings == previous_settings) && (last_calculated_resolution <= 1))
80 return original;
81
82 source_bitmap = copy_of_the_preview_bitmap;
83 target_bitmap = original;
84 }
85 else {
86 source_bitmap = original;
87 target_bitmap = new BBitmap(original->Bounds(),B_RGB32,FALSE0);
88 }
89
90
91 current_resolution = 1;
92 current_selection = selection;
93 current_settings = *new_settings;
94 progress_bar = status_bar;
95
96 delete luminance_image;
97 luminance_image = new BBitmap(source_bitmap->Bounds(),B_CMAP8);
98 CalculateLuminanceImage(source_bitmap);
99
100 start_threads();
101
102 return target_bitmap;
103}
104
105
106void SaturationManipulator::CalculateLuminanceImage(BBitmap *bitmap)
107{
108 uint8 *luminance_bits = (uint8*)luminance_image->Bits();
109 uint32 luminance_bpr = luminance_image->BytesPerRow();
110
111 uint32 *bits = (uint32*)bitmap->Bits();
112 uint32 bpr = bitmap->BytesPerRow()/4;
113
114 int32 width = bitmap->Bounds().Width();
115 int32 height = bitmap->Bounds().Height();
116
117 union {
118 uint8 bytes[4];
119 uint32 word;
120 } color;
121
122 for (int32 y=0;y<=height;y++) {
123 int32 y_times_bpr = y*bpr;
124 int32 y_times_luminance_bpr = y*luminance_bpr;
125 for (int32 x=0;x<=width;x++) {
126 color.word = *(bits + x + y_times_bpr);
127 uint8 luminance;
128 luminance = min_c(255,max_c(0,0.144 * color.bytes[0] + 0.587 * color.bytes[1] + 0.299 * color.bytes[2]))((255)>(((0)>(0.144 * color.bytes[0] + 0.587 * color.bytes
[1] + 0.299 * color.bytes[2])?(0):(0.144 * color.bytes[0] + 0.587
* color.bytes[1] + 0.299 * color.bytes[2])))?(((0)>(0.144
* color.bytes[0] + 0.587 * color.bytes[1] + 0.299 * color.bytes
[2])?(0):(0.144 * color.bytes[0] + 0.587 * color.bytes[1] + 0.299
* color.bytes[2]))):(255))
;
129 *(luminance_bits + x + y_times_luminance_bpr) = luminance;
130 }
131 }
132}
133
134int32 SaturationManipulator::PreviewBitmap(Selection *selection,bool full_quality,BRegion *updated_region)
135{
136 progress_bar = NULL__null;
137 current_selection = selection;
138 if (settings == previous_settings ) {
139 if ((last_calculated_resolution != highest_available_quality) && (last_calculated_resolution > 0))
140 last_calculated_resolution = max_c(highest_available_quality,floor(last_calculated_resolution/2.0))((highest_available_quality)>(floor(last_calculated_resolution
/2.0))?(highest_available_quality):(floor(last_calculated_resolution
/2.0)))
;
141 else
142 last_calculated_resolution = 0;
143 }
144 else
145 last_calculated_resolution = lowest_available_quality;
146
147 if (full_quality) {
148 last_calculated_resolution = min_c(1,last_calculated_resolution)((1)>(last_calculated_resolution)?(last_calculated_resolution
):(1))
;
149 }
150 previous_settings = settings;
151
152 if (last_calculated_resolution > 0) {
153 current_resolution = last_calculated_resolution;
154 updated_region->Set(preview_bitmap->Bounds());
155
156 target_bitmap = preview_bitmap;
157 source_bitmap = copy_of_the_preview_bitmap;
158 current_settings = settings;
159
160 start_threads();
161 }
162
163 return last_calculated_resolution;
164}
165
166
167void SaturationManipulator::start_threads()
168{
169 number_of_threads = GetSystemCpuCount();
170
171 thread_id *threads = new thread_id[number_of_threads];
172
173 for (int32 i=0;i<number_of_threads;i++) {
174 threads[i] = spawn_thread(thread_entrythread_func,"saturation_thread",B_NORMAL_PRIORITY10,this);
175 resume_thread(threads[i]);
176 send_data(threads[i],i,NULL__null,0);
177 }
178
179 for (int32 i=0;i<number_of_threads;i++) {
180 int32 return_value;
181 wait_for_thread(threads[i],&return_value);
182 }
183
184 delete[] threads;
185}
186
187int32 SaturationManipulator::thread_entrythread_func(void *data)
188{
189 int32 thread_number;
190 thread_number = receive_data(NULL__null,NULL__null,0);
191
192 SaturationManipulator *this_pointer = (SaturationManipulator*)data;
193
194 return this_pointer->thread_function(thread_number);
195}
196
197
198int32 SaturationManipulator::thread_function(int32 thread_number)
199{
200 // This function interpolates the image with a degenerate version,
201 // which in this case is the luminance image. The luminance image
202 // is in bitmap luminance_image, which is in B_CMAP8 color-space.
203
204 int32 step = current_resolution;
205 uint32 saturation = settings.saturation;
206
207 BWindow *progress_bar_window = NULL__null;
208 if (progress_bar != NULL__null)
209 progress_bar_window = progress_bar->Window();
210
211
212 uint32 *source_bits = (uint32*)source_bitmap->Bits();
213 uint32 *target_bits = (uint32*)target_bitmap->Bits();
214 int32 source_bpr = source_bitmap->BytesPerRow()/4;
215 int32 target_bpr = target_bitmap->BytesPerRow()/4;
216 uint8 *luminance_bits = (uint8*)luminance_image->Bits();
217 uint32 luminance_bpr = luminance_image->BytesPerRow();
218
219 // This union must be used to guarantee endianness compatibility.
220 union {
221 uint8 bytes[4];
222 uint32 word;
223 } color;
224
225 float coeff = current_settings.saturation / 100.0;
226 float one_minus_coeff = 1.0 - coeff;
227
228 if (current_selection->IsEmpty()) {
229 // Here handle the whole image.
230 int32 left = target_bitmap->Bounds().left;
231 int32 right = target_bitmap->Bounds().right;
232 int32 top = target_bitmap->Bounds().top;
233 int32 bottom = target_bitmap->Bounds().bottom;
234
235 float height = bottom - top;
236 top = height/number_of_threads*thread_number;
237 top = ceil(top/(float)step);
238 top *= step;
239 bottom = min_c(bottom,top + (height+1)/number_of_threads)((bottom)>(top + (height+1)/number_of_threads)?(top + (height
+1)/number_of_threads):(bottom))
;
240 int32 update_interval = 10;
241 float update_amount = 100.0/(bottom-top)*update_interval/(float)number_of_threads;
242 float missed_update = 0;
243
244 // Loop through all pixels in original.
245 uint32 sum;
246 saturation *= 3;
Value stored to 'saturation' is never read
247 for (int32 y=top;y<=bottom;y+=step) {
248 int32 y_times_source_bpr = y*source_bpr;
249 int32 y_times_target_bpr = y*target_bpr;
250 int32 y_times_luminance_bpr = y*luminance_bpr;
251 uint8 luminance;
252 for (int32 x=left;x<=right;x+=step) {
253 color.word = *(source_bits + x + y_times_source_bpr);
254 luminance = *(luminance_bits + x + y_times_luminance_bpr);
255 color.bytes[0] = max_c(0,min_c(255,color.bytes[0] * coeff + luminance*one_minus_coeff))((0)>(((255)>(color.bytes[0] * coeff + luminance*one_minus_coeff
)?(color.bytes[0] * coeff + luminance*one_minus_coeff):(255))
)?(0):(((255)>(color.bytes[0] * coeff + luminance*one_minus_coeff
)?(color.bytes[0] * coeff + luminance*one_minus_coeff):(255))
))
;
256 color.bytes[1] = max_c(0,min_c(255,color.bytes[1] * coeff + luminance*one_minus_coeff))((0)>(((255)>(color.bytes[1] * coeff + luminance*one_minus_coeff
)?(color.bytes[1] * coeff + luminance*one_minus_coeff):(255))
)?(0):(((255)>(color.bytes[1] * coeff + luminance*one_minus_coeff
)?(color.bytes[1] * coeff + luminance*one_minus_coeff):(255))
))
;
257 color.bytes[2] = max_c(0,min_c(255,color.bytes[2] * coeff + luminance*one_minus_coeff))((0)>(((255)>(color.bytes[2] * coeff + luminance*one_minus_coeff
)?(color.bytes[2] * coeff + luminance*one_minus_coeff):(255))
)?(0):(((255)>(color.bytes[2] * coeff + luminance*one_minus_coeff
)?(color.bytes[2] * coeff + luminance*one_minus_coeff):(255))
))
;
258 *(target_bits + x + y_times_target_bpr) = color.word;
259 }
260
261 // Update the status-bar
262 if ( ((y % update_interval) == 0) && (progress_bar_window != NULL__null) && (progress_bar_window->LockWithTimeout(0) == B_OK((int)0)) ) {
263 progress_bar->Update(update_amount+missed_update);
264 progress_bar_window->Unlock();
265 missed_update = 0;
266 }
267 else if ((y % update_interval) == 0) {
268 missed_update += update_amount;
269 }
270 }
271 }
272 else {
273 // Here handle only those pixels for which selection->ContainsPoint(x,y) is true.
274 BRect rect = current_selection->GetBoundingRect();
275
276 int32 left = rect.left;
277 int32 right = rect.right;
278 int32 top = rect.top;
279 int32 bottom = rect.bottom;
280
281 float height = bottom - top;
282 top += height/number_of_threads*thread_number;
283 top *= step;
284 top /= step;
285
286 bottom = min_c(bottom,top + (height+1)/number_of_threads)((bottom)>(top + (height+1)/number_of_threads)?(top + (height
+1)/number_of_threads):(bottom))
;
287
288 int32 update_interval = 10;
289 float update_amount = 100.0/(bottom-top)*update_interval/(float)number_of_threads;
290
291 // Loop through all pixels in original.
292 for (int32 y=top;y<=bottom;y+=step) {
293 int32 y_times_source_bpr = y*source_bpr;
294 int32 y_times_target_bpr = y*target_bpr;
295 int32 y_times_luminance_bpr = y*luminance_bpr;
296 uint8 luminance;
297 for (int32 x=left;x<=right;x+=step) {
298 if (current_selection->ContainsPoint(x,y)) {
299 color.word = *(source_bits + x + y_times_source_bpr);
300 luminance = *(luminance_bits + x + y_times_luminance_bpr);
301 color.bytes[0] = max_c(0,min_c(255,color.bytes[0] * coeff + luminance*one_minus_coeff))((0)>(((255)>(color.bytes[0] * coeff + luminance*one_minus_coeff
)?(color.bytes[0] * coeff + luminance*one_minus_coeff):(255))
)?(0):(((255)>(color.bytes[0] * coeff + luminance*one_minus_coeff
)?(color.bytes[0] * coeff + luminance*one_minus_coeff):(255))
))
;
302 color.bytes[1] = max_c(0,min_c(255,color.bytes[1] * coeff + luminance*one_minus_coeff))((0)>(((255)>(color.bytes[1] * coeff + luminance*one_minus_coeff
)?(color.bytes[1] * coeff + luminance*one_minus_coeff):(255))
)?(0):(((255)>(color.bytes[1] * coeff + luminance*one_minus_coeff
)?(color.bytes[1] * coeff + luminance*one_minus_coeff):(255))
))
;
303 color.bytes[2] = max_c(0,min_c(255,color.bytes[2] * coeff + luminance*one_minus_coeff))((0)>(((255)>(color.bytes[2] * coeff + luminance*one_minus_coeff
)?(color.bytes[2] * coeff + luminance*one_minus_coeff):(255))
)?(0):(((255)>(color.bytes[2] * coeff + luminance*one_minus_coeff
)?(color.bytes[2] * coeff + luminance*one_minus_coeff):(255))
))
;
304 *(target_bits + x + y_times_target_bpr) = color.word;
305 }
306 }
307
308 // Update the status-bar
309 if ( ((y % update_interval) == 0) && (progress_bar_window != NULL__null) && (progress_bar_window->LockWithTimeout(0) == B_OK((int)0)) ) {
310 progress_bar->Update(update_amount);
311 progress_bar_window->Unlock();
312 }
313 }
314 }
315
316 return B_OK((int)0);
317}
318
319
320void SaturationManipulator::MouseDown(BPoint point,uint32,BView*,bool first_click)
321{
322 // This function does nothing in SaturationManipulator.
323}
324
325
326void SaturationManipulator::SetPreviewBitmap(BBitmap *bm)
327{
328 if (preview_bitmap != bm) {
329 delete copy_of_the_preview_bitmap;
330 delete luminance_image;
331
332 if (bm != NULL__null) {
333 preview_bitmap = bm;
334 copy_of_the_preview_bitmap = DuplicateBitmap(bm,0);
335 luminance_image = new BBitmap(preview_bitmap->Bounds(),B_CMAP8);
336 CalculateLuminanceImage(preview_bitmap);
337 }
338 else {
339 preview_bitmap = NULL__null;
340 copy_of_the_preview_bitmap = NULL__null;
341 luminance_image = NULL__null;
342 }
343 }
344
345 if (preview_bitmap != NULL__null) {
346 // Let's select a resolution that can handle all the pixels at least
347 // 10 times in a second while assuming that one pixel calculation takes
348 // about 50 CPU cycles.
349 double speed = GetSystemClockSpeed() / (10*50);
350 BRect bounds = preview_bitmap->Bounds();
351 float num_pixels = (bounds.Width()+1) * (bounds.Height() + 1);
352 lowest_available_quality = 1;
353 while ((num_pixels/lowest_available_quality/lowest_available_quality) > speed)
354 lowest_available_quality *= 2;
355
356 lowest_available_quality = min_c(lowest_available_quality,16)((lowest_available_quality)>(16)?(16):(lowest_available_quality
))
;
357 highest_available_quality = max_c(lowest_available_quality/2,1)((lowest_available_quality/2)>(1)?(lowest_available_quality
/2):(1))
;
358 }
359 else {
360 lowest_available_quality = 1;
361 highest_available_quality = 1;
362 }
363 last_calculated_resolution = lowest_available_quality;
364}
365
366
367void SaturationManipulator::Reset(Selection*)
368{
369 if (copy_of_the_preview_bitmap != NULL__null) {
370 // memcpy seems to be about 10-15% faster that copying with a loop.
371 uint32 *source = (uint32*)copy_of_the_preview_bitmap->Bits();
372 uint32 *target = (uint32*)preview_bitmap->Bits();
373 uint32 bits_length = preview_bitmap->BitsLength();
374
375 memcpy(target,source,bits_length);
376 }
377}
378
379BView* SaturationManipulator::MakeConfigurationView(const BMessenger& target)
380{
381 if (config_view == NULL__null) {
382 config_view = new SaturationManipulatorView(this,target);
383 config_view->ChangeSettings(&settings);
384 }
385
386 return config_view;
387}
388
389
390ManipulatorSettings* SaturationManipulator::ReturnSettings()
391{
392 return new SaturationManipulatorSettings(settings);
393}
394
395void SaturationManipulator::ChangeSettings(ManipulatorSettings *s)
396{
397 SaturationManipulatorSettings *new_settings;
398 new_settings = dynamic_cast<SaturationManipulatorSettings*>(s);
399
400 if (new_settings != NULL__null) {
401 settings = *new_settings;
402 }
403}
404
405const char* SaturationManipulator::ReturnName()
406{
407 return B_TRANSLATE("Saturation")BLocaleRoster::Default()->GetCatalog()->GetString(("Saturation"
), "AddOns_Saturation")
;
408}
409
410const char* SaturationManipulator::ReturnHelpString()
411{
412 return B_TRANSLATE("Adjusts color saturation.")BLocaleRoster::Default()->GetCatalog()->GetString(("Adjusts color saturation."
), "AddOns_Saturation")
;
413}
414
415
416
417
418// -------------------------------------
419SaturationManipulatorView::SaturationManipulatorView(SaturationManipulator *manip,
420 const BMessenger& t)
421 : WindowGUIManipulatorView()
422{
423 target = t;
424 manipulator = manip;
425 started_adjusting = FALSE0;
426
427 saturation_slider = new BSlider("saturation_slider",
428 B_TRANSLATE("Saturation:")BLocaleRoster::Default()->GetCatalog()->GetString(("Saturation:"
), "AddOns_Saturation")
, new BMessage(SATURATION_ADJUSTING_FINISHED'Thaf'), 0, 255,
429 B_HORIZONTAL, B_TRIANGLE_THUMB);
430 saturation_slider->SetModificationMessage(new BMessage(SATURATION_ADJUSTED'Thad'));
431 saturation_slider->SetLimitLabels(B_TRANSLATE("Low")BLocaleRoster::Default()->GetCatalog()->GetString(("Low"
), "AddOns_Saturation")
, B_TRANSLATE("High")BLocaleRoster::Default()->GetCatalog()->GetString(("High"
), "AddOns_Saturation")
);
432 saturation_slider->SetHashMarks(B_HASH_MARKS_BOTTOM);
433 saturation_slider->SetHashMarkCount(11);
434
435 BLayoutBuilder::Group<>(this, B_VERTICAL)
436 .Add(saturation_slider)
437 .SetInsets(B_USE_SMALL_INSETS)
438 .End();
439}
440
441SaturationManipulatorView::~SaturationManipulatorView()
442{
443}
444
445void SaturationManipulatorView::AttachedToWindow()
446{
447 WindowGUIManipulatorView::AttachedToWindow();
448 saturation_slider->SetTarget(BMessenger(this));
449}
450
451void SaturationManipulatorView::AllAttached()
452{
453 saturation_slider->SetValue(settings.saturation);
454}
455
456void SaturationManipulatorView::MessageReceived(BMessage *message)
457{
458 switch (message->what) {
459 case SATURATION_ADJUSTED'Thad':
460 settings.saturation = saturation_slider->Value();
461 manipulator->ChangeSettings(&settings);
462 if (!started_adjusting) {
463 target.SendMessage(HS_MANIPULATOR_ADJUSTING_STARTED'Mast');
464 started_adjusting = TRUE1;
465 }
466 break;
467
468 case SATURATION_ADJUSTING_FINISHED'Thaf':
469 started_adjusting = FALSE0;
470 settings.saturation = saturation_slider->Value();
471 manipulator->ChangeSettings(&settings);
472 target.SendMessage(HS_MANIPULATOR_ADJUSTING_FINISHED'Mafi');
473 break;
474
475 default:
476 WindowGUIManipulatorView::MessageReceived(message);
477 break;
478 }
479}
480
481void SaturationManipulatorView::ChangeSettings(ManipulatorSettings *set)
482{
483 SaturationManipulatorSettings *new_settings = dynamic_cast<SaturationManipulatorSettings*>(set);
484
485 if (set != NULL__null) {
486 settings = *new_settings;
487
488 BWindow *window = Window();
489 if (window != NULL__null) {
490 window->Lock();
491 saturation_slider->SetValue(settings.saturation);
492 window->Unlock();
493 }
494 }
495}