private void EnumOrderedListItems(
            ref int nextStartRow,
            int column,
            ColumnPermutation permutation,
            bool returnBlankAnchors,
            out IBranch branch,
            out int treeColumn,
            out int firstRelativeRow,
            out int lastRelativeRow,
            out int relativeColumn,
            out int level,
            out int trailingBlanks,
            out bool simpleCell)
        {
            trailingBlanks = 0;
            relativeColumn = column;
            treeColumn = column;
            var pos = TrackCell(nextStartRow, ref relativeColumn);
            TREENODE tn;
            var columnCount = 0;
            var tnParent = pos.ParentNode;
            level = pos.Level;
            var processItem = true;
            var verifyColumnCount = false;
            if (pos.IsBlank(relativeColumn))
            {
                // We're currently in a blank cell. Determine the next non-blank cell in this column
                // unless we've been asked to return the blank expansions.
                columnCount = tnParent.GetColumnCount(pos.Index);
                if (relativeColumn >= columnCount)
                {
                    tn = null;
                    if (returnBlankAnchors)
                    {
                        // For returning blank anchors, we need to see if we're within
                        // the range of rows supported by the last column in this row that
                        // has items.
                        if (permutation != null)
                        {
                            var expansion = permutation.GetColumnExpansion(
                                permutation.GetPermutedColumn(relativeColumn), columnCount - 1
                                /*UNDONE_MC: Column count local, not global, relativeColumn local, not global*/);
                            if (expansion.AnchorColumn == VirtualTreeConstant.NullIndex)
                            {
                                processItem = false;
                            }
                            else
                            {
                                // UNDONE_MC: Global and relative not the same
                                relativeColumn = treeColumn = permutation.GetNativeColumn(expansion.AnchorColumn);
                            }
                        }
                        else
                        {
                            // UNDONE_MC: Global and relative not the same
                            relativeColumn = treeColumn = columnCount - 1;
                        }
                        if (processItem)
                        {
                            pos = TrackCell(nextStartRow, ref relativeColumn);
                            if (pos.IsBlank(relativeColumn))
                            {
                                processItem = false;
                            }
                            else
                            {
                                tnParent = pos.ParentNode;
                                level = pos.Level;
                                verifyColumnCount = tnParent.JaggedColumns;
                            }
                        }
                    }
                    else
                    {
                        processItem = false;
                    }
                    if (!processItem)
                    {
                        // This isn't perfect, but a call to GetBlankExpansion is unlikely to give better information,
                        // so we just move one at a time. Moving one row at a time is relatively harmless here and shouldn't
                        // cause any sort of noticeable performance hit.
                        level = -1;
                        if ((tnParent.ExpandedSubItemGain != 0)
                            && (null != (tn = tnParent.GetChildNode(pos.Index))))
                        {
                            // If there is a reason to check, then go looking for the full subitem gain
                            // of a child at this node.
                            trailingBlanks = tn.ImmedSubItemGain - pos.SubItemOffset + 1; // Include this item in the blank count
                            nextStartRow += trailingBlanks;
                        }
                        else
                        {
                            trailingBlanks = 1; // Ask the next item
                            ++nextStartRow;
                        }
                    }
                }
                else
                {
                    processItem = false;
                    tn = tnParent.GetChildNode(pos.Index);
                    if (relativeColumn != 0)
                    {
                        // Be consistent with GetItemInfo
                        level = -1;
                    }
                    trailingBlanks = tn.ImmedSubItemGain - pos.SubItemOffset + 1; // Include this item in the blank count
                    nextStartRow += trailingBlanks;
                }
                if (nextStartRow >= myRootNode.TotalCount)
                {
                    nextStartRow = VirtualTreeConstant.NullIndex;
                }
            }
            if (processItem)
            {
                lastRelativeRow = tnParent.ImmedCount - 1; // Default value if nothing else found
                branch = tnParent.Branch;
                firstRelativeRow = pos.Index;
                int subItemGain;
                var totalSubItemGain = 0;
                trailingBlanks = 0;
                var lastVerifiedColumnCount = pos.Index;
                for (tn = tnParent.FirstChild; tn != null; tn = tn.NextSibling)
                {
                    if (pos.Index <= tn.Index)
                    {
                        for (; tn != null; tn = tn.NextSibling)
                        {
                            if (verifyColumnCount)
                            {
                                // In this case, we only want to use columns with
                                // the current column count. This prevents requests with
                                // returnBlankAnchors true from attaching to an anchor in
                                // the same column.
                                var testIndex = tn.Index;
                                for (var i = lastVerifiedColumnCount + 1; i <= testIndex; ++i)
                                {
                                    if (tnParent.GetColumnCount(i) != columnCount)
                                    {
                                        lastRelativeRow = lastVerifiedColumnCount = i - 1;
                                        testIndex = -1;
                                        break;
                                    }
                                }
                                if (testIndex == -1)
                                {
                                    tn = null;
                                    break;
                                }
                                lastVerifiedColumnCount = testIndex;
                            }
                            subItemGain = tn.ImmedSubItemGain;
                            if ((tn.Expanded && tn.ImmedCount > 0)
                                || (subItemGain > 0))
                            {
                                lastRelativeRow = tn.Index;
                                trailingBlanks = subItemGain;
                                break;
                            }
                            totalSubItemGain += subItemGain;
                        }
                        break;
                    }
                }

                if (verifyColumnCount && lastVerifiedColumnCount < lastRelativeRow)
                {
                    for (var i = lastVerifiedColumnCount + 1; i <= lastRelativeRow; ++i)
                    {
                        if (tnParent.GetColumnCount(i) != columnCount)
                        {
                            lastRelativeRow = i - 1;
                            break;
                        }
                    }
                }

                nextStartRow += lastRelativeRow - firstRelativeRow + totalSubItemGain + 1;
                if (tn != null)
                {
                    nextStartRow += tn.ImmedSubItemGain; // Undo later if not correct
                    if (relativeColumn != 0)
                    {
                        // Don't pretest SubItemStyle, can't tell if we got a complex or expanded node
                        var sn = tn.SubItemAtColumn(relativeColumn);
                        if (sn != null)
                        {
                            var subItemRoot = sn.RootNode;
                            if (!subItemRoot.ComplexSubItem
                                && subItemRoot.Expanded
                                && subItemRoot.TotalCount > 0)
                            {
                                // We went too far, undo
                                nextStartRow -= tn.ImmedSubItemGain;
                            }
                        }
                    }
                }
                // See if we're looking at a simple cell. This extra
                // information is needed by ComputeWidthOfRange on the
                // control side to get an accurate width, so we need to
                // be consistent with GetItemInfo here.
                if (level == 0 && MultiColumnSupport)
                {
                    if (!tnParent.MultiColumn)
                    {
                        simpleCell = tnParent.InSubItemColumn && tnParent.NoChildExpansion;
                    }
                    else if (column == 0)
                    {
                        simpleCell = tnParent.NoChildExpansion;
                    }
                    else
                    {
                        simpleCell = !(pos.IsExpanded(column) || pos.IsExpandable(column));
                    }
                }
                else
                {
                    simpleCell = false;
                }

                Debug.Assert(nextStartRow <= myRootNode.TotalCount, "Off end of list");
                if (nextStartRow == myRootNode.TotalCount) // == instead of >= OK with assert
                {
                    nextStartRow = VirtualTreeConstant.NullIndex;
                }
            }
            else
            {
                branch = null;
                simpleCell = false;
                firstRelativeRow = lastRelativeRow = VirtualTreeConstant.NullIndex;
            }
        }
        protected BlankExpansionData GetBlankExpansion(int row, int column, ColumnPermutation columnPermutation)
        {
            if (!MultiColumnSupport)
            {
                // There is no way to get blank cells in a single-column tree
                return new BlankExpansionData(row, column);
            }
            else if (columnPermutation != null)
            {
                var permutedColumns = columnPermutation.GetColumnExpansion(column, ColumnWidthOfRow(row) - 1);
                // The consumer should not let the user do this but we need to handle it gracefully.
                // Make sure we have a row count by pulling the native row count from row 0 if the
                // row is fully blank, and from the native permutation column if it is not.
                var nativeData = GetBlankExpansion(
                    row,
                    (permutedColumns.AnchorColumn == VirtualTreeConstant.NullIndex)
                        ? 0
                        : columnPermutation.GetNativeColumn(permutedColumns.AnchorColumn), null);
                // Get the row data from the native expansion and combine with the columns from
                // the permuted expansion.
                return new BlankExpansionData(
                    nativeData.TopRow, permutedColumns.LeftColumn, nativeData.BottomRow, permutedColumns.RightColumn,
                    permutedColumns.AnchorColumn);
            }
            else
            {
                int topRow;
                int leftColumn;
                int bottomRow;
                int rightColumn;
                topRow = bottomRow = row;
                leftColumn = rightColumn = column;
                var localColumn = column;
                var lastSubItem = false;
                var pos = TrackCell(row, ref localColumn, ref lastSubItem);

                // Check the column range
                var lastNonBlankColumn = pos.ParentNode.GetColumnCount(pos.Index) - 1;
                var columnDiff = lastNonBlankColumn - localColumn;
                var localColumnAdjusted = false;
                var rowPadding = 0;
                if (columnDiff <= 0)
                {
                    // Unfortunately, there is no easy check to see if we should apply this
                    // column expansion or not. It should only be supplied if the node is a
                    // child of either a complex sub item or the root node, not in other case.
                    var tn = pos.ParentNode;
                    var nextIndex = pos.Index;
                    var onLastItem = tn.InSubItemColumn;
                    while (tn != null)
                    {
                        if (onLastItem)
                        {
                            // While we're walking the loop, see if we're on the last cell
                            if (nextIndex < (tn.FullCount - 1))
                            {
                                onLastItem = false;
                            }
                            else
                            {
                                nextIndex = tn.Index;
                            }
                        }
                        if (tn.SubItemRoot)
                        {
                            if (tn.MultiColumn)
                            {
                                // UNDONE_MC: Not sure about this one
                                tn = null;
                            }
                            else
                            {
                                // We're looking at an expandable subitem. If this is in
                                // the last column, then we need to expand to its right and treat
                                // the parent node as the real owner. We're also in a perfect position
                                // to see if we need extra row padding at the end.
                                var subitemOwner = tn.Parent;
                                if (onLastItem)
                                {
                                    rowPadding = subitemOwner.ImmedSubItemGain - tn.FullCount;
                                    if (tn.ComplexSubItem)
                                    {
                                        ++rowPadding;
                                    }
                                }
                                lastNonBlankColumn = subitemOwner.Parent.GetColumnCount(subitemOwner.Index) - 1;
                                columnDiff = lastNonBlankColumn - subitemOwner.FirstSubItem.ColumnOfRootNode(tn);
                                if (columnDiff <= 0)
                                {
                                    tn = null;
                                }
                            }
                            break;
                        }
                        tn = tn.Parent;
                    }
                    if (tn == null)
                    {
                        if (!pos.ParentNode.InSubItemColumn)
                        {
                            localColumn += columnDiff;
                            localColumnAdjusted = true;
                        }
                        leftColumn += columnDiff;
                        rightColumn = ColumnCount - 1;
                    }
                }

                // Check the row range. Note that this does not depend on the column,
                // any column in the given column range provides the same answer.
                var tnChild = pos.ParentNode.GetChildNode(pos.Index);
                if (localColumn > 0
                    && tnChild != null)
                {
                    var sn = tnChild.SubItemAtColumn(localColumn);
                    var tnSubItemRoot = (sn == null) ? null : sn.RootNode;
                    Debug.Assert(tnChild == null || !tnChild.ComplexSubItem); // A complex subitem should track to column 0
                    if (tnSubItemRoot != null
                        && tnSubItemRoot.Expanded
                        && tnSubItemRoot.FullCount > 0)
                    {
                        if (localColumnAdjusted)
                        {
                            // We are in a region with subitems, but we hit to the
                            // right of the last column, which happens to be expanded.
                            var lastRowInCell = tnSubItemRoot.FullCount;
                            if (tnSubItemRoot.ComplexSubItem)
                            {
                                --lastRowInCell;
                            }

                            // If the item is on or after
                            if (pos.SubItemOffset >= lastRowInCell)
                            {
                                topRow -= pos.SubItemOffset;
                                bottomRow = topRow + tnChild.ImmedSubItemGain;
                                topRow += lastRowInCell;
                            }
                            tnChild = null;
                        }
                        else
                        {
                            if (pos.SubItemOffset > 0)
                            {
                                topRow -= pos.SubItemOffset;
                                bottomRow = topRow + tnChild.ImmedSubItemGain;
                                // UNDONE_MC: This doesn't handle a multicolumn complex column
                                topRow += tnSubItemRoot.FullCount;
                                if (tnSubItemRoot.ComplexSubItem)
                                {
                                    --topRow;
                                }
                                tnChild = null;
                            }
                        }
                    }
                }
                if (tnChild != null)
                {
                    if (pos.SubItemOffset > 0)
                    {
                        topRow -= pos.SubItemOffset;
                        bottomRow = topRow + tnChild.ImmedSubItemGain;
                    }
                    else
                    {
                        bottomRow += tnChild.ImmedSubItemGain;
                    }
                }
                if (rowPadding != 0)
                {
                    bottomRow += rowPadding;
                }

                return new BlankExpansionData(topRow, leftColumn, bottomRow, rightColumn, leftColumn);
            }
        }