Commit 67c57b21 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

comctl32/listview: Improve LVM_GETSUBITEMRECT implementation for out-of-bounds item indices.

parent 3046a2cb
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright 2000 Jason Mawdsley * Copyright 2000 Jason Mawdsley
* Copyright 2001 CodeWeavers Inc. * Copyright 2001 CodeWeavers Inc.
* Copyright 2002 Dimitrie O. Paun * Copyright 2002 Dimitrie O. Paun
* Copyright 2009-2012 Nikolay Sivov * Copyright 2009-2013 Nikolay Sivov
* Copyright 2009 Owen Rudge for CodeWeavers * Copyright 2009 Owen Rudge for CodeWeavers
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
...@@ -6536,7 +6536,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, ...@@ -6536,7 +6536,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
HDPA hdpaSubItems; HDPA hdpaSubItems;
INT isubitem; INT isubitem;
TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount) if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
return FALSE; return FALSE;
...@@ -7027,65 +7027,61 @@ static BOOL LISTVIEW_GetItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT ...@@ -7027,65 +7027,61 @@ static BOOL LISTVIEW_GetItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT
* *
* NOTE: for subItem = 0, we should return the bounds of the _entire_ item, * NOTE: for subItem = 0, we should return the bounds of the _entire_ item,
* not only those of the first column. * not only those of the first column.
* Fortunately, LISTVIEW_GetItemMetrics does the right thing.
* *
* RETURN: * RETURN:
* TRUE: success * TRUE: success
* FALSE: failure * FALSE: failure
*/ */
static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc) static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT item, LPRECT lprc)
{ {
POINT Position, Origin; RECT rect = { 0, 0, 0, 0 };
LVITEMW lvItem; POINT origin;
INT nColumn; INT y;
if (!lprc) return FALSE; if (!lprc) return FALSE;
nColumn = lprc->top; TRACE("(item=%d, subitem=%d, type=%d)\n", item, lprc->top, lprc->left);
/* Subitem of '0' means item itself, and this works for all control view modes */
TRACE("(nItem=%d, nSubItem=%d, type=%d)\n", nItem, lprc->top, lprc->left);
/* On WinNT, a subitem of '0' calls LISTVIEW_GetItemRect */
if (lprc->top == 0) if (lprc->top == 0)
return LISTVIEW_GetItemRect(infoPtr, nItem, lprc); return LISTVIEW_GetItemRect(infoPtr, item, lprc);
if (infoPtr->uView != LV_VIEW_DETAILS) return FALSE; if (infoPtr->uView != LV_VIEW_DETAILS) return FALSE;
/* special case for header items */ LISTVIEW_GetOrigin(infoPtr, &origin);
if (nItem == -1) /* this works for any item index, no matter if it exists or not */
{ y = item * infoPtr->nItemHeight + origin.y;
if (lprc->left != LVIR_BOUNDS)
{
FIXME("Only LVIR_BOUNDS is implemented for header, got %d\n", lprc->left);
return FALSE;
}
if (infoPtr->hwndHeader) if (infoPtr->hwndHeader && SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, lprc->top, (LPARAM)&rect))
return SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, lprc->top, (LPARAM)lprc); {
else rect.top = 0;
{ rect.bottom = infoPtr->nItemHeight;
memset(lprc, 0, sizeof(RECT)); }
return TRUE; else
} {
/* Native implementation is broken for this case and garbage is left for left and right fields,
we zero them to get predictable output */
lprc->left = lprc->right = lprc->top = 0;
lprc->bottom = infoPtr->nItemHeight;
OffsetRect(lprc, origin.x, y);
TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
return TRUE;
} }
if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &Position)) return FALSE; switch (lprc->left)
LISTVIEW_GetOrigin(infoPtr, &Origin);
if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
lvItem.mask = 0;
lvItem.iItem = nItem;
lvItem.iSubItem = nColumn;
switch(lprc->left)
{ {
case LVIR_ICON: case LVIR_ICON:
LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL, NULL); {
break; /* it doesn't matter if main item actually has an icon, if imagelist is set icon width is returned */
if (infoPtr->himlSmall)
rect.right = rect.left + infoPtr->iconSize.cx;
else
rect.right = rect.left;
rect.bottom = rect.top + infoPtr->iconSize.cy;
break;
}
case LVIR_LABEL: case LVIR_LABEL:
case LVIR_BOUNDS: case LVIR_BOUNDS:
LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL, NULL);
break; break;
default: default:
...@@ -7093,7 +7089,8 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR ...@@ -7093,7 +7089,8 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
return FALSE; return FALSE;
} }
OffsetRect(lprc, Origin.x, Position.y); OffsetRect(&rect, origin.x, y);
*lprc = rect;
TRACE("return rect %s\n", wine_dbgstr_rect(lprc)); TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
return TRUE; return TRUE;
......
...@@ -247,6 +247,18 @@ static const struct message getitemposition_seq2[] = { ...@@ -247,6 +247,18 @@ static const struct message getitemposition_seq2[] = {
{ 0 } { 0 }
}; };
static const struct message getsubitemrect_seq[] = {
{ LVM_GETSUBITEMRECT, sent|id|wparam, -1, 0, LISTVIEW_ID },
{ HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
{ LVM_GETSUBITEMRECT, sent|id|wparam, 0, 0, LISTVIEW_ID },
{ HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
{ LVM_GETSUBITEMRECT, sent|id|wparam, -10, 0, LISTVIEW_ID },
{ HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
{ LVM_GETSUBITEMRECT, sent|id|wparam, 20, 0, LISTVIEW_ID },
{ HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
{ 0 }
};
static const struct message editbox_create_pos[] = { static const struct message editbox_create_pos[] = {
/* sequence sent after LVN_BEGINLABELEDIT */ /* sequence sent after LVN_BEGINLABELEDIT */
/* next two are 4.7x specific */ /* next two are 4.7x specific */
...@@ -1602,6 +1614,8 @@ static void test_create(void) ...@@ -1602,6 +1614,8 @@ static void test_create(void)
rect.top = 1; rect.top = 1;
rect.right = rect.bottom = -10; rect.right = rect.bottom = -10;
r = SendMessage(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect); r = SendMessage(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
/* right value contains garbage, probably because header columns are not set up */
expect(0, rect.bottom);
expect(1, r); expect(1, r);
hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
...@@ -2473,6 +2487,36 @@ todo_wine ...@@ -2473,6 +2487,36 @@ todo_wine
SendMessage(hwnd, LVM_SCROLL, -10, 0); SendMessage(hwnd, LVM_SCROLL, -10, 0);
/* test header interaction */
subclass_header(hwnd);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
rect.left = LVIR_BOUNDS;
rect.top = 1;
rect.right = rect.bottom = 0;
r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
expect(1, r);
rect.left = LVIR_BOUNDS;
rect.top = 1;
rect.right = rect.bottom = 0;
r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
expect(1, r);
rect.left = LVIR_BOUNDS;
rect.top = 1;
rect.right = rect.bottom = 0;
r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
expect(1, r);
rect.left = LVIR_BOUNDS;
rect.top = 1;
rect.right = rect.bottom = 0;
r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
expect(1, r);
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
DestroyWindow(hwnd); DestroyWindow(hwnd);
/* test subitem rects after re-arranging columns */ /* test subitem rects after re-arranging columns */
...@@ -2514,13 +2558,11 @@ todo_wine ...@@ -2514,13 +2558,11 @@ todo_wine
rect2.top = 1; rect2.top = 1;
rect2.right = rect2.bottom = -1; rect2.right = rect2.bottom = -1;
r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2); r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
todo_wine {
expect(TRUE, r); expect(TRUE, r);
expect(rect.right, rect2.right); expect(rect.right, rect2.right);
expect(rect.left, rect2.left); expect(rect.left, rect2.left);
expect(rect.bottom, rect2.top); expect(rect.bottom, rect2.top);
ok(rect2.bottom > rect2.top, "expected not zero height\n"); ok(rect2.bottom > rect2.top, "expected not zero height\n");
}
arr[0] = 1; arr[1] = 0; arr[2] = 2; arr[0] = 1; arr[1] = 0; arr[2] = 2;
r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr); r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment