private void Initialize(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow, int itemCount)
 {
     if (columnPermutation != null)
     {
         column = columnPermutation.GetNativeColumn(column);
     }
     myColumn       = column;
     myColumnInTree = column;
     myStartRow     = startRow;
     myEndRow       = endRow;
     if (endRow < startRow &&
         endRow >= 0)
     {
         myCycle    = true;
         myLimitRow = itemCount - 1;
     }
     else
     {
         myCycle    = false;
         myLimitRow = (endRow < 0) ? itemCount - 1 : endRow;
     }
     myNextStartRow       = startRow;
     myCurrentRow         = startRow - 1;
     myCurrentRelativeRow = myFirstRelativeRow = myLastRelativeRow = myRelativeColumn = myTrailingBlanks = myLevel = 0;
     myIsSimpleCell       = false;
     myReturnBlankAnchors = returnBlankAnchors;
     myColumnPermutation  = columnPermutation;
     myBranch             = null;
 }
        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 VirtualTreeCoordinate GetNavigationTarget(
            TreeNavigation direction, int sourceRow, int sourceColumn, ColumnPermutation columnPermutation)
        {
            var targetRow = sourceRow;
            var targetColumn = sourceColumn;
            if (myRootNode == null)
            {
                return VirtualTreeCoordinate.Invalid;
            }
            var startColumn = sourceColumn;

            var retVal = false;
            var expansion = GetBlankExpansion(sourceRow, sourceColumn, columnPermutation);
            sourceRow = expansion.TopRow;
            var nativeSourceColumn = sourceColumn;
            if (expansion.AnchorColumn != VirtualTreeConstant.NullIndex)
            {
                sourceColumn = expansion.AnchorColumn;
            }
            if (columnPermutation != null)
            {
                nativeSourceColumn = columnPermutation.GetNativeColumn(sourceColumn);
            }

            var localColumn = nativeSourceColumn;
            var lastSubItem = false;
            var pos = TrackCell(sourceRow, ref localColumn, ref lastSubItem);
            TREENODE tnChild;
            var attemptNextColumn = false;
            int selectColumn;
            TREENODE tnParent = null;
            var rowOffset = 0;
            switch (direction)
            {
                case TreeNavigation.Parent:
                case TreeNavigation.ComplexParent:
                    if (localColumn == 0
                        &&
                        (pos.ParentAbsolute != -1 ||
                         (pos.ParentNode.SubItemRoot && !pos.ParentNode.ComplexSubItem)))
                    {
                        if (nativeSourceColumn > 0)
                        {
                            // This is more work than column zero. The parent
                            // absolute is relative to the root node in the branch.
                            targetRow = sourceRow - pos.ParentNode.GetChildOffset(pos.Index);
                        }
                        else
                        {
                            targetRow = pos.ParentAbsolute;
                        }
                        targetColumn = sourceColumn;
                        retVal = true;
                    }
                    else if (direction == TreeNavigation.ComplexParent)
                    {
                        if (pos.ParentNode.ComplexSubItem)
                        {
                            targetColumn = nativeSourceColumn - pos.ParentNode.Parent.FirstSubItem.ColumnOfRootNode(pos.ParentNode);
                            if ((columnPermutation == null)
                                || (-1 != (targetColumn = columnPermutation.GetPermutedColumn(targetColumn))))
                            {
                                targetRow = sourceRow - pos.ParentNode.GetChildOffset(pos.Index) + 1;
                                retVal = true;
                            }
                        }
                        else if (localColumn > 0)
                        {
                            targetColumn = nativeSourceColumn - localColumn;
                            if ((columnPermutation == null)
                                || (-1 != (targetColumn = columnPermutation.GetPermutedColumn(targetColumn))))
                            {
                                targetRow = sourceRow;
                                retVal = true;
                            }
                        }
                    }
                    break;
                case TreeNavigation.FirstChild:
                case TreeNavigation.LastChild:
                    // FirstChild and LastChild share code for testing if the node is expanded
                    tnChild = pos.ParentNode.GetChildNode(pos.Index);
                    if (localColumn > 0
                        && tnChild != null)
                    {
                        var sn = tnChild.SubItemAtColumn(localColumn);
                        tnChild = (sn == null) ? null : sn.RootNode;
                    }
                    if (tnChild != null
                        && tnChild.Expanded
                        && tnChild.ImmedCount > 0)
                    {
                        // Right jumps to FirstChild, test LastChild, not FirstChild, so
                        // else handles both elements.
                        if (direction == TreeNavigation.LastChild)
                        {
                            targetRow = sourceRow + tnChild.GetChildOffset(tnChild.ImmedCount - 1);
                        }
                        else
                        {
                            targetRow = sourceRow + tnChild.ImmedSubItemGain + 1;
                        }
                        targetColumn = sourceColumn;
                        retVal = true;
                    }
                    else if (attemptNextColumn)
                    {
                        goto case TreeNavigation.RightColumn;
                    }
                    break;
                case TreeNavigation.RightColumn:
                    {
                        // Move right to the next column. Note that this is not a natural
                        // thing to do from the tree perspective because the closest element
                        // to the right is likely to be only a distant relative of the current
                        // node, but the user is unlikely to appreciate this distinction and
                        // just wants to move right, so we let them.
                        if (nativeSourceColumn == 0
                            || localColumn > 0)
                        {
                            if (columnPermutation == null)
                            {
                                if (pos.ParentNode.GetColumnCount(pos.Index) > (localColumn + 1))
                                {
                                    targetRow = sourceRow;
                                    targetColumn = sourceColumn + 1;
                                    retVal = true;
                                }
                            }
                            else if (expansion.RightColumn < (columnPermutation.VisibleColumnCount - 1))
                            {
                                targetColumn = GetBlankExpansion(sourceRow, expansion.RightColumn + 1, columnPermutation).AnchorColumn;
                                targetRow = sourceRow;
                                retVal = true;
                            }
                        }
                        else
                        {
                            // Walk back up this tree until we get to a subitem root node, tracking
                            // offsets as we go.
                            tnParent = pos.ParentNode;
                            rowOffset = tnParent.GetChildOffset(pos.Index);
                            while (!tnParent.SubItemRoot)
                            {
                                tnChild = tnParent;
                                tnParent = tnChild.Parent;
                                rowOffset += tnParent.GetChildOffset(tnChild.Index);
                            }
                            if (tnParent.ComplexSubItem)
                            {
                                --rowOffset;
                            }
                            tnChild = tnParent;
                            tnParent = tnChild.Parent;

                            // Find the SUBITEMNODE for the next column and the next column
                            // index. The sub item node may be null if the next column is simple.
                            SUBITEMNODE snNext = null;
                            selectColumn = -1;
                            if (columnPermutation == null)
                            {
                                if (localColumn < (tnParent.Parent.GetColumnCount(tnParent.Index) - 1))
                                {
                                    var sn = tnParent.FirstSubItem;
                                    while (sn.RootNode != tnChild)
                                    {
                                        sn = sn.NextSibling;
                                    }
                                    var snTestNext = sn.NextSibling;
                                    if (snTestNext != null
                                        && (snTestNext.Column - sn.Column) == 1)
                                    {
                                        snNext = snTestNext;
                                    }
                                    selectColumn = sourceColumn + 1;
                                }
                            }
                            else
                            {
                                if (expansion.RightColumn < (columnPermutation.VisibleColumnCount - 1))
                                {
                                    selectColumn = GetBlankExpansion(sourceRow, expansion.RightColumn + 1, columnPermutation).AnchorColumn;
                                    // Note that column zero has no subitem node, so this covers this case
                                    // UNDONE_MC: Need local column, not global
                                    snNext = tnParent.SubItemAtColumn(columnPermutation.GetNativeColumn(selectColumn));
                                }
                            }

                            if (selectColumn != -1)
                            {
                                if (snNext != null)
                                {
                                    var nextGain = snNext.RootNode.TotalCount;
                                    if (snNext.RootNode.ComplexSubItem)
                                    {
                                        --nextGain;
                                    }
                                    else if (!snNext.RootNode.Expanded)
                                    {
                                        nextGain = 0;
                                    }
                                    if (nextGain < rowOffset)
                                    {
                                        targetRow = sourceRow - rowOffset + nextGain;
                                    }
                                    else
                                    {
                                        targetRow = sourceRow;
                                    }
                                }
                                else
                                {
                                    targetRow = sourceRow - rowOffset;
                                }
                                targetColumn = selectColumn;
                                retVal = true;
                            }
                        }
                        break;
                    }
                case TreeNavigation.NextSibling:
                    // Test localColumn. Expandable and simple cells don't have siblings,
                    // and all other nodes will give back a localColumn of 0.
                    if (localColumn == 0
                        && pos.Index < (pos.ParentNode.ImmedCount - 1))
                    {
                        targetRow = sourceRow + 1;
                        tnChild = pos.ParentNode.GetChildNode(pos.Index);
                        if (tnChild != null)
                        {
                            targetRow += tnChild.TotalCount;
                        }
                        targetColumn = sourceColumn;
                        retVal = true;
                    }
                    break;
                case TreeNavigation.PreviousSibling:
                    if (localColumn == 0
                        && pos.Index > 0)
                    {
                        if (pos.ParentNode.ComplexSubItem)
                        {
                            // The parent absolute is -1 and can't be used to give back a real count, 
                            // so use a more expensive algorithm in this case.
                            targetRow = sourceRow - pos.ParentNode.GetChildOffset(pos.Index) + pos.ParentNode.GetChildOffset(pos.Index - 1);
                        }
                        else
                        {
                            targetRow = pos.ParentAbsolute + pos.ParentNode.GetChildOffset(pos.Index - 1);
                        }
                        targetColumn = sourceColumn;
                        retVal = true;
                        break;
                    }
                    break;
                case TreeNavigation.Up:
                    while (targetRow > 0)
                    {
                        expansion = GetBlankExpansion(targetRow - 1, startColumn, columnPermutation);
                        targetRow = expansion.TopRow;
                        if (startColumn == expansion.AnchorColumn)
                        {
                            retVal = true;
                            break;
                        }
                    }
                    break;
                case TreeNavigation.Down:
                    while (expansion.BottomRow < (myRootNode.TotalCount - 1))
                    {
                        // Just return the next non-blank column
                        var testRow = expansion.BottomRow + 1;
                        expansion = GetBlankExpansion(testRow, startColumn, columnPermutation);
                        targetRow = expansion.TopRow;
                        if (startColumn == expansion.AnchorColumn
                            && targetRow >= testRow)
                        {
                            retVal = true;
                            break;
                        }
                    }
                    break;
                case TreeNavigation.LeftColumn:
                    if (localColumn > 0)
                    {
                        if (columnPermutation == null)
                        {
                            if (sourceColumn > 0)
                            {
                                targetRow = sourceRow;
                                targetColumn = sourceColumn - 1;
                                retVal = true;
                            }
                        }
                        else if (expansion.LeftColumn > 0)
                        {
                            targetRow = sourceRow;
                            targetColumn = GetBlankExpansion(targetRow, expansion.LeftColumn - 1, columnPermutation).AnchorColumn;
                            retVal = true;
                        }
                    }
                    else
                    {
                        // tnParent may have been set already in TreeNavigation.Left, only set it if needed
                        // Note that the nativeSourceColumn == 0 case can happen with a columnPermutation only
                        if (tnParent == null
                            && nativeSourceColumn != 0)
                        {
                            tnParent = pos.ParentNode;
                            rowOffset = tnParent.GetChildOffset(pos.Index);
                            while (!tnParent.SubItemRoot)
                            {
                                tnChild = tnParent;
                                tnParent = tnChild.Parent;
                                rowOffset += tnParent.GetChildOffset(tnChild.Index);
                            }
                            if (tnParent.ComplexSubItem)
                            {
                                --rowOffset;
                            }
                        }
                        selectColumn = -1;
                        SUBITEMNODE snPrev = null;
                        if (columnPermutation == null)
                        {
                            if (tnParent != null
                                && tnParent.Parent != null)
                            {
                                var sn = tnParent.Parent.FirstSubItem;
                                SUBITEMNODE snTestPrev = null;
                                while (sn.RootNode != tnParent)
                                {
                                    snTestPrev = sn;
                                    sn = sn.NextSibling;
                                }
                                if (snTestPrev != null
                                    && (sn.Column - snTestPrev.Column) == 1)
                                {
                                    snPrev = snTestPrev;
                                }
                            }
                            selectColumn = sourceColumn - 1;
                        }
                        else if (expansion.LeftColumn > 0)
                        {
                            selectColumn = GetBlankExpansion(sourceRow, expansion.LeftColumn - 1, columnPermutation).AnchorColumn;
                            if (tnParent != null)
                            {
                                // Note that column zero has no subitem node, so this covers this case
                                // UNDONE_MC: Need local column, not global
                                snPrev = tnParent.Parent.SubItemAtColumn(columnPermutation.GetNativeColumn(selectColumn));
                            }
                        }
                        if (selectColumn != -1)
                        {
                            targetColumn = selectColumn;
                            retVal = true;
                            if (snPrev == null)
                            {
                                // The previous column is the parent node or a simple cell. Move
                                // to that cell.
                                targetRow = sourceRow - rowOffset;
                            }
                            else
                            {
                                // The most closely related node to the left is the 0 node in the
                                // previous column. However, this node is not spatially closest
                                // to the current cell. The subtle the distinction that the closest
                                // cell is only a distant relative of the current one is generally lost
                                // on the user, so we just let them move left to the current value.
                                var prevGain = snPrev.RootNode.TotalCount;
                                if (snPrev.RootNode.ComplexSubItem)
                                {
                                    --prevGain;
                                }
                                else if (!snPrev.RootNode.Expanded)
                                {
                                    prevGain = 0;
                                }
                                if (prevGain < rowOffset)
                                {
                                    targetRow = sourceRow - rowOffset + prevGain;
                                }
                                else
                                {
                                    targetRow = sourceRow;
                                }
                            }
                        }
                    }
                    break;
                case TreeNavigation.Left:
                    if (sourceColumn > 0)
                    {
                        if (localColumn > 0
                            ||
                            (pos.Index == 0 && pos.ParentNode.ComplexSubItem))
                        {
                            // Move left one column
                            if (columnPermutation == null)
                            {
                                targetRow = sourceRow;
                                targetColumn = sourceColumn - 1;
                                retVal = true;
                            }
                            else if (expansion.LeftColumn > 0)
                            {
                                targetRow = sourceRow;
                                targetColumn = GetBlankExpansion(sourceRow, expansion.LeftColumn - 1, columnPermutation).AnchorColumn;
                                retVal = true;
                            }
                            break;
                        }
                        else if (pos.ParentNode.ComplexSubItem
                                 && pos.Index > 0)
                        {
                            tnParent = pos.ParentNode;
                            rowOffset = tnParent.GetChildOffset(pos.Index) - 1;
                            goto case TreeNavigation.LeftColumn;
                        }
                        else if (nativeSourceColumn == 0
                                 && pos.ParentNode.Index == -1)
                        {
                            goto case TreeNavigation.LeftColumn;
                        }
                    }
                    goto case TreeNavigation.Parent;
                case TreeNavigation.Right:
                    if (MultiColumnSupport)
                    {
                        if ((sourceColumn == 0)
                            ||
                            (pos.ParentNode.ComplexSubItem && pos.Index == 0)
                            ||
                            (localColumn > 0))
                        {
                            if (columnPermutation == null)
                            {
                                if (localColumn < (pos.ParentNode.GetColumnCount(pos.Index) - 1))
                                {
                                    targetRow = sourceRow;
                                    targetColumn = sourceColumn + 1;
                                    retVal = true;
                                    break;
                                }
                            }
                            else if (expansion.RightColumn < (columnPermutation.VisibleColumnCount - 1))
                            {
                                targetRow = sourceRow;
                                targetColumn = GetBlankExpansion(sourceRow, expansion.RightColumn + 1, columnPermutation).AnchorColumn;
                                retVal = true;
                                break;
                            }
                        }
                        else if (columnPermutation == null)
                        {
                            if (sourceColumn < (ColumnCount - 1))
                            {
                                // If firstchild doesn't go anywhere, then attempt
                                // to move to the next branch.
                                attemptNextColumn = true;
                            }
                        }
                        else if (expansion.RightColumn < (columnPermutation.VisibleColumnCount - 1))
                        {
                            attemptNextColumn = true;
                        }
                    }
                    goto case TreeNavigation.FirstChild;
            }
            return retVal ? new VirtualTreeCoordinate(targetRow, targetColumn) : VirtualTreeCoordinate.Invalid;
        }
        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);
            }
        }
 private void Initialize(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow, int itemCount)
 {
     if (columnPermutation != null)
     {
         column = columnPermutation.GetNativeColumn(column);
     }
     myColumn = column;
     myColumnInTree = column;
     myStartRow = startRow;
     myEndRow = endRow;
     if (endRow < startRow
         && endRow >= 0)
     {
         myCycle = true;
         myLimitRow = itemCount - 1;
     }
     else
     {
         myCycle = false;
         myLimitRow = (endRow < 0) ? itemCount - 1 : endRow;
     }
     myNextStartRow = startRow;
     myCurrentRow = startRow - 1;
     myCurrentRelativeRow = myFirstRelativeRow = myLastRelativeRow = myRelativeColumn = myTrailingBlanks = myLevel = 0;
     myIsSimpleCell = false;
     myReturnBlankAnchors = returnBlankAnchors;
     myColumnPermutation = columnPermutation;
     myBranch = null;
 }