sysperfana/heapanalyser/Libraries/UI/HeapCtrlLib/Utilities/HeapCellMetaData.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Tue, 15 Jun 2010 12:47:20 +0300
changeset 8 15296fd0af4a
permissions -rw-r--r--
HeapAnalyser 1.1.0

/*
* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
*   this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
*   this list of conditions and the following disclaimer in the documentation
*   and/or other materials provided with the distribution.
* - Neither the name of Nokia Corporation nor the names of its contributors
*   may be used to endorse or promote products derived from this software
*   without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* 
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

using System;
using System.Drawing;
using HeapLib.Cells;
using SymbianUtils.RawItems;

namespace HeapCtrlLib.Utilities
{
    public class HeapCellMetaData
    {
        #region Constructors & destructor
        public HeapCellMetaData( HeapRenderingNavigator aNavigator )
        {
            aNavigator.iNavBegin += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavBegin( Navigator_NavBegin );
            aNavigator.iNavEnd += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavEnd( Navigator_NavEnd );
            aNavigator.iNavHeapCellBegin += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavHeapCellBegin( Navigator_NavHeapCellBegin );
            aNavigator.iNavHeapCellEnd += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavHeapCellEnd( Navigator_NavHeapCellEnd );
            aNavigator.iNavNewColumn += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavNewColumn( Navigator_NavNewColumn );
            aNavigator.iNavNewRowBody += new HeapCtrlLib.Utilities.HeapRenderingNavigator.NavNewRowBody( Navigator_NavNewRowBody );
        }
        #endregion

        #region Properties
        public Point BoxCoordinates
        {
            get { return iBoxCoordinates; }
            set { iBoxCoordinates = value; }
        }

        public int RemainingBoxes
        {
            get { return iRemainingBoxes; }
            set { iRemainingBoxes = value; }
        }

        public int RemainingBoxesAfterThisRow
        {
            get { return iRemainingBoxesAfterThisRow; }
            set { iRemainingBoxesAfterThisRow = value; }
        }

        public int RemainingRows
        {
            get { return iRemainingRows; }
            set { iRemainingRows = value; }
        }

        public long RemainingBytes
        {
            get { return iRemainingBytes; }
            set { iRemainingBytes = value; }
        }

        public int CellBoxIndex
        {
            get { return iCellBoxIndex; }
            set { iCellBoxIndex = value; }
        }

        public int CellRowIndex
        {
            get { return iCellRowIndex; }
            set { iCellRowIndex = value; }
        }

        public int CellBoxCount
        {
            get { return iCellBoxCount; }
            set { iCellBoxCount = value; }
        }

        public RawItem RawItem
        {
            get { return iRawItem; }
        }

        public HeapCell.TRegion Region
        {
            get
            {
                System.Diagnostics.Debug.Assert( iCell != null, "Not rendering a heap cell" );
                System.Diagnostics.Debug.Assert( iAddress > 0, "Invalid current address" );
                //
                HeapCell.TRegion region = iCell.RegionForAddress( iAddress );
                return region;
            }
        }

        public HeapCellBorderInfo Borders
        {
            get { return iBorders; }
            set { iBorders = value; }
        }

        // Set by the content renderer, read by the border renderer
        public Color CellBoxColor
        {
            get { return iCellBoxColor; }
            set { iCellBoxColor = value; }
        }
        #endregion

        #region Internal methods
        private void CalculateBorders( HeapCell aCell, long aAddress, Size aDimensions )
        {
            long remainingBoxes = ( aCell.EndAddress - aAddress ) / SymbianUtils.RawItems.RawItem.KSizeOfOneRawItemInBytes;

            // Start with no borders
            Borders.Reset();

            // How many boxes are left to render on this row
            int remainingBoxesForThisLine = ( aDimensions.Width - BoxCoordinates.X );

            // Its the first line if we are drawing the first row, or if we're drawing the
            // second row and there weren't any boxes from this heap cell directly above us
            // in the grid.
            bool firstLine = ( CellRowIndex == 0 );
            if  ( CellRowIndex == 1 )
            {
                int numberOfBoxesDrawnOnPreviousLine = ( CellBoxIndex - BoxCoordinates.X );
                int xPosOfFirstBox = aDimensions.Width - numberOfBoxesDrawnOnPreviousLine;
                firstLine = ( BoxCoordinates.X < xPosOfFirstBox );
            }
            Borders.SetBorder( THeapCellBorderType.ETop, firstLine );

            // Its the last line if we are drawing the last row, or then if we're drawing
            // the last-but-one row and there weren't any boxes from this heap cell directly
            // below us in the grid.
            bool lastLine = ( RemainingBoxes <= remainingBoxesForThisLine );
            if  ( RemainingRows > 0 && BoxCoordinates.Y == aDimensions.Height - 1 )
            {
                lastLine = true;
            }
            else if ( RemainingRows == 1 )
            {
                // Now we need to work out how many boxes of the next row will be
                // required to finish rendering it fully.
                lastLine = ( BoxCoordinates.X >= RemainingBoxesAfterThisRow );
            }
            Borders.SetBorder( THeapCellBorderType.EBottom, lastLine );

            // Its the first box if it is the absolute first box we have rendered for a given
            // cell, or then it is the first box in a new row.
            bool firstBox = ( CellBoxIndex == 0 ) || ( BoxCoordinates.X == 0 );
            Borders.SetBorder( THeapCellBorderType.ELeft, firstBox );

            // Its the last box if it is the absolute last box we have rendered for a given
            // cell, or then it is the last box in a new row.
            bool lastBox = ( CellBoxIndex == CellBoxCount - 1 ) || ( remainingBoxes == 0 ) || ( BoxCoordinates.X == aDimensions.Width - 1 );
            Borders.SetBorder( THeapCellBorderType.ERight, lastBox );
        }
        #endregion

        #region Navigator call backs
        private void Navigator_NavBegin()
        {
        }

        private void Navigator_NavEnd()
        {
            iCell = null;
        }

        private void Navigator_NavHeapCellBegin( HeapCell aCell, uint aAddress, Point aPosition, Size aDimensions, Size aBoxSize, Size aPadding )
        {
            // Starting a new cell
            iCell = aCell;
            iAddress = aAddress;

            // This contains the absolute number of boxes required to render a given
            // heap cell.
            CellBoxCount = (int) ( aCell.Length / SymbianUtils.RawItems.RawItem.KSizeOfOneRawItemInBytes );
            BoxCoordinates = new Point();
            RemainingBoxes = 0;
            RemainingBoxesAfterThisRow = 0;
            RemainingRows = 0;
            RemainingBytes = 0;
            CellRowIndex = 0;
            Borders.Reset();
 
            // Reset current raw item - we won't have a new one until we hit the payload section
            iRawItem = null;

            // This starts at -1 since the first act of
            // preparing the meta data is to increment the index by one.
            CellBoxIndex = -1;
        }

        private void Navigator_NavHeapCellEnd( HeapCell aCell, HeapCellMetaData aMetaData, uint aAddress, Point aPosition, Size aDimensions, Size aBoxSize, Size aPadding )
        {
            // Finished with the cell...
            iCell = null;
        }

        private void Navigator_NavNewColumn( HeapCell aCell, HeapCellMetaData aMetaData, uint aAddress, Point aPixelPos, Point aBoxPos, Size aDimensions, Size aBoxSize, Size aPadding )
        {
            System.Diagnostics.Debug.Assert( iCell != null && iCell.Address == aCell.Address );

            // Indicate that we're processing a new box
            ++CellBoxIndex;
            iAddress = aAddress;

            // Set our box coordinates
            iBoxCoordinates = aBoxPos;

            // Get current raw item if we're in the payload section
            iRawItem = null;
            try
            {
                HeapCell.TRegion region = Region;
                if ( region == HeapCell.TRegion.EPayload )
                {
                    iRawItem = iCell[ aAddress ];
                }
            }
            catch( ArgumentException )
            {
            }


            // Some up front calculations that we'll need below...
            RemainingBytes = aCell.Remainder( aAddress );
            int remainingBoxesForThisLine = ( aDimensions.Width - BoxCoordinates.X );
            RemainingBoxes = (int) ( RemainingBytes / SymbianUtils.RawItems.RawItem.KSizeOfOneRawItemInBytes );
            RemainingBoxesAfterThisRow = Math.Max( 0, RemainingBoxes - remainingBoxesForThisLine );

            // If we can render all the remaining boxes in the not-yet-drawn
            // boxes from this row, we don't need anymore rows.
            RemainingRows = 0;
            if  ( RemainingBoxesAfterThisRow > 0 )
            {
                // Otherwise, we need to identify how many more rows we will need
                // in order to complete the remaining boxes that are left over
                // after this row's boxes.
                RemainingRows = ( RemainingBoxesAfterThisRow / aDimensions.Width ) + 1;
            }

            // Work out the borders that should be enabled for the cell
            CalculateBorders( aCell, aAddress, aDimensions );
        }

        private void Navigator_NavNewRowBody( HeapCellMetaData aMetaData, uint aAddress, Point aPosition, Size aDimensions, Size aBoxSize, Size aPadding )
        {
            ++CellRowIndex;
        }
        #endregion

        #region Data members
        private Point iBoxCoordinates = new Point( 0, 0 );
        private int iRemainingBoxes = 0;
        private int iRemainingBoxesAfterThisRow = 0;
        private int iRemainingRows = 0;
        private long iRemainingBytes = 0;
        private int iCellBoxIndex = 0;
        private int iCellRowIndex = 0;
        private int iCellBoxCount = 0;
        private uint iAddress = 0;
        private HeapCell iCell = null;
        private RawItem iRawItem = null;
        private HeapCellBorderInfo iBorders = new HeapCellBorderInfo();
        private Color iCellBoxColor = Color.HotPink;
        #endregion
    }
}