Bug Summary

File:/boot/home/haiku/haiku/src/kits/interface/GridLayout.cpp
Location:line 790, column 3
Description:Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'

Annotated Source Code

1/*
2 * Copyright 2010-2011, Haiku Inc.
3 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
6
7
8#include <GridLayout.h>
9
10#include <algorithm>
11#include <new>
12#include <string.h>
13
14#include <ControlLook.h>
15#include <LayoutItem.h>
16#include <List.h>
17#include <Message.h>
18
19#include "ViewLayoutItem.h"
20
21
22using std::nothrow;
23using std::swap;
24
25
26enum {
27 MAX_COLUMN_ROW_COUNT = 1024,
28};
29
30
31namespace {
32 // a placeholder we put in our grid array to make a cell occupied
33 BLayoutItem* const OCCUPIED_GRID_CELL = (BLayoutItem*)0x1;
34
35 const char* const kRowSizesField = "BGridLayout:rowsizes";
36 // kRowSizesField = {min, max}
37 const char* const kRowWeightField = "BGridLayout:rowweight";
38 const char* const kColumnSizesField = "BGridLayout:columnsizes";
39 // kColumnSizesField = {min, max}
40 const char* const kColumnWeightField = "BGridLayout:columnweight";
41 const char* const kItemDimensionsField = "BGridLayout:item:dimensions";
42 // kItemDimensionsField = {x, y, width, height}
43}
44
45
46struct BGridLayout::ItemLayoutData {
47 Dimensions dimensions;
48
49 ItemLayoutData()
50 {
51 dimensions.x = 0;
52 dimensions.y = 0;
53 dimensions.width = 1;
54 dimensions.height = 1;
55 }
56};
57
58
59class BGridLayout::RowInfoArray {
60public:
61 RowInfoArray()
62 {
63 }
64
65 ~RowInfoArray()
66 {
67 for (int32 i = 0; Info* info = (Info*)fInfos.ItemAt(i); i++)
68 delete info;
69 }
70
71 int32 Count() const
72 {
73 return fInfos.CountItems();
74 }
75
76 float Weight(int32 index) const
77 {
78 if (Info* info = _InfoAt(index))
79 return info->weight;
80 return 1;
81 }
82
83 void SetWeight(int32 index, float weight)
84 {
85 if (Info* info = _InfoAt(index, true))
86 info->weight = weight;
87 }
88
89 float MinSize(int32 index) const
90 {
91 if (Info* info = _InfoAt(index))
92 return info->minSize;
93 return B_SIZE_UNSET;
94 }
95
96 void SetMinSize(int32 index, float size)
97 {
98 if (Info* info = _InfoAt(index, true))
99 info->minSize = size;
100 }
101
102 float MaxSize(int32 index) const
103 {
104 if (Info* info = _InfoAt(index))
105 return info->maxSize;
106 return B_SIZE_UNSET;
107 }
108
109 void SetMaxSize(int32 index, float size)
110 {
111 if (Info* info = _InfoAt(index, true))
112 info->maxSize = size;
113 }
114
115private:
116 struct Info {
117 float weight;
118 float minSize;
119 float maxSize;
120 };
121
122 Info* _InfoAt(int32 index) const
123 {
124 return (Info*)fInfos.ItemAt(index);
125 }
126
127 Info* _InfoAt(int32 index, bool resize)
128 {
129 if (index < 0 || index >= MAX_COLUMN_ROW_COUNT)
130 return NULL__null;
131
132 // resize, if necessary and desired
133 int32 count = Count();
134 if (index >= count) {
135 if (!resize)
136 return NULL__null;
137
138 for (int32 i = count; i <= index; i++) {
139 Info* info = new Info;
140 info->weight = 1;
141 info->minSize = B_SIZE_UNSET;
142 info->maxSize = B_SIZE_UNSET;
143 fInfos.AddItem(info);
144 }
145 }
146
147 return _InfoAt(index);
148 }
149
150 BList fInfos;
151};
152
153
154BGridLayout::BGridLayout(float horizontal, float vertical)
155 :
156 fGrid(NULL__null),
157 fColumnCount(0),
158 fRowCount(0),
159 fRowInfos(new RowInfoArray),
160 fColumnInfos(new RowInfoArray),
161 fMultiColumnItems(0),
162 fMultiRowItems(0)
163{
164 SetSpacing(horizontal, vertical);
165}
166
167
168BGridLayout::BGridLayout(BMessage* from)
169 :
170 BTwoDimensionalLayout(BUnarchiver::PrepareArchive(from)),
171 fGrid(NULL__null),
172 fColumnCount(0),
173 fRowCount(0),
174 fRowInfos(new RowInfoArray),
175 fColumnInfos(new RowInfoArray),
176 fMultiColumnItems(0),
177 fMultiRowItems(0)
178{
179 BUnarchiver unarchiver(from);
180 int32 columns;
181 from->GetInfo(kColumnWeightField, NULL__null, &columns);
182
183 int32 rows;
184 from->GetInfo(kRowWeightField, NULL__null, &rows);
185
186 // sets fColumnCount && fRowCount on success
187 if (!_ResizeGrid(columns, rows)) {
188 unarchiver.Finish(B_NO_MEMORY((-2147483647 - 1) + 0));
189 return;
190 }
191
192 for (int32 i = 0; i < fRowCount; i++) {
193 float getter;
194 if (from->FindFloat(kRowWeightField, i, &getter) == B_OK((int)0))
195 fRowInfos->SetWeight(i, getter);
196
197 if (from->FindFloat(kRowSizesField, i * 2, &getter) == B_OK((int)0))
198 fRowInfos->SetMinSize(i, getter);
199
200 if (from->FindFloat(kRowSizesField, i * 2 + 1, &getter) == B_OK((int)0))
201 fRowInfos->SetMaxSize(i, getter);
202 }
203
204 for (int32 i = 0; i < fColumnCount; i++) {
205 float getter;
206 if (from->FindFloat(kColumnWeightField, i, &getter) == B_OK((int)0))
207 fColumnInfos->SetWeight(i, getter);
208
209 if (from->FindFloat(kColumnSizesField, i * 2, &getter) == B_OK((int)0))
210 fColumnInfos->SetMinSize(i, getter);
211
212 if (from->FindFloat(kColumnSizesField, i * 2 + 1, &getter) == B_OK((int)0))
213 fColumnInfos->SetMaxSize(i, getter);
214 }
215}
216
217
218BGridLayout::~BGridLayout()
219{
220 delete fRowInfos;
221 delete fColumnInfos;
222}
223
224
225int32
226BGridLayout::CountColumns() const
227{
228 return fColumnCount;
229}
230
231
232int32
233BGridLayout::CountRows() const
234{
235 return fRowCount;
236}
237
238
239float
240BGridLayout::HorizontalSpacing() const
241{
242 return fHSpacing;
243}
244
245
246float
247BGridLayout::VerticalSpacing() const
248{
249 return fVSpacing;
250}
251
252
253void
254BGridLayout::SetHorizontalSpacing(float spacing)
255{
256 spacing = BControlLook::ComposeSpacing(spacing);
257 if (spacing != fHSpacing) {
258 fHSpacing = spacing;
259
260 InvalidateLayout();
261 }
262}
263
264
265void
266BGridLayout::SetVerticalSpacing(float spacing)
267{
268 spacing = BControlLook::ComposeSpacing(spacing);
269 if (spacing != fVSpacing) {
270 fVSpacing = spacing;
271
272 InvalidateLayout();
273 }
274}
275
276
277void
278BGridLayout::SetSpacing(float horizontal, float vertical)
279{
280 horizontal = BControlLook::ComposeSpacing(horizontal);
281 vertical = BControlLook::ComposeSpacing(vertical);
282 if (horizontal != fHSpacing || vertical != fVSpacing) {
283 fHSpacing = horizontal;
284 fVSpacing = vertical;
285
286 InvalidateLayout();
287 }
288}
289
290
291float
292BGridLayout::ColumnWeight(int32 column) const
293{
294 return fColumnInfos->Weight(column);
295}
296
297
298void
299BGridLayout::SetColumnWeight(int32 column, float weight)
300{
301 fColumnInfos->SetWeight(column, weight);
302}
303
304
305float
306BGridLayout::MinColumnWidth(int32 column) const
307{
308 return fColumnInfos->MinSize(column);
309}
310
311
312void
313BGridLayout::SetMinColumnWidth(int32 column, float width)
314{
315 fColumnInfos->SetMinSize(column, width);
316}
317
318
319float
320BGridLayout::MaxColumnWidth(int32 column) const
321{
322 return fColumnInfos->MaxSize(column);
323}
324
325
326void
327BGridLayout::SetMaxColumnWidth(int32 column, float width)
328{
329 fColumnInfos->SetMaxSize(column, width);
330}
331
332
333float
334BGridLayout::RowWeight(int32 row) const
335{
336 return fRowInfos->Weight(row);
337}
338
339
340void
341BGridLayout::SetRowWeight(int32 row, float weight)
342{
343 fRowInfos->SetWeight(row, weight);
344}
345
346
347float
348BGridLayout::MinRowHeight(int row) const
349{
350 return fRowInfos->MinSize(row);
351}
352
353
354void
355BGridLayout::SetMinRowHeight(int32 row, float height)
356{
357 fRowInfos->SetMinSize(row, height);
358}
359
360
361float
362BGridLayout::MaxRowHeight(int32 row) const
363{
364 return fRowInfos->MaxSize(row);
365}
366
367
368void
369BGridLayout::SetMaxRowHeight(int32 row, float height)
370{
371 fRowInfos->SetMaxSize(row, height);
372}
373
374
375BLayoutItem*
376BGridLayout::ItemAt(int32 column, int32 row) const
377{
378 if (column < 0 || column >= CountColumns()
379 || row < 0 || row >= CountRows())
380 return NULL__null;
381
382 return fGrid[column][row];
383}
384
385
386BLayoutItem*
387BGridLayout::AddView(BView* child)
388{
389 return BTwoDimensionalLayout::AddView(child);
390}
391
392
393BLayoutItem*
394BGridLayout::AddView(int32 index, BView* child)
395{
396 return BTwoDimensionalLayout::AddView(index, child);
397}
398
399
400BLayoutItem*
401BGridLayout::AddView(BView* child, int32 column, int32 row, int32 columnCount,
402 int32 rowCount)
403{
404 if (!child)
405 return NULL__null;
406
407 BLayoutItem* item = new BViewLayoutItem(child);
408 if (!AddItem(item, column, row, columnCount, rowCount)) {
409 delete item;
410 return NULL__null;
411 }
412
413 return item;
414}
415
416
417bool
418BGridLayout::AddItem(BLayoutItem* item)
419{
420 // find a free spot
421 for (int32 row = 0; row < fRowCount; row++) {
422 for (int32 column = 0; column < fColumnCount; column++) {
423 if (_IsGridCellEmpty(row, column))
424 return AddItem(item, column, row, 1, 1);
425 }
426 }
427
428 // no free spot, start a new column
429 return AddItem(item, fColumnCount, 0, 1, 1);
430}
431
432
433bool
434BGridLayout::AddItem(int32 index, BLayoutItem* item)
435{
436 return AddItem(item);
437}
438
439
440bool
441BGridLayout::AddItem(BLayoutItem* item, int32 column, int32 row,
442 int32 columnCount, int32 rowCount)
443{
444 if (!_AreGridCellsEmpty(column, row, columnCount, rowCount))
445 return false;
446
447 bool success = BTwoDimensionalLayout::AddItem(-1, item);
448 if (!success)
449 return false;
450
451 // set item dimensions
452 if (ItemLayoutData* data = _LayoutDataForItem(item)) {
453 data->dimensions.x = column;
454 data->dimensions.y = row;
455 data->dimensions.width = columnCount;
456 data->dimensions.height = rowCount;
457 }
458
459 if (!_InsertItemIntoGrid(item)) {
460 RemoveItem(item);
461 return false;
462 }
463
464 if (columnCount > 1)
465 fMultiColumnItems++;
466 if (rowCount > 1)
467 fMultiRowItems++;
468
469 return success;
470}
471
472
473status_t
474BGridLayout::Archive(BMessage* into, bool deep) const
475{
476 BArchiver archiver(into);
477 status_t err = BTwoDimensionalLayout::Archive(into, deep);
478
479 for (int32 i = 0; i < fRowCount && err == B_OK((int)0); i++) {
480 err = into->AddFloat(kRowWeightField, fRowInfos->Weight(i));
481 if (err == B_OK((int)0))
482 err = into->AddFloat(kRowSizesField, fRowInfos->MinSize(i));
483 if (err == B_OK((int)0))
484 err = into->AddFloat(kRowSizesField, fRowInfos->MaxSize(i));
485 }
486
487 for (int32 i = 0; i < fColumnCount && err == B_OK((int)0); i++) {
488 err = into->AddFloat(kColumnWeightField, fColumnInfos->Weight(i));
489 if (err == B_OK((int)0))
490 err = into->AddFloat(kColumnSizesField, fColumnInfos->MinSize(i));
491 if (err == B_OK((int)0))
492 err = into->AddFloat(kColumnSizesField, fColumnInfos->MaxSize(i));
493 }
494
495 return archiver.Finish(err);
496}
497
498
499status_t
500BGridLayout::AllArchived(BMessage* into) const
501{
502 return BTwoDimensionalLayout::AllArchived(into);
503}
504
505
506status_t
507BGridLayout::AllUnarchived(const BMessage* from)
508{
509 return BTwoDimensionalLayout::AllUnarchived(from);
510}
511
512
513BArchivable*
514BGridLayout::Instantiate(BMessage* from)
515{
516 if (validate_instantiation(from, "BGridLayout"))
517 return new BGridLayout(from);
518 return NULL__null;
519}
520
521
522status_t
523BGridLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const
524{
525 ItemLayoutData* data = _LayoutDataForItem(item);
526
527 status_t err = into->AddInt32(kItemDimensionsField, data->dimensions.x);
528 if (err == B_OK((int)0))
529 err = into->AddInt32(kItemDimensionsField, data->dimensions.y);
530 if (err == B_OK((int)0))
531 err = into->AddInt32(kItemDimensionsField, data->dimensions.width);
532 if (err == B_OK((int)0))
533 err = into->AddInt32(kItemDimensionsField, data->dimensions.height);
534
535 return err;
536}
537
538
539status_t
540BGridLayout::ItemUnarchived(const BMessage* from,
541 BLayoutItem* item, int32 index)
542{
543 ItemLayoutData* data = _LayoutDataForItem(item);
544 Dimensions& dimensions = data->dimensions;
545
546 index *= 4;
547 // each item stores 4 int32s into kItemDimensionsField
548 status_t err = from->FindInt32(kItemDimensionsField, index, &dimensions.x);
549 if (err == B_OK((int)0))
550 err = from->FindInt32(kItemDimensionsField, ++index, &dimensions.y);
551
552 if (err == B_OK((int)0))
553 err = from->FindInt32(kItemDimensionsField, ++index, &dimensions.width);
554
555 if (err == B_OK((int)0)) {
556 err = from->FindInt32(kItemDimensionsField,
557 ++index, &dimensions.height);
558 }
559
560 if (err != B_OK((int)0))
561 return err;
562
563 if (!_AreGridCellsEmpty(dimensions.x, dimensions.y,
564 dimensions.width, dimensions.height))
565 return B_BAD_DATA((-2147483647 - 1) + 16);
566
567 if (!_InsertItemIntoGrid(item))
568 return B_NO_MEMORY((-2147483647 - 1) + 0);
569
570 if (dimensions.width > 1)
571 fMultiColumnItems++;
572 if (dimensions.height > 1)
573 fMultiRowItems++;
574
575 return err;
576}
577
578
579bool
580BGridLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
581{
582 item->SetLayoutData(new(nothrow) ItemLayoutData);
583 return item->LayoutData() != NULL__null;
584}
585
586
587void
588BGridLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
589{
590 ItemLayoutData* data = _LayoutDataForItem(item);
591 Dimensions itemDimensions = data->dimensions;
592 item->SetLayoutData(NULL__null);
593 delete data;
594
595 if (itemDimensions.width > 1)
596 fMultiColumnItems--;
597 if (itemDimensions.height > 1)
598 fMultiRowItems--;
599
600 // remove the item from the grid
601 for (int x = 0; x < itemDimensions.width; x++) {
602 for (int y = 0; y < itemDimensions.height; y++)
603 fGrid[itemDimensions.x + x][itemDimensions.y + y] = NULL__null;
604 }
605
606 // check whether we can shrink the grid
607 if (itemDimensions.x + itemDimensions.width == fColumnCount
608 || itemDimensions.y + itemDimensions.height == fRowCount) {
609 int32 columnCount = fColumnCount;
610 int32 rowCount = fRowCount;
611
612 // check for empty columns
613 bool empty = true;
614 for (; columnCount > 0; columnCount--) {
615 for (int32 row = 0; empty && row < rowCount; row++)
616 empty &= (fGrid[columnCount - 1][row] == NULL__null);
617
618 if (!empty)
619 break;
620 }
621
622 // check for empty rows
623 empty = true;
624 for (; rowCount > 0; rowCount--) {
625 for (int32 column = 0; empty && column < columnCount; column++)
626 empty &= (fGrid[column][rowCount - 1] == NULL__null);
627
628 if (!empty)
629 break;
630 }
631
632 // resize the grid
633 if (columnCount != fColumnCount || rowCount != fRowCount)
634 _ResizeGrid(columnCount, rowCount);
635 }
636}
637
638
639bool
640BGridLayout::HasMultiColumnItems()
641{
642 return (fMultiColumnItems > 0);
643}
644
645
646bool
647BGridLayout::HasMultiRowItems()
648{
649 return (fMultiRowItems > 0);
650}
651
652
653int32
654BGridLayout::InternalCountColumns()
655{
656 return fColumnCount;
657}
658
659
660int32
661BGridLayout::InternalCountRows()
662{
663 return fRowCount;
664}
665
666
667void
668BGridLayout::GetColumnRowConstraints(orientation orientation, int32 index,
669 ColumnRowConstraints* constraints)
670{
671 if (orientation == B_HORIZONTAL) {
672 constraints->min = MinColumnWidth(index);
673 constraints->max = MaxColumnWidth(index);
674 constraints->weight = ColumnWeight(index);
675 } else {
676 constraints->min = MinRowHeight(index);
677 constraints->max = MaxRowHeight(index);
678 constraints->weight = RowWeight(index);
679 }
680}
681
682
683void
684BGridLayout::GetItemDimensions(BLayoutItem* item, Dimensions* dimensions)
685{
686 if (ItemLayoutData* data = _LayoutDataForItem(item))
687 *dimensions = data->dimensions;
688}
689
690
691bool
692BGridLayout::_IsGridCellEmpty(int32 column, int32 row)
693{
694 if (column < 0 || row < 0)
695 return false;
696 if (column >= fColumnCount || row >= fRowCount)
697 return true;
698
699 return (fGrid[column][row] == NULL__null);
700}
701
702
703bool
704BGridLayout::_AreGridCellsEmpty(int32 column, int32 row, int32 columnCount,
705 int32 rowCount)
706{
707 if (column < 0 || row < 0)
708 return false;
709 int32 toColumn = min_c(column + columnCount, fColumnCount)((column + columnCount)>(fColumnCount)?(fColumnCount):(column
+ columnCount))
;
710 int32 toRow = min_c(row + rowCount, fRowCount)((row + rowCount)>(fRowCount)?(fRowCount):(row + rowCount)
)
;
711
712 for (int32 x = column; x < toColumn; x++) {
713 for (int32 y = row; y < toRow; y++) {
714 if (fGrid[x][y] != NULL__null)
715 return false;
716 }
717 }
718
719 return true;
720}
721
722
723bool
724BGridLayout::_InsertItemIntoGrid(BLayoutItem* item)
725{
726 BGridLayout::ItemLayoutData* data = _LayoutDataForItem(item);
727 int32 column = data->dimensions.x;
728 int32 columnCount = data->dimensions.width;
729 int32 row = data->dimensions.y;
730 int32 rowCount = data->dimensions.height;
731
732 // resize the grid, if necessary
733 int32 newColumnCount = max_c(fColumnCount, column + columnCount)((fColumnCount)>(column + columnCount)?(fColumnCount):(column
+ columnCount))
;
734 int32 newRowCount = max_c(fRowCount, row + rowCount)((fRowCount)>(row + rowCount)?(fRowCount):(row + rowCount)
)
;
735 if (newColumnCount > fColumnCount || newRowCount > fRowCount) {
736 if (!_ResizeGrid(newColumnCount, newRowCount))
737 return false;
738 }
739
740 // enter the item in the grid
741 for (int32 x = 0; x < columnCount; x++) {
742 for (int32 y = 0; y < rowCount; y++) {
743 if (x == 0 && y == 0)
744 fGrid[column + x][row + y] = item;
745 else
746 fGrid[column + x][row + y] = OCCUPIED_GRID_CELL;
747 }
748 }
749 return true;
750}
751
752
753bool
754BGridLayout::_ResizeGrid(int32 columnCount, int32 rowCount)
755{
756 if (columnCount == fColumnCount && rowCount == fRowCount)
757 return true;
758
759 int32 rowsToKeep = min_c(rowCount, fRowCount)((rowCount)>(fRowCount)?(fRowCount):(rowCount));
760
761 // allocate new grid
762 BLayoutItem*** grid = new(nothrow) BLayoutItem**[columnCount];
763 if (!grid)
1
Assuming 'grid' is non-null
2
Taking false branch
764 return false;
765 memset(grid, 0, sizeof(BLayoutItem**) * columnCount);
766
767 bool success = true;
768 for (int32 i = 0; i < columnCount; i++) {
3
Assuming 'i' is < 'columnCount'
4
Loop condition is true. Entering loop body
8
Assuming 'i' is < 'columnCount'
9
Loop condition is true. Entering loop body
769 BLayoutItem** column = new(nothrow) BLayoutItem*[rowCount];
5
Memory is allocated
770 if (!column) {
6
Assuming 'column' is non-null
7
Taking false branch
10
Assuming 'column' is null
11
Taking true branch
771 success = false;
772 break;
12
Execution continues on line 782
773 }
774 grid[i] = column;
775
776 memset(column, 0, sizeof(BLayoutItem*) * rowCount);
777 if (i < fColumnCount && rowsToKeep > 0)
778 memcpy(column, fGrid[i], sizeof(BLayoutItem*) * rowsToKeep);
779 }
780
781 // if everything went fine, set the new grid
782 if (success) {
13
Taking false branch
783 swap(grid, fGrid);
784 swap(columnCount, fColumnCount);
785 swap(rowCount, fRowCount);
786 }
787
788 // delete the old, respectively on error the partially created grid
789 for (int32 i = 0; i < columnCount; i++)
14
Loop condition is true. Entering loop body
790 delete grid[i];
15
Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'
791 delete[] grid;
792
793 return success;
794}
795
796
797BGridLayout::ItemLayoutData*
798BGridLayout::_LayoutDataForItem(BLayoutItem* item) const
799{
800 if (!item)
801 return NULL__null;
802 return (ItemLayoutData*)item->LayoutData();
803}
804
805
806status_t
807BGridLayout::Perform(perform_code d, void* arg)
808{
809 return BTwoDimensionalLayout::Perform(d, arg);
810}
811
812
813void BGridLayout::_ReservedGridLayout1() {}
814void BGridLayout::_ReservedGridLayout2() {}
815void BGridLayout::_ReservedGridLayout3() {}
816void BGridLayout::_ReservedGridLayout4() {}
817void BGridLayout::_ReservedGridLayout5() {}
818void BGridLayout::_ReservedGridLayout6() {}
819void BGridLayout::_ReservedGridLayout7() {}
820void BGridLayout::_ReservedGridLayout8() {}
821void BGridLayout::_ReservedGridLayout9() {}
822void BGridLayout::_ReservedGridLayout10() {}
823