/// <remarks>
        /// If the provided area is large enough, the lower part of the area is partitioned to host the row and the
        /// lower bound of the area moves upwards. When the area becomes empty, it is removed from the chain of
        /// unpartitioned areas to avoid spending time on it during future allocations.
        /// </remarks>
        private bool TryPartitionArea(AreaNode areaNode, int rowIndex, int rowHeight, int minWidth)
        {
            RectInt area = areaNode.rect;

            if (area.height < rowHeight || area.width < minWidth)
            {
                return(false);
            }

            var row = m_OpenRows[rowIndex];

            if (row != null)
            {
                row.Release();
            }
            row = Row.Acquire(area.x, area.y, area.width, rowHeight);
            m_OpenRows[rowIndex] = row;
            area.y      += rowHeight;
            area.height -= rowHeight;

            if (area.height == 0)
            {
                if (areaNode == m_FirstUnpartitionedArea)
                {
                    m_FirstUnpartitionedArea = areaNode.next;
                }
                areaNode.RemoveFromChain();
                areaNode.Release();
            }
            else
            {
                areaNode.rect = area;
            }
            return(true);
        }