Module: wine Branch: master Commit: 67c57b216c734a7133088bb097f436bc0e0ca743 URL: http://source.winehq.org/git/wine.git/?a=commit;h=67c57b216c734a7133088bb097...
Author: Nikolay Sivov nsivov@codeweavers.com Date: Thu Jan 3 15:29:39 2013 +0400
comctl32/listview: Improve LVM_GETSUBITEMRECT implementation for out-of-bounds item indices.
---
dlls/comctl32/listview.c | 79 +++++++++++++++++++--------------------- dlls/comctl32/tests/listview.c | 46 ++++++++++++++++++++++- 2 files changed, 82 insertions(+), 43 deletions(-)
diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index cf7cc6d..977bb18 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -6,7 +6,7 @@ * Copyright 2000 Jason Mawdsley * Copyright 2001 CodeWeavers Inc. * Copyright 2002 Dimitrie O. Paun - * Copyright 2009-2012 Nikolay Sivov + * Copyright 2009-2013 Nikolay Sivov * Copyright 2009 Owen Rudge for CodeWeavers * * 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, HDPA hdpaSubItems; 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) return FALSE; @@ -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, * not only those of the first column. - * Fortunately, LISTVIEW_GetItemMetrics does the right thing. * * RETURN: * TRUE: success * 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; - LVITEMW lvItem; - INT nColumn; + RECT rect = { 0, 0, 0, 0 }; + POINT origin; + INT y;
if (!lprc) return FALSE;
- nColumn = lprc->top; - - TRACE("(nItem=%d, nSubItem=%d, type=%d)\n", nItem, lprc->top, lprc->left); - /* On WinNT, a subitem of '0' calls LISTVIEW_GetItemRect */ + 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 */ if (lprc->top == 0) - return LISTVIEW_GetItemRect(infoPtr, nItem, lprc); + return LISTVIEW_GetItemRect(infoPtr, item, lprc);
if (infoPtr->uView != LV_VIEW_DETAILS) return FALSE;
- /* special case for header items */ - if (nItem == -1) - { - if (lprc->left != LVIR_BOUNDS) - { - FIXME("Only LVIR_BOUNDS is implemented for header, got %d\n", lprc->left); - return FALSE; - } + LISTVIEW_GetOrigin(infoPtr, &origin); + /* this works for any item index, no matter if it exists or not */ + y = item * infoPtr->nItemHeight + origin.y;
- if (infoPtr->hwndHeader) - return SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, lprc->top, (LPARAM)lprc); - else - { - memset(lprc, 0, sizeof(RECT)); - return TRUE; - } + if (infoPtr->hwndHeader && SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, lprc->top, (LPARAM)&rect)) + { + rect.top = 0; + rect.bottom = infoPtr->nItemHeight; + } + 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; - 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) + switch (lprc->left) { 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_BOUNDS: - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL, NULL); break;
default: @@ -7093,7 +7089,8 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR return FALSE; }
- OffsetRect(lprc, Origin.x, Position.y); + OffsetRect(&rect, origin.x, y); + *lprc = rect; TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
return TRUE; diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c index 0dfddef..0620afe 100644 --- a/dlls/comctl32/tests/listview.c +++ b/dlls/comctl32/tests/listview.c @@ -247,6 +247,18 @@ static const struct message getitemposition_seq2[] = { { 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[] = { /* sequence sent after LVN_BEGINLABELEDIT */ /* next two are 4.7x specific */ @@ -1602,6 +1614,8 @@ static void test_create(void) rect.top = 1; rect.right = rect.bottom = -10; 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);
hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); @@ -2473,6 +2487,36 @@ todo_wine
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);
/* test subitem rects after re-arranging columns */ @@ -2514,13 +2558,11 @@ todo_wine rect2.top = 1; rect2.right = rect2.bottom = -1; r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2); -todo_wine { expect(TRUE, r); expect(rect.right, rect2.right); expect(rect.left, rect2.left); expect(rect.bottom, rect2.top); ok(rect2.bottom > rect2.top, "expected not zero height\n"); -}
arr[0] = 1; arr[1] = 0; arr[2] = 2; r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);