vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / Gradient.cpp
blob218323b8726d1701195d28ea095543e362fc0048
1 /*
2 * Copyright 2006-2009, Haiku.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stephan Aßmus <superstippi@gmx.de>
7 * Artur Wyszynski <harakash@gmail.com>
8 */
10 #include "Gradient.h"
12 #include <algorithm>
13 #include <math.h>
14 #include <stdio.h>
16 #include <Message.h>
19 // constructor
20 BGradient::ColorStop::ColorStop(const rgb_color c, float o)
22 color.red = c.red;
23 color.green = c.green;
24 color.blue = c.blue;
25 color.alpha = c.alpha;
26 offset = o;
30 // constructor
31 BGradient::ColorStop::ColorStop(uint8 r, uint8 g, uint8 b, uint8 a, float o)
33 color.red = r;
34 color.green = g;
35 color.blue = b;
36 color.alpha = a;
37 offset = o;
41 // constructor
42 BGradient::ColorStop::ColorStop(const ColorStop& other)
44 color.red = other.color.red;
45 color.green = other.color.green;
46 color.blue = other.color.blue;
47 color.alpha = other.color.alpha;
48 offset = other.offset;
52 // constructor
53 BGradient::ColorStop::ColorStop()
55 color.red = 0;
56 color.green = 0;
57 color.blue = 0;
58 color.alpha = 255;
59 offset = 0;
63 // operator!=
64 bool
65 BGradient::ColorStop::operator!=(const ColorStop& other) const
67 return color.red != other.color.red ||
68 color.green != other.color.green ||
69 color.blue != other.color.blue ||
70 color.alpha != other.color.alpha ||
71 offset != other.offset;
75 static bool
76 sort_color_stops_by_offset(const BGradient::ColorStop* left,
77 const BGradient::ColorStop* right)
79 return left->offset < right->offset;
83 // #pragma mark -
86 // constructor
87 BGradient::BGradient()
88 : BArchivable(),
89 fColorStops(4),
90 fType(TYPE_NONE)
95 // constructor
96 BGradient::BGradient(BMessage* archive)
97 : BArchivable(archive),
98 fColorStops(4),
99 fType(TYPE_NONE)
101 if (!archive)
102 return;
104 // color stops
105 ColorStop stop;
106 for (int32 i = 0; archive->FindFloat("offset", i, &stop.offset) >= B_OK; i++) {
107 if (archive->FindInt32("color", i, (int32*)&stop.color) >= B_OK)
108 AddColorStop(stop, i);
109 else
110 break;
112 if (archive->FindInt32("type", (int32*)&fType) < B_OK)
113 fType = TYPE_LINEAR;
115 // linear
116 if (archive->FindFloat("linear_x1", (float*)&fData.linear.x1) < B_OK)
117 fData.linear.x1 = 0.0f;
118 if (archive->FindFloat("linear_y1", (float*)&fData.linear.y1) < B_OK)
119 fData.linear.y1 = 0.0f;
120 if (archive->FindFloat("linear_x2", (float*)&fData.linear.x2) < B_OK)
121 fData.linear.x2 = 0.0f;
122 if (archive->FindFloat("linear_y2", (float*)&fData.linear.y2) < B_OK)
123 fData.linear.y2 = 0.0f;
125 // radial
126 if (archive->FindFloat("radial_cx", (float*)&fData.radial.cx) < B_OK)
127 fData.radial.cx = 0.0f;
128 if (archive->FindFloat("radial_cy", (float*)&fData.radial.cy) < B_OK)
129 fData.radial.cy = 0.0f;
130 if (archive->FindFloat("radial_radius", (float*)&fData.radial.radius) < B_OK)
131 fData.radial.radius = 0.0f;
133 // radial focus
134 if (archive->FindFloat("radial_f_cx", (float*)&fData.radial_focus.cx) < B_OK)
135 fData.radial_focus.cx = 0.0f;
136 if (archive->FindFloat("radial_f_cy", (float*)&fData.radial_focus.cy) < B_OK)
137 fData.radial_focus.cy = 0.0f;
138 if (archive->FindFloat("radial_f_fx", (float*)&fData.radial_focus.fx) < B_OK)
139 fData.radial_focus.fx = 0.0f;
140 if (archive->FindFloat("radial_f_fy", (float*)&fData.radial_focus.fy) < B_OK)
141 fData.radial_focus.fy = 0.0f;
142 if (archive->FindFloat("radial_f_radius", (float*)&fData.radial_focus.radius) < B_OK)
143 fData.radial_focus.radius = 0.0f;
145 // diamond
146 if (archive->FindFloat("diamond_cx", (float*)&fData.diamond.cx) < B_OK)
147 fData.diamond.cx = 0.0f;
148 if (archive->FindFloat("diamond_cy", (float*)&fData.diamond.cy) < B_OK)
149 fData.diamond.cy = 0.0f;
151 // conic
152 if (archive->FindFloat("conic_cx", (float*)&fData.conic.cx) < B_OK)
153 fData.conic.cx = 0.0f;
154 if (archive->FindFloat("conic_cy", (float*)&fData.conic.cy) < B_OK)
155 fData.conic.cy = 0.0f;
156 if (archive->FindFloat("conic_angle", (float*)&fData.conic.angle) < B_OK)
157 fData.conic.angle = 0.0f;
161 // destructor
162 BGradient::~BGradient()
164 MakeEmpty();
168 // Archive
169 status_t
170 BGradient::Archive(BMessage* into, bool deep) const
172 status_t ret = BArchivable::Archive(into, deep);
174 // color steps
175 if (ret >= B_OK) {
176 for (int32 i = 0; ColorStop* stop = ColorStopAt(i); i++) {
177 ret = into->AddInt32("color", (const uint32&)stop->color);
178 if (ret < B_OK)
179 break;
180 ret = into->AddFloat("offset", stop->offset);
181 if (ret < B_OK)
182 break;
185 // gradient type
186 if (ret >= B_OK)
187 ret = into->AddInt32("type", (int32)fType);
189 // linear
190 if (ret >= B_OK)
191 ret = into->AddFloat("linear_x1", (float)fData.linear.x1);
192 if (ret >= B_OK)
193 ret = into->AddFloat("linear_y1", (float)fData.linear.y1);
194 if (ret >= B_OK)
195 ret = into->AddFloat("linear_x2", (float)fData.linear.x2);
196 if (ret >= B_OK)
197 ret = into->AddFloat("linear_y2", (float)fData.linear.y2);
199 // radial
200 if (ret >= B_OK)
201 ret = into->AddFloat("radial_cx", (float)fData.radial.cx);
202 if (ret >= B_OK)
203 ret = into->AddFloat("radial_cy", (float)fData.radial.cy);
204 if (ret >= B_OK)
205 ret = into->AddFloat("radial_radius", (float)fData.radial.radius);
207 // radial focus
208 if (ret >= B_OK)
209 ret = into->AddFloat("radial_f_cx", (float)fData.radial_focus.cx);
210 if (ret >= B_OK)
211 ret = into->AddFloat("radial_f_cy", (float)fData.radial_focus.cy);
212 if (ret >= B_OK)
213 ret = into->AddFloat("radial_f_fx", (float)fData.radial_focus.fx);
214 if (ret >= B_OK)
215 ret = into->AddFloat("radial_f_fy", (float)fData.radial_focus.fy);
216 if (ret >= B_OK)
217 ret = into->AddFloat("radial_f_radius", (float)fData.radial_focus.radius);
219 // diamond
220 if (ret >= B_OK)
221 ret = into->AddFloat("diamond_cx", (float)fData.diamond.cx);
222 if (ret >= B_OK)
223 ret = into->AddFloat("diamond_cy", (float)fData.diamond.cy);
225 // conic
226 if (ret >= B_OK)
227 ret = into->AddFloat("conic_cx", (float)fData.conic.cx);
228 if (ret >= B_OK)
229 ret = into->AddFloat("conic_cy", (float)fData.conic.cy);
230 if (ret >= B_OK)
231 ret = into->AddFloat("conic_angle", (float)fData.conic.angle);
233 // finish off
234 if (ret >= B_OK)
235 ret = into->AddString("class", "BGradient");
237 return ret;
241 // operator=
242 BGradient&
243 BGradient::operator=(const BGradient& other)
245 SetColorStops(other);
246 fType = other.fType;
247 return *this;
251 // operator==
252 bool
253 BGradient::operator==(const BGradient& other) const
255 return ((other.GetType() == GetType()) && ColorStopsAreEqual(other));
259 // operator!=
260 bool
261 BGradient::operator!=(const BGradient& other) const
263 return !(*this == other);
267 // ColorStopsAreEqual
268 bool
269 BGradient::ColorStopsAreEqual(const BGradient& other) const
271 int32 count = CountColorStops();
272 if (count == other.CountColorStops() &&
273 fType == other.fType) {
275 bool equal = true;
276 for (int32 i = 0; i < count; i++) {
277 ColorStop* ourStop = ColorStopAtFast(i);
278 ColorStop* otherStop = other.ColorStopAtFast(i);
279 if (*ourStop != *otherStop) {
280 equal = false;
281 break;
284 return equal;
286 return false;
290 // SetColorStops
291 void
292 BGradient::SetColorStops(const BGradient& other)
294 MakeEmpty();
295 for (int32 i = 0; ColorStop* stop = other.ColorStopAt(i); i++)
296 AddColorStop(*stop, i);
300 // AddColor
301 int32
302 BGradient::AddColor(const rgb_color& color, float offset)
304 // Out of bounds stops would crash the app_server
305 if (offset < 0.f || offset > 255.f)
306 return -1;
308 // find the correct index (sorted by offset)
309 ColorStop* stop = new ColorStop(color, offset);
310 int32 index = 0;
311 int32 count = CountColorStops();
312 for (; index < count; index++) {
313 ColorStop* s = ColorStopAtFast(index);
314 if (s->offset > stop->offset)
315 break;
317 if (!fColorStops.AddItem((void*)stop, index)) {
318 delete stop;
319 return -1;
321 return index;
325 // AddColorStop
326 bool
327 BGradient::AddColorStop(const ColorStop& colorStop, int32 index)
329 ColorStop* stop = new ColorStop(colorStop);
330 if (!fColorStops.AddItem((void*)stop, index)) {
331 delete stop;
332 return false;
334 return true;
338 // RemoveColor
339 bool
340 BGradient::RemoveColor(int32 index)
342 ColorStop* stop = (ColorStop*)fColorStops.RemoveItem(index);
343 if (!stop) {
344 return false;
346 delete stop;
347 return true;
351 // SetColorStop
352 bool
353 BGradient::SetColorStop(int32 index, const ColorStop& color)
355 if (ColorStop* stop = ColorStopAt(index)) {
356 if (*stop != color) {
357 stop->color = color.color;
358 stop->offset = color.offset;
359 return true;
362 return false;
366 // SetColor
367 bool
368 BGradient::SetColor(int32 index, const rgb_color& color)
370 ColorStop* stop = ColorStopAt(index);
371 if (stop && stop->color != color) {
372 stop->color = color;
373 return true;
375 return false;
379 // SetOffset
380 bool
381 BGradient::SetOffset(int32 index, float offset)
383 ColorStop* stop = ColorStopAt(index);
384 if (stop && stop->offset != offset) {
385 stop->offset = offset;
386 return true;
388 return false;
392 // CountColorStops
393 int32
394 BGradient::CountColorStops() const
396 return fColorStops.CountItems();
400 // ColorStopAt
401 BGradient::ColorStop*
402 BGradient::ColorStopAt(int32 index) const
404 return (ColorStop*)fColorStops.ItemAt(index);
408 // ColorStopAtFast
409 BGradient::ColorStop*
410 BGradient::ColorStopAtFast(int32 index) const
412 return (ColorStop*)fColorStops.ItemAtFast(index);
416 // ColorStops
417 BGradient::ColorStop*
418 BGradient::ColorStops() const
420 if (CountColorStops() > 0) {
421 return (ColorStop*) fColorStops.Items();
423 return NULL;
427 // SortColorStopsByOffset
428 void
429 BGradient::SortColorStopsByOffset()
431 // Use stable sort: stops with the same offset will retain their original
432 // order. This can be used to have sharp color changes in the gradient.
433 // BList.SortItems() uses qsort(), which isn't stable, and sometimes swaps
434 // such stops.
435 const BGradient::ColorStop** first = (const BGradient::ColorStop**)fColorStops.Items();
436 const BGradient::ColorStop** last = first + fColorStops.CountItems();
437 std::stable_sort(first, last, sort_color_stops_by_offset);
441 // MakeEmpty
442 void
443 BGradient::MakeEmpty()
445 int32 count = CountColorStops();
446 for (int32 i = 0; i < count; i++)
447 delete ColorStopAtFast(i);
448 fColorStops.MakeEmpty();