Module: wine Branch: master Commit: 5517209a241f34506533a892aee8c09c2d2f65ac URL: http://source.winehq.org/git/wine.git/?a=commit;h=5517209a241f34506533a892ae...
Author: Nikolay Sivov bunglehead@gmail.com Date: Sun Oct 18 15:21:00 2009 +0400
comctl32/header: Process input order array more accurately.
---
dlls/comctl32/header.c | 58 ++++++++++++++++++--- dlls/comctl32/tests/header.c | 121 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 7 deletions(-)
diff --git a/dlls/comctl32/header.c b/dlls/comctl32/header.c index d84965c..dce1d8c 100644 --- a/dlls/comctl32/header.c +++ b/dlls/comctl32/header.c @@ -1214,20 +1214,64 @@ HEADER_GetOrderArray(const HEADER_INFO *infoPtr, INT size, LPINT order) return TRUE; }
+/* Returns index of first duplicate 'value' from [0,to) range, + or -1 if there isn't any */ +static INT has_duplicate(INT *array, INT to, INT value) +{ + INT i; + for(i = 0; i < to; i++) + if (array[i] == value) return i; + return -1; +} + +/* returns next available value from [0,max] not to duplicate in [0,to) */ +static INT get_nextvalue(INT *array, INT to, INT max) +{ + INT i; + for(i = 0; i < max; i++) + if (has_duplicate(array, to, i) == -1) return i; + return 0; +} + static LRESULT HEADER_SetOrderArray(HEADER_INFO *infoPtr, INT size, const INT *order) { - INT i; HEADER_ITEM *lpItem; + INT i;
- if ((UINT)size <infoPtr->uNumItem) + if ((UINT)size != infoPtr->uNumItem) return FALSE; - memcpy(infoPtr->order, order, infoPtr->uNumItem * sizeof(INT)); + + for (i=0; i<size; i++) + { + if (order[i] >= size || order[i] < 0) + /* on invalid index get next available */ + /* FIXME: if i==0 array item is out of range behaviour is + different, see tests */ + infoPtr->order[i] = get_nextvalue(infoPtr->order, i, size); + else + { + INT j, dup; + + infoPtr->order[i] = order[i]; + j = i; + /* remove duplicates */ + while ((dup = has_duplicate(infoPtr->order, j, order[j])) != -1) + { + INT next; + + next = get_nextvalue(infoPtr->order, j, size); + infoPtr->order[dup] = next; + j--; + } + } + } + /* sync with item data */ for (i=0; i<size; i++) - { - lpItem = &infoPtr->items[*order++]; - lpItem->iOrder=i; - } + { + lpItem = &infoPtr->items[infoPtr->order[i]]; + lpItem->iOrder = i; + } HEADER_SetItemBounds(infoPtr); InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); return TRUE; diff --git a/dlls/comctl32/tests/header.c b/dlls/comctl32/tests/header.c index 2fecaee..283c568 100644 --- a/dlls/comctl32/tests/header.c +++ b/dlls/comctl32/tests/header.c @@ -1689,6 +1689,126 @@ static int init(void) return 1; }
+/* maximum 8 items allowed */ +static void check_orderarray(HWND hwnd, DWORD start, DWORD set, DWORD expected, + int todo, int line) +{ + int count, i; + INT order[8]; + DWORD ret, array = 0; + + count = SendMessage(hwnd, HDM_GETITEMCOUNT, 0, 0); + + /* initial order */ + for(i = 1; i<=count; i++) + order[i-1] = start>>(4*(count-i)) & 0xf; + + ret = SendMessage(hwnd, HDM_SETORDERARRAY, count, (LPARAM)order); + ok_(__FILE__, line)(ret, "Expected HDM_SETORDERARAY to succeed, got %d\n", ret); + + /* new order */ + for(i = 1; i<=count; i++) + order[i-1] = set>>(4*(count-i)) & 0xf; + ret = SendMessage(hwnd, HDM_SETORDERARRAY, count, (LPARAM)order); + ok_(__FILE__, line)(ret, "Expected HDM_SETORDERARAY to succeed, got %d\n", ret); + + /* check actual order */ + ret = SendMessage(hwnd, HDM_GETORDERARRAY, count, (LPARAM)order); + ok_(__FILE__, line)(ret, "Expected HDM_GETORDERARAY to succeed, got %d\n", ret); + for(i = 1; i<=count; i++) + array |= order[i-1]<<(4*(count-i)); + + if (todo) { + todo_wine + ok_(__FILE__, line)(array == expected, "Expected %x, got %x\n", expected, array); + } + else + ok_(__FILE__, line)(array == expected, "Expected %x, got %x\n", expected, array); +} + +static void test_hdm_orderarray(void) +{ + HWND hwnd; + INT order[5]; + DWORD ret; + + hwnd = create_header_control(); + + /* three items */ + addItem(hwnd, 0, NULL); + addItem(hwnd, 1, NULL); + addItem(hwnd, 2, NULL); + + ret = SendMessage(hwnd, HDM_GETORDERARRAY, 3, (LPARAM)order); + if (!ret) + { + win_skip("HDM_GETORDERARRAY not implemented.\n"); + DestroyWindow(hwnd); + return; + } + + expect(0, order[0]); + expect(1, order[1]); + expect(2, order[2]); + +if (0) +{ + /* null pointer, crashes native */ + ret = SendMessage(hwnd, HDM_SETORDERARRAY, 3, (LPARAM)NULL); + expect(FALSE, ret); +} + /* count out of limits */ + ret = SendMessage(hwnd, HDM_SETORDERARRAY, 5, (LPARAM)order); + expect(FALSE, ret); + /* count out of limits */ + ret = SendMessage(hwnd, HDM_SETORDERARRAY, 2, (LPARAM)order); + expect(FALSE, ret); + + /* try with out of range item index */ + /* (0,1,2)->(1,0,3) => (1,0,2) */ + check_orderarray(hwnd, 0x120, 0x103, 0x102, FALSE, __LINE__); + /* (1,0,2)->(3,0,1) => (0,2,1) */ + check_orderarray(hwnd, 0x102, 0x301, 0x021, TRUE, __LINE__); + /* (0,2,1)->(2,3,1) => (2,0,1) */ + check_orderarray(hwnd, 0x021, 0x231, 0x201, FALSE, __LINE__); + + /* (0,1,2)->(0,2,2) => (0,1,2) */ + check_orderarray(hwnd, 0x012, 0x022, 0x012, FALSE, __LINE__); + + addItem(hwnd, 3, NULL); + + /* (0,1,2,3)->(0,1,2,2) => (0,1,3,2) */ + check_orderarray(hwnd, 0x0123, 0x0122, 0x0132, FALSE, __LINE__); + /* (0,1,2,3)->(0,1,3,3) => (0,1,2,3) */ + check_orderarray(hwnd, 0x0123, 0x0133, 0x0123, FALSE, __LINE__); + /* (0,1,2,3)->(0,4,2,3) => (0,1,2,3) */ + check_orderarray(hwnd, 0x0123, 0x0423, 0x0123, FALSE, __LINE__); + /* (0,1,2,3)->(4,0,1,2) => (0,1,3,2) */ + check_orderarray(hwnd, 0x0123, 0x4012, 0x0132, TRUE, __LINE__); + /* (0,1,3,2)->(4,0,1,4) => (0,3,1,2) */ + check_orderarray(hwnd, 0x0132, 0x4014, 0x0312, TRUE, __LINE__); + /* (0,1,2,3)->(4,1,0,2) => (1,0,3,2) */ + check_orderarray(hwnd, 0x0123, 0x4102, 0x1032, TRUE, __LINE__); + /* (0,1,2,3)->(0,1,4,2) => (0,1,2,3) */ + check_orderarray(hwnd, 0x0123, 0x0142, 0x0132, FALSE, __LINE__); + /* (0,1,2,3)->(4,4,4,4) => (0,1,2,3) */ + check_orderarray(hwnd, 0x0123, 0x4444, 0x0123, FALSE, __LINE__); + /* (0,1,2,3)->(4,4,1,2) => (0,1,3,2) */ + check_orderarray(hwnd, 0x0123, 0x4412, 0x0132, TRUE, __LINE__); + /* (0,1,2,3)->(4,4,4,1) => (0,2,3,1) */ + check_orderarray(hwnd, 0x0123, 0x4441, 0x0231, TRUE, __LINE__); + /* (0,1,2,3)->(1,4,4,4) => (1,0,2,3) */ + check_orderarray(hwnd, 0x0123, 0x1444, 0x1023, FALSE, __LINE__); + /* (0,1,2,3)->(4,2,4,1) => (0,2,3,1) */ + check_orderarray(hwnd, 0x0123, 0x4241, 0x0231, FALSE, __LINE__); + /* (0,1,2,3)->(4,2,0,1) => (2,0,3,1) */ + check_orderarray(hwnd, 0x0123, 0x4201, 0x2031, TRUE, __LINE__); + /* (3,2,1,0)->(4,2,0,1) => (3,2,0,1) */ + check_orderarray(hwnd, 0x3210, 0x4201, 0x3201, FALSE, __LINE__); + + DestroyWindow(hwnd); +} + START_TEST(header) { HWND parent_hwnd; @@ -1700,6 +1820,7 @@ START_TEST(header)
test_header_control(); test_header_order(); + test_hdm_orderarray(); test_customdraw();
DestroyWindow(hHeaderParentWnd);