Improved header control performance by maintaining an internal order
array.

diff --git a/dlls/comctl32/header.c b/dlls/comctl32/header.c
index ab3ebce..5ef8447 100644
--- a/dlls/comctl32/header.c
+++ b/dlls/comctl32/header.c
@@ -87,6 +87,7 @@
 
     HIMAGELIST  himl;		/* handle to an image list (may be 0) */
     HEADER_ITEM *items;		/* pointer to array of HEADER_ITEM's */
+    INT         *order;         /* array of item IDs indexed by order */
     BOOL	bRectsValid;	/* validity flag for bounding rectangles */
 } HEADER_INFO;
 
@@ -113,14 +114,10 @@
 {
     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
     INT iorder = (INT)wParam;
-    UINT i;
 
-    if ((iorder <0) || iorder >infoPtr->uNumItem)
+    if ((iorder <0) || iorder >= infoPtr->uNumItem)
       return iorder;
-    for (i=0; i<infoPtr->uNumItem; i++)
-      if (HEADER_IndexToOrder(hwnd,i) == iorder)
-	return i;
-    return iorder;
+    return infoPtr->order[iorder];
 }
 
 static void
@@ -647,16 +644,19 @@
         if (infoPtr->items[0].pszText)
             Free (infoPtr->items[0].pszText);
         Free (infoPtr->items);
+        Free(infoPtr->order);
         infoPtr->items = 0;
+        infoPtr->order = 0;
         infoPtr->uNumItem = 0;
     }
     else {
         HEADER_ITEM *oldItems = infoPtr->items;
-        HEADER_ITEM *pItem;
         INT i;
         INT iOrder;
         TRACE("Complex delete! [iItem=%d]\n", iItem);
 
+        for (i = 0; i < infoPtr->uNumItem; i++)
+           TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
         if (infoPtr->items[iItem].pszText)
             Free (infoPtr->items[iItem].pszText);
         iOrder = infoPtr->items[iItem].iOrder;
@@ -676,11 +676,21 @@
         }
 
         /* Correct the orders */
-        for (i=infoPtr->uNumItem, pItem = infoPtr->items; i; i--, pItem++)
+        if (iOrder < infoPtr->uNumItem)
         {
-            if (pItem->iOrder > iOrder)
-            pItem->iOrder--;
+            memmove(&infoPtr->order[iOrder], &infoPtr->order[iOrder + 1],
+                   (infoPtr->uNumItem - iOrder) * sizeof(INT));
+            for (i = 0; i < infoPtr->uNumItem; i++)
+            {
+                if (infoPtr->order[i] > iItem)
+                    infoPtr->order[i]--;
+                if (i >= iOrder)
+                    infoPtr->items[infoPtr->order[i]].iOrder = infoPtr->order[i];
+            }
         }
+
+        for (i = 0; i < infoPtr->uNumItem; i++)
+           TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
         Free (oldItems);
     }
 
@@ -850,14 +860,13 @@
 static LRESULT
 HEADER_GetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
-    int i;
     LPINT order = (LPINT) lParam;
     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
 
     if ((unsigned int)wParam <infoPtr->uNumItem)
       return FALSE;
-    for (i=0; i<(int)wParam; i++)
-      *order++=HEADER_OrderToIndex(hwnd,i);
+
+    memcpy(order, infoPtr->order, infoPtr->uNumItem * sizeof(INT));
     return TRUE;
 }
 
@@ -871,6 +880,7 @@
 
     if ((unsigned int)wParam <infoPtr->uNumItem)
       return FALSE;
+    memcpy(infoPtr->order, order, infoPtr->uNumItem * sizeof(INT));
     for (i=0; i<(int)wParam; i++)
       {
         lpItem = &infoPtr->items[*order++];
@@ -923,10 +933,12 @@
 
     if (infoPtr->uNumItem == 0) {
         infoPtr->items = Alloc (sizeof (HEADER_ITEM));
+        infoPtr->order = Alloc(sizeof(INT));
         infoPtr->uNumItem++;
     }
     else {
         HEADER_ITEM *oldItems = infoPtr->items;
+        INT *oldOrder = infoPtr->order;
 
         infoPtr->uNumItem++;
         infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
@@ -949,13 +961,21 @@
             }
         }
 
+        infoPtr->order = Alloc(sizeof(INT) * infoPtr->uNumItem);
+        memcpy(infoPtr->order, oldOrder, iOrder * sizeof(INT));
+        infoPtr->order[iOrder] = nItem;
+        memcpy(&infoPtr->order[iOrder + 1], &oldOrder[iOrder],
+               (infoPtr->uNumItem - iOrder - 1) * sizeof(INT));
+
         Free (oldItems);
+        Free(oldOrder);
     }
 
-    for (i=0; i < infoPtr->uNumItem; i++)
+    for (i = 0; i < infoPtr->uNumItem; i++)
     {
-        if (infoPtr->items[i].iOrder >= iOrder)
-            infoPtr->items[i].iOrder++;
+        if (i != iOrder && infoPtr->order[i] >= nItem)
+            infoPtr->order[i]++;
+        infoPtr->items[infoPtr->order[i]].iOrder = infoPtr->order[i];
     }
 
     lpItem = &infoPtr->items[nItem];
@@ -1025,10 +1045,12 @@
 
     if (infoPtr->uNumItem == 0) {
         infoPtr->items = Alloc (sizeof (HEADER_ITEM));
+        infoPtr->order = Alloc(sizeof(INT));
         infoPtr->uNumItem++;
     }
     else {
         HEADER_ITEM *oldItems = infoPtr->items;
+        INT *oldOrder = infoPtr->order;
 
         infoPtr->uNumItem++;
         infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
@@ -1051,13 +1073,21 @@
             }
         }
 
+        infoPtr->order = Alloc(infoPtr->uNumItem * sizeof(INT));
+        memcpy(infoPtr->order, oldOrder, iOrder * sizeof(INT));
+        infoPtr->order[iOrder] = nItem;
+        memcpy(&infoPtr->order[iOrder + 1], &oldOrder[iOrder],
+               (infoPtr->uNumItem - iOrder - 1) * sizeof(INT));
+
         Free (oldItems);
+        Free(oldOrder);
     }
 
-    for (i=0; i < infoPtr->uNumItem; i++)
+    for (i = 0; i < infoPtr->uNumItem; i++)
     {
-        if (infoPtr->items[i].iOrder >= iOrder)
-            infoPtr->items[i].iOrder++;
+        if (i != iOrder && infoPtr->order[i] >= nItem)
+            infoPtr->order[i]++;
+        infoPtr->items[infoPtr->order[i]].iOrder = infoPtr->order[i];
     }
 
     lpItem = &infoPtr->items[nItem];
@@ -1224,7 +1254,27 @@
 
     if (phdi->mask & HDI_ORDER)
       {
-	lpItem->iOrder = phdi->iOrder;
+        INT i, nMin, nMax;
+        
+        if (lpItem->iOrder < phdi->iOrder)
+        {
+            memmove(&infoPtr->order[lpItem->iOrder],
+                   &infoPtr->order[lpItem->iOrder + 1],
+                   (phdi->iOrder - lpItem->iOrder) * sizeof(INT));
+        }
+        if (phdi->iOrder < lpItem->iOrder)
+        {
+            memmove(&infoPtr->order[phdi->iOrder + 1],
+                    &infoPtr->order[phdi->iOrder],
+                    (lpItem->iOrder - phdi->iOrder) * sizeof(INT));
+        }
+        infoPtr->order[phdi->iOrder] = nItem;
+        nMin = min(lpItem->iOrder, phdi->iOrder);
+        nMax = max(lpItem->iOrder, phdi->iOrder);
+        for (i = nMin; i <= nMax; i++)
+        {
+            infoPtr->items[infoPtr->order[i]].iOrder = infoPtr->order[i];
+        }
       }
 
     HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGEDA, nItem, phdi->mask);
@@ -1289,7 +1339,27 @@
 
     if (phdi->mask & HDI_ORDER)
       {
-	lpItem->iOrder = phdi->iOrder;
+        INT i, nMin, nMax;
+        
+        if (lpItem->iOrder < phdi->iOrder)
+        {
+            memmove(&infoPtr->order[lpItem->iOrder],
+                   &infoPtr->order[lpItem->iOrder + 1],
+                   (phdi->iOrder - lpItem->iOrder) * sizeof(INT));
+        }
+        if (phdi->iOrder < lpItem->iOrder)
+        {
+            memmove(&infoPtr->order[phdi->iOrder + 1],
+                    &infoPtr->order[phdi->iOrder],
+                    (lpItem->iOrder - phdi->iOrder) * sizeof(INT));
+        }
+        infoPtr->order[phdi->iOrder] = nItem;
+        nMin = min(lpItem->iOrder, phdi->iOrder);
+        nMax = max(lpItem->iOrder, phdi->iOrder);
+        for (i = nMin; i <= nMax; i++)
+        {
+            infoPtr->items[infoPtr->order[i]].iOrder = infoPtr->order[i];
+        }
       }
 
     HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDW, nItem, phdi->mask);
@@ -1328,6 +1398,7 @@
     infoPtr->uNumItem = 0;
     infoPtr->hFont = 0;
     infoPtr->items = 0;
+    infoPtr->order = 0;
     infoPtr->bRectsValid = FALSE;
     infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
     infoPtr->hcurDivider = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDER));
@@ -1372,6 +1443,9 @@
         Free (infoPtr->items);
     }
 
+    if (infoPtr->order)
+        Free(infoPtr->order);
+
     if (infoPtr->himl)
 	ImageList_Destroy (infoPtr->himl);
 
@@ -1505,6 +1579,9 @@
             lpItem= &infoPtr->items[infoPtr->iMoveItem];
 	    lpItem->iOrder = newindex;
 
+            infoPtr->order[oldindex] = nItem;
+            infoPtr->order[newindex] = infoPtr->iMoveItem;
+
 	    infoPtr->bRectsValid = FALSE;
 	    InvalidateRect(hwnd, NULL, FALSE);
 	    /* FIXME: Should some WM_NOTIFY be sent */