/*
* Copyright (c) 2000 - 2002 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

#include "nw_lmgr_boxi.h" 
#include "nw_lmgr_rootbox.h"
#include "nw_lmgr_marqueebox.h"
#include "nw_lmgr_statictablerowbox.h"
#include "nw_lmgr_statictablecellbox.h"
#include "nw_lmgr_bidiflowbox.h"
#include "nw_lmgr_textbox.h"
#include "nw_lmgr_simplepropertylist.h"
#include "nw_text_ucs2.h"
#include "nwx_string.h"
#include "nwx_logger.h"
#include "nwx_math.h"
#include "nw_gdi_utils.h"
#include "nw_lmgr_activecontainerbox.h"
#include "nw_lmgr_imgcontainerbox.h"
#include "nw_lmgr_posflowbox.h"
#include "nw_lmgr_verticaltablebox.h"
#include "nw_lmgr_verticaltablerowbox.h"
#include "nw_lmgr_verticaltablecellbox.h"
#include "urlloader_urlloaderint.h"
#include "nwx_settings.h"
#include "GDIDeviceContext.h"

#include "nw_lmgr_imgcontainerbox.h"
#include "LMgrMarkerImage.h"
#include "LMgrMarkerText.h"
#include "BrsrStatusCodes.h"
#include "LMgrAnonBlock.h"
#include "nw_css_tokentoint.h"
#include <bitdev.h>
#include <aknutils.h>
#include "LMgrObjectBoxOOC.h"

/* ------------------------------------------------------------------------- *
   private final methods
 * ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_ResolveAbsoluteLength
 * Description:  Resolves a relative length (Cm, Mm, In, Pt, Pc).
 * Returns:      KBrsrSuccess.
 */

static
TBrowserStatusCode
NW_LMgr_Box_ResolveAbsoluteLength(NW_LMgr_Box_t* box, 
                                  NW_LMgr_PropertyName_t propertyName,
                                  NW_LMgr_Property_t *property)
    {
    NW_Float32 val = property->value.decimal;

    NW_REQUIRED_PARAM(box);
    NW_REQUIRED_PARAM(propertyName);

    switch(property->type & NW_CSS_ValueType_Mask)
        {
        case NW_CSS_ValueType_Pc:
            // A pica is equivalent to 12 points
            val = val * 12;

            break;

        case NW_CSS_ValueType_Cm:
            // A centimeter is 28.34 points
            val = val * (NW_Float32)28.34;

            break;

        case NW_CSS_ValueType_Mm:
            // A millimeter is 2.83 points
            val = val * (NW_Float32)2.83;

            break;

        case NW_CSS_ValueType_In:
            // A inch is 72 points
            val = val * 72;

            break;

        case NW_CSS_ValueType_Pt:
        default:
            break;
        }
  
    property->type = NW_CSS_ValueType_Pt;
    property->value.decimal = val;

    return KBrsrSuccess;
    }

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_ResolveRelativeLength
 * Description:  Resolves a relative length (Em, Ex).
 * Returns:      KBrsrSuccess.
 */

static
TBrowserStatusCode
NW_LMgr_Box_ResolveRelativeLength(NW_LMgr_Box_t* box, 
                                  NW_LMgr_PropertyName_t propertyName,
                                  NW_LMgr_Property_t *property)
    {
    NW_LMgr_Box_t *baseBox;
    NW_Int32 val;
  
    (void) propertyName;

    // Fontsize uses the parent's em
    if (propertyName == NW_CSS_Prop_fontSize) 
        {
        baseBox = (NW_LMgr_Box_t*)NW_LMgr_Box_GetParent(box);

        // This assert is only going to be triggered in the case when
        // there are percentage properties applied to the RootBox.
        // That is an error condition because the RootBox should have
        // no properties.
        NW_ASSERT(baseBox != NULL);
        }
    else 
        {
        baseBox = box;
        }

    // set the absolute font-size
    if (property->type == NW_CSS_ValueType_Em) 
        {
        val = (NW_Int32)(property->value.decimal * NW_LMgr_Box_GetEm(baseBox));
        }
    else 
        {
        val = (NW_Int32)(property->value.decimal * NW_LMgr_Box_GetEx(baseBox));
        }

    if (propertyName == NW_CSS_Prop_fontSize) 
        {
        // we can't use pixels here because in NW_LMgr_Box_ApplyFontProps(),
        // pixel will be adjusted to bigger value 
        CEikonEnv* eikEnv = CEikonEnv::Static();
        CWsScreenDevice& screenDev = *eikEnv->ScreenDevice();
        NW_Float32 valPt = FontUtils::PointsFromTwips(screenDev.VerticalPixelsToTwips(val));

        property->type = NW_CSS_ValueType_Pt;
        property->value.decimal = valPt;
        }
    else
        {
        property->type = NW_CSS_ValueType_Px;
        property->value.integer = val;
        }

    return KBrsrSuccess;
    }

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_ResolvePercent
 * Description:  Resolves a relative property (percentage).
 * Returns:      KBrsrSuccess.
 */

static
TBrowserStatusCode
NW_LMgr_Box_ResolvePercent(NW_LMgr_Box_t* box, 
                           NW_LMgr_PropertyName_t propertyName,
						   NW_LMgr_Property_t *property)


    {
    NW_LMgr_Box_t* parentBox;
    NW_GDI_Rectangle_t bounds;
    NW_Float32 val = 0;
    NW_Int32 px = 0;
    NW_LMgr_Property_t parentProp;
    NW_GDI_Dimension2D_t size;
    NW_GDI_Dimension3D_t imgSize;
    TBrowserStatusCode status = KBrsrSuccess;
    NW_Image_AbstractImage_t *image = NULL;

    NW_Int32 fontSizeI = 0;
    NW_Float32 fontSizeD = 0.0;

    NW_LMgr_PropertyValue_t backgroundPropValue;

    val = property->value.decimal;

    switch(propertyName)
        {
        // This property calculate its percentage with respect to the
        // value of the same property of their parent box 
        case NW_CSS_Prop_fontSize:
            {
            // First we need to see if the box is a body box, if so, we need
            // to find what the default CSS font size is.
            NW_LMgr_RootBox_t* rootBox = NW_LMgr_Box_GetRootBox( box );

            // check for body box
            if( NW_LMgr_RootBox_GetBody( rootBox ) == box)
            {
                // TODO query the CSS table for the default font size
                // We know it is 6.5 points
                fontSizeD = (NW_Float32)(val * 6) / 100;

                property->type = NW_CSS_ValueType_Pt;
                property->value.decimal = fontSizeD;

                (void) NW_LMgr_Box_SetProperty (box, NW_CSS_Prop_fontSize, property);
            }
            else
            {
                // calculate the percentage of the parent box's  font size
                parentBox = (NW_LMgr_Box_t*)NW_LMgr_Box_GetParent(box);

                NW_LMgr_Box_GetProperty(NW_LMgr_BoxOf (parentBox), 
                    NW_CSS_Prop_fontSize, &parentProp);

                switch(parentProp.type)
                    {
                    case NW_CSS_ValueType_Em:
                    case NW_CSS_ValueType_Ex:
                    case NW_CSS_ValueType_In:
                    case NW_CSS_ValueType_Cm:
                    case NW_CSS_ValueType_Mm:
                    case NW_CSS_ValueType_Pt:
                    case NW_CSS_ValueType_Pc:
                        fontSizeD = (val * parentProp.value.decimal) / 100;

                        property->type = parentProp.type;
                        property->value.decimal = fontSizeD;

                        (void) NW_LMgr_Box_SetProperty (box, NW_CSS_Prop_fontSize, property);
                        break;

                    case NW_CSS_ValueType_Px: 
                    default:
                        fontSizeI = (NW_Int32) ((val * parentProp.value.integer) / 100);

                        property->type = parentProp.type;
                        property->value.integer = fontSizeI;

                        (void) NW_LMgr_Box_SetProperty (box, NW_CSS_Prop_fontSize, property);
                        break;
                    }
                }
            return status;
            }

        /* These properties calculate their percentage with repect to the
           value of the same property of the surrounding flow */
	    case NW_CSS_Prop_backgroundPosition_x:
	    case NW_CSS_Prop_backgroundPosition_y:
		    {
			    parentBox = box;
			    bounds = NW_LMgr_Box_GetFormatBounds(parentBox);
			    /* check if background-image is defined */
			     backgroundPropValue.object = NULL;
			     NW_LMgr_FrameInfo_t borderWidthInfo;
			     NW_LMgr_Box_GetBorderWidth(parentBox, &borderWidthInfo, ELMgrFrameAll );
			    (void)NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_backgroundImage, NW_CSS_ValueType_Image, &backgroundPropValue);
			    if (backgroundPropValue.object == NULL )
			        {
				    return KBrsrSuccess;
			        }

			    /* check if image is opened */
			    image = (NW_Image_AbstractImage_t*)backgroundPropValue.object;
			    (void) NW_Image_AbstractImage_GetSize(image, &imgSize);
			    if (imgSize.width == 0 || imgSize.height == 0)
			        {
				    return KBrsrSuccess;
			        }
 
			    if(propertyName == NW_CSS_Prop_backgroundPosition_x)
			        {
				    px = (NW_Int32)(val * (bounds.dimension.width - imgSize.width- borderWidthInfo.right
				     - borderWidthInfo.left) / 100);
			        }
			    else //propertyName == NW_CSS_Prop_backgroundPosition_y)
			        {
				    px = (NW_Int32)(val * (bounds.dimension.height - imgSize.height

				     - borderWidthInfo.top - borderWidthInfo.bottom	) / 100);
			        }
			    break;
		        }
        case NW_CSS_Prop_width:
        case NW_CSS_Prop_height:
        case NW_CSS_Prop_padding:
        case NW_CSS_Prop_leftPadding:
        case NW_CSS_Prop_rightPadding:
        case NW_CSS_Prop_topPadding:
        case NW_CSS_Prop_bottomPadding:
        case NW_CSS_Prop_margin:
        case NW_CSS_Prop_leftMargin:
        case NW_CSS_Prop_rightMargin:
        case NW_CSS_Prop_topMargin:
        case NW_CSS_Prop_bottomMargin:
        case NW_CSS_Prop_border:
        case NW_CSS_Prop_leftBorderWidth:
        case NW_CSS_Prop_rightBorderWidth:
        case NW_CSS_Prop_topBorderWidth:
        case NW_CSS_Prop_bottomBorderWidth:
        case NW_CSS_Prop_textIndent:
        case NW_CSS_Prop_marqueeAmount:
            /* First find the enclosing flow */
            do 
                {  
                parentBox = (NW_LMgr_Box_t*)NW_LMgr_Box_GetParent(box);
                
                /* This assert is only going to be triggered in the case when
                * there are percentage properties applied to the RootBox.
                * That is an error condition because the RootBox should have
                * no properties.
                */
                NW_ASSERT(parentBox != NULL);
                
                /* Move one level up */
                box = parentBox;
                
                } while (!NW_Object_IsInstanceOf(parentBox, &NW_LMgr_FlowBox_Class));
            if ((propertyName == NW_CSS_Prop_height || propertyName == NW_CSS_Prop_width) && 
                NW_Object_IsInstanceOf(parentBox, &NW_LMgr_PosFlowBox_Class))
                {
                NW_LMgr_RootBox_t* rootBox = NW_LMgr_Box_GetRootBox(box);
                CGDIDeviceContext* deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
                // The width of a positioned box depends on the containing block
                // If the positioned box is nested, the containing box is
                // the parent positioned box, otherwise it is the screen size
                NW_LMgr_PosFlowBox_t* posParent = (NW_LMgr_PosFlowBox_t*)parentBox;
                if (posParent->iContainingBlock == NULL)
                    {
                    bounds = (*deviceContext->DisplayBounds());
                    }
                else
                    {
                    bounds = NW_LMgr_Box_GetFormatBounds(posParent->iContainingBlock);
                    }
                if (propertyName == NW_CSS_Prop_width)
                    {	    
                    NW_LMgr_FrameInfo_t paddingInfo;
                    NW_LMgr_FrameInfo_t borderWidthInfo;
                    
                    NW_LMgr_Box_GetPadding(parentBox, &paddingInfo, ELMgrFrameAll );
                    NW_LMgr_Box_GetBorderWidth(parentBox, &borderWidthInfo, ELMgrFrameAll );
                    NW_GDI_Metric_t containingWidth = (NW_GDI_Metric_t)
                        (bounds.dimension.width - 
                        paddingInfo.left - paddingInfo.right -
                        borderWidthInfo.left - borderWidthInfo.right);
                    
                    px = (NW_Int32)((val * containingWidth) / 100);
                    }
                else // propertyName == NW_CSS_Prop_height
                    { 
                
                    px = (NW_Int32)((val * bounds.dimension.height) / 100);

                    }
                }
            else
                {
                if (propertyName != NW_CSS_Prop_height) 
                    {
                    bounds = NW_LMgr_Box_GetFormatBounds(parentBox); //  width 
                    
                    
                    // S60 bug fix <PHEN-64EEW3>
                    // If the box needs to have x% of parent box's width,
                    // deduct border, padding width from parent box's width first
                    // then calculate the x% of the remaining width
                    if (propertyName == NW_CSS_Prop_width) 
                        {
                        NW_LMgr_FrameInfo_t paddingInfo;
                        NW_LMgr_FrameInfo_t borderWidthInfo;
                        
                        NW_LMgr_Box_GetPadding(parentBox, &paddingInfo, ELMgrFrameAll );
                        NW_LMgr_Box_GetBorderWidth(parentBox, &borderWidthInfo, ELMgrFrameAll );
                        NW_GDI_Metric_t containingWidth = (NW_GDI_Metric_t)
                            (bounds.dimension.width - 
                            paddingInfo.left - paddingInfo.right -
                            borderWidthInfo.left - borderWidthInfo.right);
                        
                        px = (NW_Int32)((val * containingWidth) / 100);
                        }
                    else 
                        {
                        px = (NW_Int32)((val * bounds.dimension.width) / 100);
                        }
                    }
                else // propertyName == NW_CSS_Prop_height

                    { 
                    if (!NW_Object_IsClass(parentBox, &NW_LMgr_StaticTableCellBox_Class) &&
		                !NW_Object_IsClass(parentBox, &NW_LMgr_VerticalTableCellBox_Class)) 
                    {
                        NW_LMgr_RootBox_t* rootBox = NW_LMgr_Box_GetRootBox(box);
                        CGDIDeviceContext* deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
                        bounds = (*deviceContext->DisplayBounds());
                        NW_LMgr_FrameInfo_t paddingInfo;
                        NW_LMgr_FrameInfo_t borderWidthInfo;
                    
                        NW_LMgr_Box_GetPadding(parentBox, &paddingInfo, ELMgrFrameAll );
                        NW_LMgr_Box_GetBorderWidth(parentBox, &borderWidthInfo, ELMgrFrameAll );
                        NW_GDI_Metric_t containingHeight = (NW_GDI_Metric_t)
                            (bounds.dimension.height - 
                        paddingInfo.top - paddingInfo.bottom -
                        borderWidthInfo.top - borderWidthInfo.bottom);
                        px = (NW_Int32)((val * containingHeight) / 100);

                    }
                    else
                    {


                   status = NW_LMgr_Box_GetSizeProperties(parentBox, &size);
                    if (status != KBrsrSuccess) 
                        {
                        return status;
                        }
                    
                    if (size.height != -1) 
                        {
                        px = (NW_Int32) ((val * size.height) / 100);
                        }
                    else 
                        {
                        return KBrsrNotFound;
                        } 
                    }
                        
                    }
                }
            break;

        default:
          /* In all other cases return the percentage as is (this useful for v-align) */
          return KBrsrSuccess;
      }

      property->type = NW_CSS_ValueType_Px;
      property->value.integer = px;

      return status;
    }

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_ResolveRelativeProperty
 * Description:  Resolves a relative property (percentage, em, ex,).
 * Returns:      KBrsrSuccess.
 */

static
TBrowserStatusCode
 NW_LMgr_Box_ResolveRelativeProperty(NW_LMgr_Box_t* box, 
                                    NW_LMgr_PropertyName_t propertyName,
                                    NW_LMgr_Property_t *property)  
{
  TBrowserStatusCode status = KBrsrSuccess;

  NW_ASSERT (box);
  NW_ASSERT (property);

  // Remove bit flag so it works for default/variable properties as well
  // as normal ones.
  switch (property->type & NW_CSS_ValueType_Mask)
  {
    case NW_CSS_ValueType_Percentage:
      status = NW_LMgr_Box_ResolvePercent (box, propertyName, property); 
      break;

    case NW_CSS_ValueType_Em:
    case NW_CSS_ValueType_Ex:
      status = NW_LMgr_Box_ResolveRelativeLength (box, propertyName, property);
      break;
    
    case NW_CSS_ValueType_In:
    case NW_CSS_ValueType_Cm:
    case NW_CSS_ValueType_Mm:
    case NW_CSS_ValueType_Pt:
    case NW_CSS_ValueType_Pc:
      status = NW_LMgr_Box_ResolveAbsoluteLength (box, propertyName, property);
      break;
  
    default:
      break;
  }
  
  return status;
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_ConvertBorderStyle
 * Description:  Converts border style to GDIContext value
 * Returns:      Converted border style
 */

static
NW_GDI_Pattern_t
NW_LMgr_Box_ConvertBorderStyle(NW_LMgr_PropertyValueToken_t style)
{
  NW_GDI_Pattern_t gdiStyle;
  switch (style)
  {
    case NW_CSS_PropValue_solid:
      gdiStyle = NW_GDI_Pattern_Solid;
      break;

    case NW_CSS_PropValue_dashed:
      gdiStyle = NW_GDI_Pattern_Dashed;
      break;

    case NW_CSS_PropValue_dotted:
      gdiStyle = NW_GDI_Pattern_Dotted;
      break;
  
    default:
      gdiStyle = NW_GDI_Pattern_None;
      break;
  }
  return gdiStyle;
}

/* ------------------------------------------------------------------------- *
   static data
 * ------------------------------------------------------------------------- */

const
NW_LMgr_Box_Class_t  NW_LMgr_Box_Class = {
  { /* NW_Object_Core            */
    /* super                     */ &NW_Object_Dynamic_Class,
    /* queryInterface            */ _NW_Object_Base_QueryInterface
  },
  { /* NW_Object_Base            */
    /* interfaceList             */ NULL
  },
  { /* NW_Object_Dynamic         */
    /* instanceSize              */ sizeof (NW_LMgr_Box_t),
    /* construct                 */ _NW_LMgr_Box_Construct,
    /* destruct                  */ _NW_LMgr_Box_Destruct
  },
  { /* NW_LMgr_Box               */
    /* split                     */ _NW_LMgr_Box_Split,
    /* resize                    */ _NW_LMgr_Box_Resize,
    /* postResize                */ _NW_LMgr_Box_PostResize,
    /* getMinimumContentSize     */ _NW_LMgr_Box_GetMinimumContentSize,
    /* hasFixedContentSize       */ _NW_LMgr_Box_HasFixedContentSize,
    /* constrain                 */ _NW_LMgr_Box_Constrain,
    /* draw                      */ _NW_LMgr_Box_Draw,
    /* render                    */ _NW_LMgr_Box_Render,
    /* getBaseline               */ _NW_LMgr_Box_GetBaseline,
    /* shift                     */ _NW_LMgr_Box_Shift,
    /* clone                     */ _NW_LMgr_Box_Clone
  }
};

/* ------------------------------------------------------------------------- *
   virtual methods
 * ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_Construct
 * Description:  The constructor.  
 * Returns:      KBrsrSuccess, KBrsrOutOfMemory.
 */

TBrowserStatusCode
_NW_LMgr_Box_Construct (NW_Object_Dynamic_t* dynamicObject,
                        va_list* argp)
{
  NW_TRY (status) 
  {
    NW_LMgr_Box_t* box;
    NW_ADT_Vector_Metric_t initPropCount;

    NW_ASSERT(dynamicObject != NULL);

    /* for convenience */
    box = NW_LMgr_BoxOf (dynamicObject);
   
    /* initialize the member variables */
    initPropCount = (NW_ADT_Vector_Metric_t) va_arg (*argp, NW_Uint32);
    if (initPropCount != 0) 
    {
      box->propList = (NW_LMgr_PropertyList_t*)
        NW_LMgr_SimplePropertyList_New (initPropCount, 2);
      NW_THROW_OOM_ON_NULL (box->propList, status);
    } 
    else 
    {
      box->propList = NULL;
    }

    box->hasFocus = NW_FALSE;
    box->rootBox = NULL;
  } 
  NW_CATCH (status) 
  {
  } 
  NW_FINALLY 
  {
    return status;
  } NW_END_TRY
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_Destruct
 * Description:  The destructor.  
 * Returns:      void
 */

void
_NW_LMgr_Box_Destruct (NW_Object_Dynamic_t* dynamicObject)
{
  NW_LMgr_Box_t* box;

  NW_ASSERT(dynamicObject != NULL);

  /* for convenience */
  box = NW_LMgr_BoxOf (dynamicObject);

  /* before deleting the object, we must make sure that it is removed from the
     parent */
  TBrowserStatusCode status = NW_LMgr_Box_Detach(box);
  NW_ASSERT(status == KBrsrSuccess);
	/* To fix TI compiler warning */
	(void) status; 
  
  /* delete the properties */
  if (box->propList != NULL) {
    NW_Object_Delete (box->propList);
  }
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_Split
 * Description:  Splits the box, storing the split box in splitBox.  
 *               By default, boxes can't split.  If there is enough space for the box,
 *               or if we're at the new line, we return success.  Otherwise 
 *               split fails. 
 * Returns:      KBrsrLmgrSplitOk, KBrsrLmgrNoSplit
 */

TBrowserStatusCode
_NW_LMgr_Box_Split(NW_LMgr_Box_t* box, 
                   NW_GDI_Metric_t space, 
                   NW_LMgr_Box_t* *splitBox,
                   NW_Uint8 flags)
{
  NW_ASSERT(box != NULL);

  if (flags & NW_LMgr_Box_SplitFlags_Nowrap) {
    *splitBox = NULL;
    return KBrsrSuccess;
  }

  NW_GDI_Rectangle_t boxBounds = NW_LMgr_Box_GetFormatBounds( box );

  if((boxBounds.dimension.width <= space) 
     || (flags & NW_LMgr_Box_SplitFlags_AtNewLine)) { 
    *splitBox = NULL;
    return KBrsrSuccess;
  }
  else {
    *splitBox = NULL;
    return KBrsrLmgrNoSplit;
  }
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_Resize
 * Description:  Resizes the box.  By default, boxes resize themselves to match 
                 any CSS size properties. Otherwise they get the default minimum size.
 * Returns:      void
 */

TBrowserStatusCode
_NW_LMgr_Box_Resize (NW_LMgr_Box_t* box,  NW_LMgr_FormatContext_t* context)
{
  NW_REQUIRED_PARAM(context);
  NW_TRY (status) {
    NW_GDI_Dimension2D_t size;

    NW_ASSERT(box != NULL);

    status = NW_LMgr_Box_GetMinimumSize (box, &size);
    _NW_THROW_ON_ERROR (status);

    NW_GDI_Rectangle_t boxBounds = NW_LMgr_Box_GetFormatBounds( box );

    boxBounds.dimension.width = size.width;  
    boxBounds.dimension.height = size.height;
    NW_LMgr_Box_SetFormatBounds( box, boxBounds );

} NW_CATCH (status) {
  } NW_FINALLY {
    return status;
  } NW_END_TRY
}

TBrowserStatusCode
_NW_LMgr_Box_PostResize (NW_LMgr_Box_t* box)
{
  NW_REQUIRED_PARAM(box);
 
  return KBrsrSuccess;
}

/* ------------------------------------------------------------------------- *
 * Function:   NW_LMgr_Box_Constrain
 * Description This method sets an initial size for a box depending on an external
 *             constraint. This is different from resize which knows about box
 *             content size, box size properties, and box minimum size. For
 *             container boxes, resize involves laying out children with size
 *             constrained in one dimension: this method is called before resizing
 *             the box to set the constraint. For other box types, this method
 *             does nothing and returns KBrsrLmgrNotConstrained, indicating
 *             that the box has a fixed size and cannot be arbitrarily
 *             constrained. This method can be called to discover whether a box
 *             obeys constraint arguments or has a fixed size. 
 * Returns:    KBrsrLmgrNotConstrained
 */

TBrowserStatusCode
_NW_LMgr_Box_Constrain(NW_LMgr_Box_t *box,
                       NW_GDI_Metric_t constraint) {
  
  NW_REQUIRED_PARAM(box);
  NW_REQUIRED_PARAM(constraint);

  return KBrsrLmgrNotConstrained;
}


/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_GetMinimumContentSize
 * Description: This virtual method returns the minimum content size for the
 *              box.  If the WIDTH property is set on the box, this is assumed 
 *              to be the minimum size for the box.  Otherwise, the box returns 
 *              the default values (8,8).
 * Returns:     KBrsrSuccess
 */
 
TBrowserStatusCode
_NW_LMgr_Box_GetMinimumContentSize(NW_LMgr_Box_t *box,
                                   NW_GDI_Dimension2D_t *size){
  NW_LMgr_PropertyValue_t sizeVal;

  NW_REQUIRED_PARAM(box);
  NW_ASSERT(size != NULL);

  /* If the box has its Width/Height properties set, use that for sizing;
   * otherwise return default values (8 by 8).
   */
  NW_LMgr_RootBox_t* rootBox = NW_LMgr_Box_GetRootBox( box );

  if( NW_LMgr_RootBox_GetSmallScreenOn( rootBox ) )
  {
    NW_LMgr_PropertyValue_t visibilityVal;
    TBrowserStatusCode status ;
    visibilityVal.token = NW_CSS_PropValue_visible;
    status = NW_LMgr_Box_GetPropertyValue (box, NW_CSS_Prop_visibility,
                                   NW_CSS_ValueType_Token, &visibilityVal);
    if (status  == KBrsrSuccess && visibilityVal.token == NW_CSS_PropValue_hidden) 
    {
      size->width = 0 ;
      size->height = 0;
       return KBrsrSuccess;
    }
  }

  if(NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_width, NW_CSS_ValueType_Px, &sizeVal) == KBrsrSuccess){
    size->width = (NW_GDI_Metric_t)sizeVal.integer;
  }
  else {
    size->width = NW_LMGR_BOX_MIN_WIDTH;
  }

  if(NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_height, NW_CSS_ValueType_Px, &sizeVal) == KBrsrSuccess){
    size->height = (NW_GDI_Metric_t)sizeVal.integer;
  }
  else {
    size->height = NW_LMGR_BOX_MIN_HEIGHT;
  }

  return KBrsrSuccess;
}

/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_HasFixedContentSize
 * Description: Determines whether the content of the box has fixed size or not.
 *              By default, boxes don't have a fixed content size: i.e. they can
 *              be arbitrarily resized by applying a constraint.
 * Returns:     NW_FALSE
 */
 
NW_Bool
_NW_LMgr_Box_HasFixedContentSize(NW_LMgr_Box_t *box){
  NW_REQUIRED_PARAM(box);
  return NW_FALSE;
}

/**
 * Function:     NW_LMgr_Box_Predraw
 * Description:  draw the background for the box, including background color and
 *               background image. 
 *               The latter one includes background-image, background-repeat,
 *               background-attachment and background-position.
 * Parameters:   box --     The box for which the background is to be handled.
 *               deviceContext -- The device context object.
 *               hasFocus -- has the focus or not.
 *
 * Returns:      KBrsrSuccess, KBrsrOutOfMemory
 */

TBrowserStatusCode
NW_LMgr_Box_Predraw (NW_LMgr_Box_t* box,
                     CGDIDeviceContext* deviceContext, 
                     NW_Uint8 hasFocus)
{
  NW_GDI_Color_t initialColor;
  NW_GDI_Color_t initialBackgroundColor;
  NW_GDI_Color_t highlightColor;


  /* parameter assertion block */
  NW_ASSERT (box != NULL);
  NW_ASSERT (NW_Object_IsInstanceOf (box, &NW_LMgr_Box_Class));

  initialColor = deviceContext->ForegroundColor();
  initialBackgroundColor = deviceContext->BackgroundColor();

  NW_TRY (status) 
    {
    NW_LMgr_Property_t backgroundProp;
    NW_LMgr_Property_t backgroundPropX, backgroundPropY;
    NW_LMgr_PropertyValue_t backgroundPropValue;
    NW_Image_AbstractImage_t *image = NULL; 
    NW_GDI_Rectangle_t rect;                  /* box rectangle */
    NW_GDI_Rectangle_t viewBounds;            /* view rectangle */
    NW_GDI_Point2D_t startDraw;                /* start point for drawing the background image */
    NW_GDI_Point2D_t viewOffset;              /* view offset caused by scrolling */
    NW_GDI_Dimension3D_t size;                /* size of image */
    NW_Bool isFixed = NW_FALSE;               /* if the background-attachment is set to fixed */
    NW_LMgr_RootBox_t* rootBox;
        
    rect = NW_LMgr_Box_GetDisplayBounds(box);

    /* draw the background color */

    backgroundProp.type = NW_CSS_ValueType_Token;
    backgroundProp.value.token = NW_CSS_PropValue_transparent;

    if (NW_Object_IsClass(box, &NW_LMgr_StaticTableCellBox_Class))
      {         
      NW_LMgr_StaticTableCellBox_t *cell = NW_LMgr_StaticTableCellBoxOf(box);
      NW_LMgr_StaticTableCellBox_GetBackground(cell, &backgroundProp);
      } 
    else
      {
      status = NW_LMgr_Box_GetProperty(box, NW_CSS_Prop_backgroundColor, &backgroundProp);
      }

    if (hasFocus && NW_Object_IsInstanceOf(box, &NW_LMgr_AbstractTextBox_Class))
      {
      /* we want to change the background */
      backgroundProp.type = NW_CSS_ValueType_Color;

      deviceContext->GetHighlightColor( &highlightColor);
      backgroundProp.value.integer = highlightColor;
      }
      
    if (backgroundProp.type == NW_CSS_ValueType_Color) 
      {  
      deviceContext->SetPaintMode ( NW_GDI_PaintMode_Copy);
      deviceContext->SetBackgroundColor( backgroundProp.value.integer);
      deviceContext->FillRectangle( &rect);
      }
    
    /* draw the background image */

    /* check if background-image is defined */
    backgroundPropValue.object = NULL;
    (void)NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_backgroundImage, NW_CSS_ValueType_Image, &backgroundPropValue);
    if (backgroundPropValue.object == NULL )
      {
      NW_THROW (KBrsrSuccess);
      }

    /* check if image is opened */
    image = (NW_Image_AbstractImage_t*)backgroundPropValue.object;
    (void) NW_Image_AbstractImage_GetSize(image, &size);
    if (size.width == 0 || size.height == 0)
      {
      NW_THROW (KBrsrSuccess);
      }

    /* initialized some drawing coordinates */
    viewOffset = deviceContext->ClipRect().point;
    viewBounds = *(deviceContext->DisplayBounds());
    startDraw = rect.point;
    
    rootBox = NW_LMgr_Box_GetRootBox( box );
    
    /* check for body box */
    if( NW_LMgr_RootBox_GetBody( rootBox ) == box)
      {
      /* to make sure the image can be drawn on the entire view */
      startDraw = viewBounds.point;
      rect.dimension.width = rect.dimension.width + rect.point.x;
      rect.dimension.height =rect.dimension.height + rect.point.y;
      rect.point.x = 0;
      rect.point.y = 0;

      // Note: following is a temporary fix for bug RLAU-5W9LA8
      // the cause of the bug was body box's width not being correctly set by format functions, 
      // instead it's always set to roughly view bounds width
      // A better fix should be in post format functions
      if (rect.dimension.width < viewBounds.dimension.width + viewOffset.x)
        rect.dimension.width = viewBounds.dimension.width + viewOffset.x;
     }
      /* check for background-attachment property */
      backgroundPropValue.token = NW_CSS_PropValue_scroll;
      NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_backgroundAttachment, NW_CSS_ValueType_Token, &backgroundPropValue);
      
      if (backgroundPropValue.token == NW_CSS_PropValue_background_fixed)
        {
        isFixed = NW_TRUE;
        }
 

    /* check and apply background-position property */
    backgroundPropX.type = NW_CSS_ValueType_Token;
    backgroundPropX.value.token = NW_CSS_PropValue_none;
    backgroundPropY.type = NW_CSS_ValueType_Token;
    backgroundPropY.value.token = NW_CSS_PropValue_none;
    NW_LMgr_FrameInfo_t borderWidthInfo; 
    NW_LMgr_Box_GetBorderWidth(box, &borderWidthInfo, ELMgrFrameAll );

    NW_LMgr_Box_GetPropertyFromList(box, NW_CSS_Prop_backgroundPosition_x, &backgroundPropX); 
    NW_LMgr_Box_GetPropertyFromList(box, NW_CSS_Prop_backgroundPosition_y, &backgroundPropY); 
	if(backgroundPropX.type == NW_CSS_ValueType_Token)
	{
    if((backgroundPropX.value.token == NW_CSS_PropValue_none) && (backgroundPropY.value.token != NW_CSS_PropValue_none))
      {
      backgroundPropX.value.token = NW_CSS_PropValue_center;
      }
	}
	if(backgroundPropY.type == NW_CSS_ValueType_Token)
	{
    if((backgroundPropX.value.token != NW_CSS_PropValue_none) && (backgroundPropY.value.token == NW_CSS_PropValue_none))
      {
      backgroundPropY.value.token = NW_CSS_PropValue_center;
      }
	}

    if(backgroundPropX.type == NW_CSS_ValueType_Token)
      {
      /* if background image needs to be shown as fixed, set the position relative to view bounds instead of box bounds */
      if ((backgroundPropX.value.token == NW_CSS_PropValue_center )
          && size.width <= rect.dimension.width)
        {
        if (isFixed == NW_TRUE)
          startDraw.x += (viewBounds.dimension.width - size.width)/2;
        else 
          startDraw.x += (rect.dimension.width - size.width)/2;
        }
      else if (backgroundPropX.value.token == NW_CSS_PropValue_right)
        {
        if (isFixed == NW_TRUE)
          startDraw.x += (viewBounds.dimension.width - size.width);
        else 
          startDraw.x += (rect.dimension.width - size.width);
        }
      }
    else if ( backgroundPropX.type == NW_CSS_ValueType_Number)
      {
      startDraw.x += (TInt32)backgroundPropX.value.decimal + borderWidthInfo.left;
      }
	else
	{
		startDraw.x += backgroundPropX.value.integer + borderWidthInfo.left;
	}

    if(backgroundPropY.type == NW_CSS_ValueType_Token)
      {
      if ((backgroundPropY.value.token == NW_CSS_PropValue_center) &&
          (size.height <= rect.dimension.height))
        {
        if (isFixed == NW_TRUE)
          startDraw.y += (viewBounds.dimension.height - size.height)/2;
        else
          startDraw.y += (rect.dimension.height - size.height)/2;
        }
      else if (backgroundPropY.value.token == NW_CSS_PropValue_bottom)
        {
        if (isFixed == NW_TRUE)
          startDraw.y += (viewBounds.dimension.height - size.height);
        else
          startDraw.y += (rect.dimension.height - size.height);
        }
      }
    else if ( backgroundPropY.type == NW_CSS_ValueType_Number)
      {
		startDraw.y += (TInt32)backgroundPropY.value.decimal + borderWidthInfo.top;
      }
	else
	{
		startDraw.y += backgroundPropY.value.integer + borderWidthInfo.top;
	}

    /* Apply background-attachment feature only to the body element */
    if ( isFixed == NW_TRUE)
      {
      startDraw.x += viewOffset.x;
      startDraw.y += viewOffset.y;
      }

    /* check and apply background-repeat property */
    backgroundPropValue.token = NW_CSS_PropValue_background_repeat;
    NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_backgroundRepeat, NW_CSS_ValueType_Token, &backgroundPropValue);

    // Draw the image once at startDraw.
    if (backgroundPropValue.token == NW_CSS_PropValue_background_norepeat) 
      {
      /* do no repeat, just draw the image once*/
      status = NW_Image_AbstractImage_DrawInRect (image, deviceContext, &startDraw, NULL, &rect );
      } 

    // If repeat-x, draw a row of images at startDraw.y
    else if (backgroundPropValue.token == NW_CSS_PropValue_background_repeat_x) 
      {
      /* do horizonta repeat */
      /* in case the image is moved by background-position property, restore the start to left */
      if (isFixed == NW_FALSE)
        {
        startDraw.x = rect.point.x;
        }
      else
        {
        startDraw.x = viewBounds.point.x + viewOffset.x;
        }
      /*startDraw.x += deviceContext->ClipRect().point.x;*/

      for (; startDraw.x < rect.point.x + rect.dimension.width; startDraw.x += size.width)
        {
        if (startDraw.x < viewBounds.point.x + viewOffset.x - size.width)
          continue;
        if (startDraw.x > viewBounds.point.x + viewOffset.x + viewBounds.dimension.width)
          break;

        status = NW_Image_AbstractImage_DrawInRect (image, deviceContext, &startDraw, NULL, &rect);
        if (status != KBrsrSuccess)
          break;
        }
      }

    // If repeat-y, draw a column of images at startDraw.x.
    else if (backgroundPropValue.token == NW_CSS_PropValue_background_repeat_y) 
      {
      /* do verticall repeat */
      /* in case the image is  moved by background-position property, restore the start to top */
      if (isFixed == NW_FALSE)
        {
        startDraw.y = rect.point.y;
        } 
      else
        {
        startDraw.y = viewBounds.point.y + viewOffset.y;
        }

      for (; startDraw.y < rect.point.y + rect.dimension.height; startDraw.y += size.height)
        {
        /* check to make sure only draw the images in the view */
        if (startDraw.y < viewBounds.point.y + viewOffset.y - size.height)
          continue;
        if (startDraw.y > viewBounds.point.y + viewOffset.y + viewBounds.dimension.height)
          break;

        status = NW_Image_AbstractImage_DrawInRect (image, deviceContext, &startDraw, NULL, &rect);
        if (status != KBrsrSuccess)
          break;
        }
      }

    // If repeating in both x and y directions and the image is a "dot"
    // stretch the image to fill the box.  This speeds up rendering considerably.
    else if ((size.width == 1) && (size.height == 1))
      {
      NW_GDI_Rectangle_t    realViewBounds;
      NW_GDI_Rectangle_t    visibleArea;
      NW_GDI_Dimension3D_t  scaledSize;

      // Set the view rectangle
      realViewBounds = viewBounds;
      realViewBounds.point = viewOffset;

      // Get the visible part of the box on which the image is stretched.
      if( !NW_GDI_Rectangle_Cross( &realViewBounds, &rect, &visibleArea ) )
        {
        // the box is not in the view
        NW_THROW_SUCCESS( status );
        }

      scaledSize.width = visibleArea.dimension.width;
      scaledSize.height = visibleArea.dimension.height;
      scaledSize.depth = 0; 

      // Draw the image to fill scaledSize.
      status = NW_Image_AbstractImage_DrawScaled( image, deviceContext, &startDraw, &scaledSize );
      }

    // Otherwise draw a grid of iamges.
    else  
      {
      NW_GDI_Point2D_t  boxBegin;
      NW_GDI_Point2D_t  boxEnd;
      NW_GDI_Point2D_t  point;
      NW_Int32          x;
      NW_Int32          y;

      // Normalize the box's rectangle in the view.
      boxBegin.x = rect.point.x;
      boxBegin.y = rect.point.y;

      boxEnd.x = boxBegin.x + rect.dimension.width;
      boxEnd.y = boxBegin.y + rect.dimension.height;

      // IsFixed is only true when "background-attachment: fixed" is applied to 
      // a "body" box.  In this case place the first image at the top-left corner
      // of the view.
      if (isFixed)
        {
        startDraw.x = viewOffset.x;
        startDraw.y = viewOffset.y;
        }
      
      // Otherwise place the first image at the top-left corner of the box.
      else
        {
        startDraw.x = boxBegin.x;
        startDraw.y = boxBegin.y;
        }

      // Draw columns that overlap the box's rect.
      for (x = startDraw.x; x < boxEnd.x; x += size.width)
        {
        // Skip columns to the left of the box's rectangle.
        if ((x + size.width) < boxBegin.x)
          {
          continue;
          }

        // Draw cells that overlap the box's box.
        for (y = startDraw.y; y < boxEnd.y; y += size.height)
          {
          // Skip cells above box's rectangle.
          if ((y + size.height) < boxBegin.y)
            {
            continue;
            }

          // Draw the cell.
          point.x = x; 
          point.y = y;

          status = NW_Image_AbstractImage_DrawInRect(image, deviceContext, &point, NULL, &rect);
          _NW_THROW_ON_ERROR(status);
          }
        }
      }
    }
      
  NW_CATCH (status) 
    {
    }
     
  NW_FINALLY 
    {
    deviceContext->SetForegroundColor( initialColor);
    deviceContext->SetBackgroundColor( initialBackgroundColor);
    return status;
    } 
  NW_END_TRY
  }

/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_Draw
 * Description: The base class draw only draws the borders and the background.
 * Returns:     KBrsrSuccess, KBrsrOutOfMemory.
 */
 
TBrowserStatusCode
_NW_LMgr_Box_Draw (NW_LMgr_Box_t* box,
                   CGDIDeviceContext* deviceContext,
                   NW_Uint8 hasFocus)
  {
  NW_GDI_PaintMode_t oldPaintMode;
  NW_Bool paintModeChanged = NW_FALSE;
  NW_TRY (status) 
    {
    NW_LMgr_FrameInfo_t borderWidth;
    NW_LMgr_FrameInfo_t borderStyle;
    NW_LMgr_FrameInfo_t borderColor;
    NW_LMgr_PropertyValue_t displayVal;
    NW_LMgr_PropertyValue_t focusBehavior;
    NW_Bool getBorder = NW_FALSE;
    NW_LMgr_FrameInfo_t origBorderColor;

    /* parameter assertion block */
    NW_ASSERT (box != NULL);
    NW_ASSERT (NW_Object_IsInstanceOf (box, &NW_LMgr_Box_Class));
    NW_ASSERT (deviceContext != NULL);

    NW_LMgr_Box_Predraw(box, deviceContext, hasFocus);
    /* Check if display is actually a displayable one */
    displayVal.token = NW_CSS_PropValue_display_inline; 
    (void) NW_LMgr_Box_GetPropertyValue (box, NW_CSS_Prop_display,
                                         NW_CSS_ValueType_Token, &displayVal);
    if (displayVal.token == NW_CSS_PropValue_none) 
      {
      return KBrsrSuccess; 
    }

    // save paint mode
    oldPaintMode = deviceContext->PaintMode();
    deviceContext->SetPaintMode ( NW_GDI_PaintMode_Copy);
    paintModeChanged = NW_TRUE;

    NW_LMgr_Box_GetBorderStyle (box, &borderStyle, ELMgrFrameAll );
    NW_LMgr_Box_GetBorderColor (box, &origBorderColor);

    // do not check color and width unless border is present.
    if( !( borderStyle.top == NW_CSS_PropValue_none || borderStyle.top == NW_CSS_PropValue_hidden || origBorderColor.top == NW_GDI_Color_Transparent ) ||
        !( borderStyle.bottom == NW_CSS_PropValue_none || borderStyle.bottom == NW_CSS_PropValue_hidden || origBorderColor.bottom == NW_GDI_Color_Transparent) ||
        !( borderStyle.left == NW_CSS_PropValue_none || borderStyle.left == NW_CSS_PropValue_hidden || origBorderColor.left == NW_GDI_Color_Transparent ) ||
        !( borderStyle.right == NW_CSS_PropValue_none || borderStyle.right == NW_CSS_PropValue_hidden || origBorderColor.right == NW_GDI_Color_Transparent ) )
      {
      getBorder = NW_TRUE;
      NW_LMgr_Box_GetBorderColor (box, &borderColor);
      NW_LMgr_Box_GetBorderWidth (box, &borderWidth, ELMgrFrameAll );
      }
    else
      {
      // set border color to white
      borderColor.bottom = borderColor.left = 
        borderColor.right = borderColor.top = NW_GDI_Color_White;
      // and the style to none
      borderWidth.bottom = borderWidth.left = 
        borderWidth.right = borderWidth.top = 0;
      }

    /* Modify the look of the box if we're in focus */
    if (hasFocus)
      {
      focusBehavior.token = NW_CSS_PropValue_none;
      (void) NW_LMgr_Box_GetPropertyValue (box, NW_CSS_Prop_focusBehavior,
                                           NW_CSS_ValueType_Token,
                                           &focusBehavior);

      if (focusBehavior.token == NW_CSS_PropValue_growBorder) 
        {        
        // get the border color and style unless we already have them.
        if( getBorder == NW_FALSE )
          {
          NW_LMgr_Box_GetBorderColor (box, &borderColor);
          NW_LMgr_Box_GetBorderWidth (box, &borderWidth, ELMgrFrameAll );
          }
        borderWidth.top = (NW_GDI_Metric_t)(borderWidth.top + 1);
        borderWidth.bottom = (NW_GDI_Metric_t)(borderWidth.bottom + 1);
        borderWidth.left = (NW_GDI_Metric_t)(borderWidth.left + 1);
        borderWidth.right = (NW_GDI_Metric_t)(borderWidth.right + 1);

        if (origBorderColor.top == NW_GDI_Color_Transparent) 
          {
          borderStyle.top = NW_CSS_PropValue_solid;
          borderColor.top = deviceContext->ForegroundColor();
          }
        if (origBorderColor.bottom == NW_GDI_Color_Transparent) 
          {
          borderStyle.bottom = NW_CSS_PropValue_solid;
          borderColor.bottom = deviceContext->ForegroundColor();
          }
        if (origBorderColor.left == NW_GDI_Color_Transparent) 
          {
          borderStyle.left = NW_CSS_PropValue_solid;
          borderColor.left = deviceContext->ForegroundColor();
          }
        if (origBorderColor.right == NW_GDI_Color_Transparent) 
          {
          borderStyle.right = NW_CSS_PropValue_solid;
          borderColor.right = deviceContext->ForegroundColor();
          }
        if ((borderStyle.top == NW_CSS_PropValue_none) || (borderStyle.top == NW_CSS_PropValue_hidden)) 
          {
          borderStyle.top = NW_CSS_PropValue_solid;
          }
        if ((borderStyle.bottom == NW_CSS_PropValue_none) || (borderStyle.bottom == NW_CSS_PropValue_hidden)) 
          {
          borderStyle.bottom = NW_CSS_PropValue_solid;
          }
        if ((borderStyle.left == NW_CSS_PropValue_none) || (borderStyle.left == NW_CSS_PropValue_hidden)) 
          {
          borderStyle.left = NW_CSS_PropValue_solid;
          }
        if ((borderStyle.right == NW_CSS_PropValue_none) || (borderStyle.right == NW_CSS_PropValue_hidden)) 
          {
          borderStyle.right = NW_CSS_PropValue_solid;
          }
        }
      }

    /* TODO: if cache is empty, ignore CSS imposed by "a:visited" pseudo-class,
             but for now we just fix the color */

    /* Check for link by looking at parent container. */
    if (NW_LMgr_Box_GetParent(box) != NULL && NW_Object_IsClass(NW_LMgr_Box_GetParent(box), &NW_LMgr_ActiveContainerBox_Class))
     {
      /* If Cache is empty, force border to be drawn in uncached color (blue).
         NOTE: GetNumEntries allocates a list of the cached files, so avoid it for non-links. */
      //if (UrlLoader_GetNumCacheEntries() == 0)
      //  {
      //  borderColor.top    = NW_GDI_Color_Blue;
      //  borderColor.bottom = NW_GDI_Color_Blue;
      //  borderColor.left   = NW_GDI_Color_Blue;
      //  borderColor.right  = NW_GDI_Color_Blue;
      //  }
      }
    /* draw the border */
    /* TODO add support for other border types */
    status = NW_LMgr_Box_DrawBorder( NW_LMgr_Box_GetDisplayBounds(box), deviceContext, &borderWidth, &borderStyle, &borderColor);
    _NW_THROW_ON_ERROR(status);
    }
  NW_CATCH (status) 
    {
    } 
  NW_FINALLY 
    {
    if( paintModeChanged == NW_TRUE )
      {
      // reset paint mode
      deviceContext->SetPaintMode(  oldPaintMode );
      }
    return status;
    } 
  NW_END_TRY
  }

/* -------------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_Update_RenderCache
 * Description:  Updates the render cache  
 * Returns:      NW_TRUE, NW_FALSE
 */

NW_Bool NW_LMgr_Box_Update_RenderCache (NW_LMgr_RootBox_t* rootBox, 
                                     NW_LMgr_Box_t* box,
                                     NW_GDI_Rectangle_t* realClip,
                                     void ***ptr)
{
    NW_Bool cachePresent = NW_FALSE; 
    if (rootBox->renderedBoxes && rootBox->renderedClips )
        {
        cachePresent = NW_TRUE;
        NW_ADT_Vector_Metric_t index =  NW_ADT_Vector_GetElementIndex(rootBox->renderedBoxes, &box);
        if (index == NW_ADT_Vector_AtEnd)
            {
            *ptr = NW_ADT_DynamicVector_InsertAt(rootBox->renderedBoxes, &box, NW_ADT_Vector_AtEnd);
            if (*ptr == NULL)
                return cachePresent;
            *ptr = NW_ADT_DynamicVector_InsertAt(rootBox->renderedClips, realClip, NW_ADT_Vector_AtEnd);
            if (*ptr == NULL)
                return cachePresent;
            }
        else
            {
            *ptr = NW_ADT_DynamicVector_ReplaceAt(rootBox->renderedBoxes, &box, index);
            if (*ptr == NULL)
                return cachePresent;

            *ptr = NW_ADT_DynamicVector_ReplaceAt(rootBox->renderedClips, realClip, index);
            if (*ptr == NULL)
                return cachePresent;
            }
        }
    return cachePresent;
}

/* -------------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_Render
 * Description:  Renders the box.  
 * Returns:      KBrsrSuccess, KBrsrOutOfMemory
 */

TBrowserStatusCode
_NW_LMgr_Box_Render (NW_LMgr_Box_t* box,
                     CGDIDeviceContext* deviceContext,
                     NW_GDI_Rectangle_t* clipRect,
                     NW_LMgr_Box_t* currentBox,
                     NW_Uint8 flags, 
                     NW_Bool* hasFocus,
                     NW_Bool* skipChildren,
                     NW_LMgr_RootBox_t* rootBox )
{
  NW_GDI_Rectangle_t visibleArea;
  NW_LMgr_PropertyValue_t floatVal;
  NW_LMgr_PropertyValue_t visibilityVal;
  NW_GDI_Rectangle_t viewBounds;  
  NW_GDI_Rectangle_t oldClip = {{0, 0}, {0, 0}};  
  NW_GDI_Rectangle_t realClip;  
  NW_Bool clipRectChanged = NW_FALSE;
  void** ptr = NULL;

  NW_TRY (status) 
    {    
    /* Should we draw floats? */
    if (!(flags & NW_LMgr_Box_Flags_DrawFloats)) 
      {
      floatVal.token = NW_CSS_PropValue_none;
      (void) NW_LMgr_Box_GetPropertyValue (box, NW_CSS_Prop_float,
                                           NW_CSS_ValueType_Token, &floatVal);
      if (floatVal.token != NW_CSS_PropValue_none) 
        {
        NW_THROW_SUCCESS (status);
        }
      }
    // check if the this box has focus
    // if hasFocus is already set to true by any parent
    // then it should not be overuled.
    if( !(*hasFocus) && currentBox == box )
      {
      *hasFocus = NW_TRUE;
      }

    /* Calculate the view bounds */
    viewBounds = *(deviceContext->DisplayBounds());
    viewBounds.point = *(deviceContext->Origin());
    NW_GDI_Rectangle_t boxBounds = NW_LMgr_Box_GetDisplayBounds( box );

    /* Calculate tree extents first */
    if (!NW_GDI_Rectangle_Cross(clipRect, &boxBounds, &visibleArea)) 
      {
      NW_THROW_SUCCESS (status);
      }
    /* Is the box visible on screen?  If not, we don't draw */
    if (!NW_GDI_Rectangle_Cross(&viewBounds, &visibleArea, NULL)) 
      {
      NW_THROW_SUCCESS (status);
      }
    /* Calculate the part of the clip that is visible on screen;
       if the clip is off-screen, don't draw */
    if (!NW_GDI_Rectangle_Cross(clipRect, &viewBounds, &realClip)) 
      {
      NW_THROW_SUCCESS (status);
      }

    /* Save the old clip rect */
    oldClip = deviceContext->ClipRect();
    /* Set the new clip rect */
    deviceContext->SetClipRect(  &realClip );
    clipRectChanged = NW_TRUE;

    /* Check if visibility val is not hidden */
    visibilityVal.token = NW_CSS_PropValue_visible;
    (void) NW_LMgr_Box_GetPropertyValue (box, NW_CSS_Prop_visibility,
                                         NW_CSS_ValueType_Token, &visibilityVal);
    if ((visibilityVal.token == NW_CSS_PropValue_hidden) ||
        (visibilityVal.token == NW_CSS_PropValue_collapse)) 
      {
      NW_THROW_SUCCESS(status);
      }

    /* make the box draw itself */
    status = NW_LMgr_Box_Draw (box, deviceContext, *hasFocus);
    _NW_THROW_ON_ERROR (status);

    /* Add the box and the clip to the cache */
    NW_Bool cachePresent = NW_LMgr_Box_Update_RenderCache (rootBox, box, &realClip, &ptr);
    if (cachePresent)
        {
      NW_THROW_OOM_ON_NULL(ptr, status);
      }
    } 
  NW_CATCH (status) 
    {
    } 
  NW_FINALLY 
    {
    // box has no child
    *skipChildren = NW_FALSE;

    if( clipRectChanged == NW_TRUE )
      {
      /* Reset the clip rect */
      deviceContext->SetClipRect( &oldClip);
      }
    return status;
    } 
  NW_END_TRY
  }

/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_GetBaseline
 * Description: Returns the baseline of a box.  The default implementation
 *              returns the bottom of the box content area as the baseline.
 * Returns:     KBrsrSuccess, KBrsrOutOfMemory.
 */
 
NW_GDI_Metric_t
_NW_LMgr_Box_GetBaseline(NW_LMgr_Box_t* box){

  NW_ASSERT(box != NULL);

  return (NW_GDI_Metric_t)(NW_LMgr_Box_GetFormatBounds(box).dimension.height);
}

/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_Shift
 * Description: Shifts the contents of the box by a given offset.  The default
 *              implementation simply modifies the box boundaries.
 * Returns:     KBrsrSuccess
 */
 
TBrowserStatusCode
_NW_LMgr_Box_Shift (NW_LMgr_Box_t* box, NW_GDI_Point2D_t *delta){

  NW_ASSERT(box != NULL);

  NW_GDI_Rectangle_t boxBounds = NW_LMgr_Box_GetFormatBounds( box );
  boxBounds.point.x = (NW_GDI_Metric_t)(boxBounds.point.x + delta->x);
  boxBounds.point.y = (NW_GDI_Metric_t)(boxBounds.point.y + delta->y);
  NW_LMgr_Box_SetFormatBounds( box, boxBounds );

  return KBrsrSuccess;
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_Clone
 * Description:  Clone returns a "deep" copy of the box, where the actual definition of
 *               "deep" is up to the individual box type.  The default implementation
 *               fails.  Only the ContainerBox and its descendants have
 *               meaningful implementations at present, because they are the only
 *               ones that need it.  TODO:  Fix this.
 * Returns:      NULL.
 */

NW_LMgr_Box_t*
_NW_LMgr_Box_Clone (NW_LMgr_Box_t* box){

  NW_REQUIRED_PARAM(box);
  NW_ASSERT(0);

  return NULL;
}

/* ------------------------------------------------------------------------- *
   protected methods
 * ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- *
   public methods
 * ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_GetRawProperty
 * Description: Tries to get a property from the box's own property list.
 *              Property inheritance is ignored.
 * Returns:     KBrsrSuccess, KBrsrNotFound.
 */
 
TBrowserStatusCode
NW_LMgr_Box_GetRawProperty(NW_LMgr_Box_t *box,
                           NW_LMgr_PropertyName_t name,
                           NW_LMgr_Property_t* property)
{
  TBrowserStatusCode status;
  NW_LMgr_Property_t origProperty;

  NW_ASSERT(box != NULL);

  if(box->propList != NULL){
    status = NW_LMgr_PropertyList_Get(box->propList, name, &origProperty);
    if (status != KBrsrSuccess) {
      return KBrsrNotFound;
    }

    property->type = (NW_LMgr_PropertyValueType_t)(origProperty.type & NW_CSS_ValueType_Mask);
    property->value = origProperty.value;

    status = KBrsrSuccess;
  }
  else {
    status = KBrsrNotFound;
  }

  return status;
}

/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_GetPropertyFromList
 * Description: Tries to get a property from the box's own property list.
 *              Property inheritance is ignored.
 * Returns:     KBrsrSuccess, KBrsrNotFound.
 */
 
TBrowserStatusCode
NW_LMgr_Box_GetPropertyFromList(NW_LMgr_Box_t* box,
                                NW_LMgr_PropertyName_t name,
                                NW_LMgr_Property_t* property) 
  {
  TBrowserStatusCode status;
  NW_LMgr_Property_t origProperty;
  NW_Bool specialProperty, isMargin = NW_FALSE, isMarker = NW_FALSE;

  NW_ASSERT(box != NULL);

  if( box->propList )
    {
    // In Vertical Layout Mode, table, tr, td, th need to ignore margin, padding,
    // border, whitespace. This special handling is done in 
    // NW_LMgr_VerticalTableBox_GetPropertyFromList.
    // For rest of the properties (specialProperty flag is false) we handle them
    // the normal way
    if (NW_Object_IsClass(box, &NW_LMgr_VerticalTableBox_Class) ||
        NW_Object_IsClass(box, &NW_LMgr_VerticalTableCellBox_Class) ||
        NW_Object_IsClass(box, &NW_LMgr_VerticalTableRowBox_Class))
      {
      status = NW_LMgr_VerticalTableBox_GetPropertyFromList(box, name, property, &specialProperty);
      if (specialProperty)
        {
        return status;
        }
      }
    
    if(NW_Object_IsInstanceOf(box, &LMgrMarkerImage_Class) || NW_Object_IsInstanceOf(box, &LMgrMarkerText_Class))
      {
      isMarker = NW_TRUE;
      }
    if( NW_LMgr_RootBox_GetSmallScreenOn( NW_LMgr_Box_GetRootBox( box ) ) )
      {
      if((name == NW_CSS_Prop_margin) || (name == NW_CSS_Prop_leftMargin) ||
         (name == NW_CSS_Prop_rightMargin) || (name == NW_CSS_Prop_topMargin) ||
         (name == NW_CSS_Prop_bottomMargin) )
        {
        isMargin = NW_TRUE;
        if( NW_Object_IsDerivedFrom(box, &NW_LMgr_ImgContainerBox_Class) && !isMarker)
          {
          return KBrsrNotFound;
          }
        }
      }
    
    status = NW_LMgr_PropertyList_Get(box->propList, name, &origProperty);
    if (status != KBrsrSuccess) 
      {
      return KBrsrNotFound;
      }
    
    if(isMargin && !isMarker)
      {
      if(origProperty.value.integer < 0)
        {
        property->value.integer = 0;
        return KBrsrSuccess;
        }
      }
    
    *property = origProperty;
    status = NW_LMgr_Box_ResolveRelativeProperty (box, name, property);
    if (status != KBrsrSuccess) 
      {
      return KBrsrNotFound;
      }
    
    property->type = (NW_LMgr_PropertyValueType_t)(property->type & NW_CSS_ValueType_Mask);
    
    status = KBrsrSuccess;
    }
  else 
    {
    status = KBrsrNotFound;
    }

  return status;
  }

/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_GetProperty
 * Description: Tries to get a property from the box's own property list.
 *              If the property is not found, and the property is inherited,
 *              it queries the ancestors for it.
 * Returns:     KBrsrSuccess, KBrsrNotFound.
 */
 
TBrowserStatusCode
NW_LMgr_Box_GetProperty (NW_LMgr_Box_t* box, 
                         NW_LMgr_PropertyName_t name, 
                         NW_LMgr_Property_t* property)
  {
  NW_LMgr_Box_t* childBox = box;
  NW_Bool lookingForInheritProp = NW_FALSE;
  // parameter assertion block 
  NW_ASSERT (NW_Object_IsInstanceOf (box, &NW_LMgr_Box_Class));

  do 
    {
    TBrowserStatusCode status;
    NW_LMgr_Property_t p;

    status = NW_LMgr_Box_GetPropertyFromList(box, name, &p);
    if( status == KBrsrSuccess ) 
      {
      if( p.type != NW_CSS_ValueType_Token ||
          p.value.token != NW_CSS_PropValue_inherit) 
        {
        // if we are looking for inherit property, then
        // first make sure that the property value did not get resolved
        // while calling NW_LMgr_Box_GetPropertyFromList on the parent box.
        // if it was modified, then we need to take a look at the 
        // original type to check if resolving the value is appropriate here.
        // for examp: parent has 50% as height which gets resolved to 100px,
        // so then we get the inherited value as 100px instead of the correct 
        // 50% (50px) 
        if( lookingForInheritProp == NW_TRUE && box->propList )
          {
          NW_LMgr_Property_t origProperty;
          status = NW_LMgr_PropertyList_Get( box->propList, name, &origProperty );
          if( status == KBrsrSuccess && origProperty.type != p.type )
            {
            // resolve the original value on the child now
            status = NW_LMgr_Box_ResolveRelativeProperty( childBox, name, &origProperty);
            if( status == KBrsrSuccess )
              {
              *property = origProperty;
              property->type =
                  (NW_LMgr_PropertyValueType_t) (property->type & NW_CSS_ValueType_Mask);
              return KBrsrSuccess;
              }
            }
          }
        *property = p;
        property->type =
            (NW_LMgr_PropertyValueType_t) (property->type & NW_CSS_ValueType_Mask);
        return KBrsrSuccess;
        }
      } 
    else 
      {
      if (!(name & NW_CSS_PropInherit)) 
        {
        // drop out and return "not found" 
        break; 
        }
      }
    // The prop is inherit 
    lookingForInheritProp = NW_TRUE;
    box = (NW_LMgr_Box_t*) NW_LMgr_Box_GetParent (box);
    if( !box ) 
      {
      break;
      }
    // note: Allow reading direction property from anonymous box 
    if (name != NW_CSS_Prop_textDirection) 
      {
      // Check if the parent is an anonymous box 
      if (NW_Object_IsInstanceOf(box, &LMgrAnonBlock_Class)) 
        {
          // this parent is an anonymous box, we should go up to see if grandpa has 
          // the prop we are interested. 
          box = (NW_LMgr_Box_t*) NW_LMgr_Box_GetParent( box );
        }
      }
    } while( box );
    
  // the property was not found 
  return KBrsrNotFound;
  }

/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_GetPropertyValue
 * Description: Same as GetProperty, only the type of the property is not returned.
 * Returns:     KBrsrSuccess, KBrsrNotFound.
 */

/* TODO: This method should go away.  We should always query for the property type.
 */

TBrowserStatusCode
NW_LMgr_Box_GetPropertyValue (NW_LMgr_Box_t *box, 
                              NW_LMgr_PropertyName_t name, 
                              NW_LMgr_PropertyValueType_t type,
                              NW_LMgr_PropertyValue_t *value)
{
  NW_LMgr_Property_t property;
  TBrowserStatusCode status;
  NW_LMgr_RootBox_t* rootBox;
  NW_Bool flag;
  NW_Bool inMarquee = NW_FALSE;

  NW_ASSERT(box != NULL);

  status = NW_LMgr_Box_GetProperty (box, name, &property);
  if (status != KBrsrSuccess) {
    return status;
  }

  if (type == (property.type & NW_CSS_ValueType_Mask)) 
    {
    *value = property.value;
    rootBox = NW_LMgr_Box_GetRootBox( box );
    flag = NW_LMgr_RootBox_GetSmallScreenOn( rootBox );

    if (NW_Object_IsInstanceOf(box, &NW_LMgr_BidiFlowBox_Class))
    {
      /* we want to limit the width of the FlowBoxes to be the display width 
         in vertical layout mode
      */
      if ((name == NW_CSS_Prop_width) && flag)
      {
        CGDIDeviceContext* deviceContext;
        const NW_GDI_Rectangle_t* rectangle;
        
        deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
        rectangle = deviceContext->DisplayBounds();

        if (value->integer > rectangle->dimension.width)
        {
          value->integer = (NW_Uint32)(rectangle->dimension.width-4);
        }
      }
    }
    /* In vertical layout mode, we want to ignore the whitespace property */
    if ((name == NW_CSS_Prop_whitespace) && flag)
    {
    while( box != NULL )
      {
      if( NW_Object_IsClass( box, &NW_LMgr_MarqueeBox_Class ) == NW_TRUE )
        {
        inMarquee = NW_TRUE; 
        break;
        }
      if (!box->parent)
        {
        break;
        }
      box = NW_LMgr_BoxOf( box->parent );
      }
    if (!inMarquee) 
      {
      if (value->token == NW_CSS_PropValue_pre) 
        {
        value->token = NW_CSS_PropValue_flags_smallScreenPre;
        } else {
        value->token = NW_CSS_PropValue_normal;
          }
      }
    }
    return KBrsrSuccess;
  } else {
    return KBrsrNotFound;
  }
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_SetProperty
 * Description:  Sets a property on a box.
 * Returns:      KBrsrSuccess if successful; KBrsrOutOfMemory if
 *               out of memory.
 */

TBrowserStatusCode
NW_LMgr_Box_SetProperty (NW_LMgr_Box_t* box,
                         NW_LMgr_PropertyName_t name,
                         NW_LMgr_Property_t* property)
{
  NW_TRY (status) {
    NW_ASSERT(box != NULL);

    if (box->propList == NULL) {
      box->propList =
        (NW_LMgr_PropertyList_t*) NW_LMgr_SimplePropertyList_New( 2, 10 );
      NW_THROW_OOM_ON_NULL (box->propList, status);
    }
  
    status = NW_LMgr_PropertyList_Set (box->propList, name, property);
    _NW_THROW_ON_ERROR (status);

} NW_CATCH (status) {
  } NW_FINALLY {
   return status;
  } NW_END_TRY
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_RemoveProperty
 * Description:  Removes a property from a box.
 * Returns:      KBrsrSuccess if successful; KBrsrOutOfMemory if
 *               out of memory.
 */

TBrowserStatusCode
NW_LMgr_Box_RemoveProperty (NW_LMgr_Box_t* box,
                            NW_LMgr_PropertyName_t name)
{
  TBrowserStatusCode status = KBrsrSuccess;

  NW_ASSERT(box != NULL);

  if (box->propList != NULL) {
    status = NW_LMgr_PropertyList_Remove (box->propList, name);
  }

  return status;
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_RemovePropertyWithoutDelete
 * Description:  Removes a property from a box; however, does NOT delete the property
 *               Only for simple property list
 * Returns:      KBrsrSuccess if successful; KBrsrOutOfMemory if
 *               out of memory.
 */

TBrowserStatusCode
NW_LMgr_Box_RemovePropertyWithoutDelete (NW_LMgr_Box_t* box,
                                         NW_LMgr_PropertyName_t name)
    {
    TBrowserStatusCode status = KBrsrSuccess;

    NW_ASSERT(box != NULL);
    NW_ASSERT( NW_Object_IsInstanceOf(box->propList, &NW_LMgr_SimplePropertyList_Class) );

    if (box->propList != NULL) 
        {
        status = NW_LMgr_SimplePropertyList_RemoveWithoutDelete (
                                                 (NW_LMgr_SimplePropertyList_t*)(box->propList), 
                                                 name);
        }

    return status;
    }

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_ApplyFontProps
 * Description:  Use the CSS properties of a text box to match a GDI font and cache
 *               this as the NW_Prop_GDI_Font property. The allocates a font object
 *               which needs to be freed when the box is destroyed.
 * Returns:     KBrsrSuccess, KBrsrOutOfMemory.
 */
TBrowserStatusCode
NW_LMgr_Box_ApplyFontProps (NW_LMgr_Box_t* box)
    {
    NW_LMgr_Property_t fontProp;

    fontProp.type = NW_CSS_ValueType_Font;
    fontProp.value.object = NULL;

    NW_TRY (status) 
        {
        NW_LMgr_RootBox_t* rootBox;
        CGDIDeviceContext* deviceContext;
        NW_LMgr_Property_t fontFamily;
        NW_LMgr_Property_t size;
        NW_LMgr_Property_t style;
        NW_LMgr_Property_t weight;
        NW_LMgr_Property_t variant;
        NW_Uint8 gdiFontStyle;
        NW_Uint8 gdiFontVariant;
        TBrowserStatusCode s1, s2, s3, s4, s5;

        /* Check whether the properties have already been applied */
        NW_LMgr_Box_GetPropertyFromList (box, NW_CSS_Prop_fontObject, &fontProp);
        if (fontProp.value.object != NULL) 
            {
            return KBrsrSuccess;
            }

        // Get the properties from the box property list
        s1 = NW_LMgr_Box_GetPropertyFromList (box, NW_CSS_Prop_fontFamily, &fontFamily);
        s2 = NW_LMgr_Box_GetPropertyFromList (box, NW_CSS_Prop_fontSize, &size);
        s3 = NW_LMgr_Box_GetPropertyFromList (box, NW_CSS_Prop_fontStyle, &style);
        s4 = NW_LMgr_Box_GetPropertyFromList (box, NW_CSS_Prop_fontWeight, &weight);
        s5 = NW_LMgr_Box_GetPropertyFromList (box, NW_CSS_Prop_fontVariant, &variant);

        // If there are no properties to apply, we return.  If the box is the root,
        // we must apply the properties at all times. 
        if (s1 == KBrsrNotFound && s2 == KBrsrNotFound && s3 == KBrsrNotFound && 
        s4 == KBrsrNotFound && s5 == KBrsrNotFound && box->parent != NULL) 
            {
            return KBrsrSuccess;
            }    

        // Set defaults
        fontFamily.value.object = const_cast<NW_Text_t*>(KGDIFontDefaultFamily);
        size.value.integer = KGDIFontZeroSize;
        style.value.token = NW_CSS_PropValue_normal;
        weight.value.integer = KGDIFontDefaultWeight;
        variant.value.token = NW_CSS_PropValue_normal;

        // Now take into account inheritance
        NW_LMgr_Box_GetProperty (box, NW_CSS_Prop_fontFamily, &fontFamily);
        NW_LMgr_Box_GetProperty (box, NW_CSS_Prop_fontSize, &size);
        NW_LMgr_Box_GetProperty (box, NW_CSS_Prop_fontStyle, &style);
        NW_LMgr_Box_GetProperty (box, NW_CSS_Prop_fontWeight, &weight);
        NW_LMgr_Box_GetProperty (box, NW_CSS_Prop_fontVariant, &variant);

        // For negative value, use default font size
        if ( size.value.integer < 0 )
            {
            size.value.decimal = KGDIFontDefaultSizeInPt;
            size.type = NW_CSS_ValueType_Pt;
            }

        // Check the device resolution in order to resolve the correct font size for the device
        CEikonEnv* eikEnv = CEikonEnv::Static();
        CWsScreenDevice& screenDev = *eikEnv->ScreenDevice();

        // we are using pixels to pass off to the device context, from there they get converted to twips
        TInt px = 0;

        if (size.type == NW_CSS_ValueType_Pt)
            {
            TInt valInt = (TInt)NW_Math_round(size.value.decimal);

            px = screenDev.VerticalTwipsToPixels(FontUtils::TwipsFromPoints(valInt));

            size.type = NW_CSS_ValueType_Px;
            size.value.integer = px;
            }
        else if (size.type == NW_CSS_ValueType_Px)
            {
            TUint dpi = screenDev.VerticalTwipsToPixels(KTwipsPerInch);

            // Since web designers assume a 96 pixel per inch (ppi) display use that as the reference point. 
            // Thus the multiplier should be:
            // ppi/96
            // Below is a list of the density of commercially available LCD displays. 
            // Density Multiplier:
            // 400 ppi	4.2
            // 210 ppi	2.2
            // 200 ppi	2.1
            // 120 ppi	1.3
            // 100 ppi	1.0
            // 96 ppi   1.0       
            if ((200 > dpi) && (dpi > 120))
                {
                px = (TInt)((float)size.value.integer * 1.3);
                }
            else if ((210 > dpi) && (dpi > 200))
                {
                px = (TInt)((float)size.value.integer * 2.1);
                }
            else if ((400 > dpi) && (dpi > 210))
                {
                px = (TInt)((float)size.value.integer * 2.2);
                }
            else if (dpi > 400)
                {
                px = (TInt)((float)size.value.integer * 4.2);
                }

            size.value.integer = px;
            }

        switch (style.value.token)  
            {
            case NW_CSS_PropValue_oblique:
                gdiFontStyle = EGDIFontStyleOblique;
                break;

            case NW_CSS_PropValue_italic:
                gdiFontStyle = EGDIFontStyleItalic;
                break;

            default:
                gdiFontStyle = KGDIFontDefaultStyle;
            }

        switch (variant.value.token) 
            {
            case NW_CSS_PropValue_smallcaps:
                gdiFontVariant = EGDIFontVariantSmallCaps;
                break;

            default:
                gdiFontVariant = KGDIFontDefaultVariant;
            }

        // we're going to need the DeviceContext to create Font
        rootBox = NW_LMgr_Box_GetRootBox (box);
        NW_ASSERT (rootBox != NULL);

        deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
        NW_ASSERT (deviceContext != NULL);

        fontProp.type = NW_CSS_ValueType_Font;
        fontProp.value.object =
        deviceContext->CreateFont ((NW_Text_t*) fontFamily.value.object,
                                 (TGDIFontStyle) gdiFontStyle,
                                 (NW_Uint8) size.value.integer,
                                 (NW_Uint16) weight.value.integer,
                                 (TGDIFontVariant) gdiFontVariant);
        NW_THROW_OOM_ON_NULL (fontProp.value.object, status);

        // Add the computed GDI font to the property list
        status = NW_LMgr_Box_SetProperty (NW_LMgr_BoxOf(box),
                                      NW_CSS_Prop_fontObject, &fontProp);

        _NW_THROW_ON_ERROR (status);

        } 
    NW_CATCH (status) 
        {
        delete (CGDIFont*)fontProp.value.object;
        } 
    NW_FINALLY 
        {
        return status;
        } 
    NW_END_TRY
    }

/* ------------------------------------------------------------------------- *
 * Function:    NW_LMgr_Box_GetFont
 * Description: Get the GDI font handle.
 * Returns:     KBrsrSuccess, KBrsrOutOfMemory.
 */

CGDIFont*
NW_LMgr_Box_GetFont (NW_LMgr_Box_t* box)
{
  TBrowserStatusCode status;
  NW_LMgr_PropertyValue_t font;

  NW_ASSERT(box != NULL);

  font.object = NULL;

  /* If GDI font handle prop is set, return it */
  status = NW_LMgr_Box_GetPropertyValue (box, NW_CSS_Prop_fontObject, NW_CSS_ValueType_Font, &font);
  if (status == KBrsrSuccess) {
    return (CGDIFont*) font.object;
  }
  else {
    return NULL;
  }
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetModelProp
 * Description:  Returns a single box-model property for the box
 *               (as opposed to GetModelProps which returns the values for
 *               all sides of the box).
 * Returns:      Property value.
 */

/* TODO: move all this to GetValueProp */

NW_Int32
NW_LMgr_Box_GetModelProp(NW_LMgr_Box_t *box, NW_LMgr_PropertyName_t propName) 
{
  NW_LMgr_Property_t prop;
  NW_LMgr_PropertyName_t shortcutProp;
  NW_LMgr_PropertyValueType_t defaultPropType;
  NW_Bool doInherit = NW_FALSE;
  TBrowserStatusCode status;

  switch (propName) {
  case NW_CSS_Prop_topBorderWidth:
  case NW_CSS_Prop_bottomBorderWidth:
  case NW_CSS_Prop_leftBorderWidth:
  case NW_CSS_Prop_rightBorderWidth:

    shortcutProp = NW_CSS_Prop_borderWidth;
    defaultPropType = NW_CSS_ValueType_Px;
    break;

  case NW_CSS_Prop_topBorderStyle:
  case NW_CSS_Prop_bottomBorderStyle:
  case NW_CSS_Prop_leftBorderStyle:
  case NW_CSS_Prop_rightBorderStyle:

    shortcutProp = NW_CSS_Prop_borderStyle;
    defaultPropType = NW_CSS_ValueType_Token;
    break;

  case NW_CSS_Prop_topBorderColor:
  case NW_CSS_Prop_bottomBorderColor:
  case NW_CSS_Prop_leftBorderColor:
  case NW_CSS_Prop_rightBorderColor:

    shortcutProp = NW_CSS_Prop_borderColor;
    defaultPropType = NW_CSS_ValueType_Color;
    break;

  case NW_CSS_Prop_topPadding:
  case NW_CSS_Prop_bottomPadding:
  case NW_CSS_Prop_leftPadding:
  case NW_CSS_Prop_rightPadding:

    shortcutProp = NW_CSS_Prop_padding;
    defaultPropType = NW_CSS_ValueType_Px;
    break;

  case NW_CSS_Prop_topMargin:
  case NW_CSS_Prop_bottomMargin:
  case NW_CSS_Prop_leftMargin:
  case NW_CSS_Prop_rightMargin:

    shortcutProp = NW_CSS_Prop_margin;
    defaultPropType = NW_CSS_ValueType_Px;
    break;

  default:
    NW_ASSERT(0);
    return 0;
  }

  status = NW_LMgr_Box_GetPropertyFromList(box, propName, &prop);
  if (status == KBrsrSuccess) {
    if ((prop.type == NW_CSS_ValueType_Token) && (prop.value.token == NW_CSS_PropValue_inherit)) {
      doInherit = NW_TRUE;
    }
    else if (prop.type == defaultPropType) {
      if ((shortcutProp == NW_CSS_Prop_padding) || (shortcutProp == NW_CSS_Prop_borderWidth)) {
        if (prop.value.integer < 0) {
          return 0;
        }
      }
      return prop.value.integer;
    }
    else if (shortcutProp == NW_CSS_Prop_margin) {
      /* Special handling of auto margins */
      if ((prop.type == NW_CSS_ValueType_Token) && (prop.value.token == NW_CSS_PropValue_auto)) {
        return NW_LMgr_FrameInfo_AutoMargin;
      }
    }
  }
  status = NW_LMgr_Box_GetPropertyFromList(box, shortcutProp, &prop);
  if (status == KBrsrSuccess) {
    if ((prop.type == NW_CSS_ValueType_Token) && (prop.value.token == NW_CSS_PropValue_inherit)) {
      doInherit = NW_TRUE;
    }
    else if (prop.type == defaultPropType) {
      if ((shortcutProp == NW_CSS_Prop_padding) || (shortcutProp == NW_CSS_Prop_borderWidth)) {
        if (prop.value.integer < 0) {
          return 0;
        }
      }
      return prop.value.integer;
    }
    else if (shortcutProp == NW_CSS_Prop_margin) {
      /* Special handling of auto margins */
      if ((prop.type == NW_CSS_ValueType_Token) && (prop.value.token == NW_CSS_PropValue_auto)) {
        return NW_LMgr_FrameInfo_AutoMargin;
      }
    }
  }

  if (doInherit && box->parent) 
  {
    if (NW_Object_IsInstanceOf(box->parent, &LMgrAnonBlock_Class)) 
    {
     // this parent is an anonymous box, we should go up to see if grandpa has 
      //  the prop we are interested. 
      box = (NW_LMgr_Box_t*) NW_LMgr_Box_GetParent (box);
      if (box->parent == NULL) {
        return 0;
      }
    }
    return NW_LMgr_Box_GetModelProp((NW_LMgr_Box_t*)(box->parent), propName);
  }

  /* Otherwise return defaults */
  if (shortcutProp == NW_CSS_Prop_borderColor) {
    NW_LMgr_PropertyValue_t color;
    color.integer = 0;
    status = NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_color, NW_CSS_ValueType_Color, &color);
    return color.integer;
  }
  else if (shortcutProp == NW_CSS_Prop_borderWidth) 
  {
    if (NW_Object_IsDerivedFrom(box, &NW_LMgr_ImgContainerBox_Class))
    {
      return (NW_LMgr_ImgContainerBox_ImageIsBroken(box) == NW_TRUE) ?
        NW_CSS_PropValue_none : NW_LMgr_Box_MinBorderWidth;
    }
    else
    {
      return NW_LMgr_Box_MediumBorderWidth;
    }
  }
  else if (shortcutProp == NW_CSS_Prop_borderStyle) {
    if (NW_Object_IsDerivedFrom(box, &NW_LMgr_ImgContainerBox_Class) && 
        NW_LMgr_ImgContainerBox_ImageIsBroken( box ) == NW_TRUE )
    {
      return NW_CSS_PropValue_solid;
    }
    return NW_CSS_PropValue_none;
  }
  else {
    return 0;
  }
}


/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetBorderWidth
 * Description:  Calculates the width of the box border on all four sides
 *               and stores it in borderWidth.  
 * Returns:      void.
 */

void
NW_LMgr_Box_GetBorderWidth(NW_LMgr_Box_t *box,
                           NW_LMgr_FrameInfo_t *borderWidth, 
                           NW_Int8 aFrameSide )
{
  NW_LMgr_FrameInfo_t borderStyle;

  borderWidth->left = 0;
  borderWidth->right = 0;
  borderWidth->top = 0;
  borderWidth->bottom = 0;

  /* set the width to zero if the box style is "none" */
  NW_LMgr_Box_GetBorderStyle( box, &borderStyle, aFrameSide );

  if( ( aFrameSide & ELMgrFrameLeft ) && 
      borderStyle.left != NW_CSS_PropValue_none && borderStyle.left != NW_CSS_PropValue_hidden )
    {
    borderWidth->left = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_leftBorderWidth);
  }
  if( ( aFrameSide & ELMgrFrameBottom ) && 
      borderStyle.bottom != NW_CSS_PropValue_none && borderStyle.bottom != NW_CSS_PropValue_hidden )
    {
    borderWidth->bottom = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_bottomBorderWidth);
  }
  if( ( aFrameSide & ELMgrFrameTop ) && 
      borderStyle.top != NW_CSS_PropValue_none && borderStyle.top != NW_CSS_PropValue_hidden )      
    {
    borderWidth->top = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_topBorderWidth);
  }
  if( ( aFrameSide & ELMgrFrameRight ) && 
    borderStyle.right != NW_CSS_PropValue_none && borderStyle.right != NW_CSS_PropValue_hidden )
    {
    borderWidth->right = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_rightBorderWidth);
  }
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetBorderStyle
 * Description:  Gets a set of box border-style properties
 *               (left, right, top, bottom) and stores them in borderStyle.  
 * Returns:      void (in case no property are set, the default value of 0
 *               is returned for the property value).
 */

void
NW_LMgr_Box_GetBorderStyle(NW_LMgr_Box_t *box,
                           NW_LMgr_FrameInfo_t* borderStyle,
                           NW_Int8 aFrameSide )
  {
  // init
  borderStyle->left = 0;
  borderStyle->right = 0;
  borderStyle->top = 0;
  borderStyle->bottom = 0;
  //
  if( aFrameSide & ELMgrFrameLeft )
{
  borderStyle->left = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_leftBorderStyle);
    }
  if( aFrameSide & ELMgrFrameRight )
    {
  borderStyle->right = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_rightBorderStyle);
    }
  if( aFrameSide & ELMgrFrameTop )
    {
  borderStyle->top = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_topBorderStyle);
    }
  if( aFrameSide & ELMgrFrameBottom )
    {
  borderStyle->bottom = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_bottomBorderStyle);
    }
  }

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetBorderColor
 * Description:  Gets a set of box border-color properties
 *               (left, right, top, bottom) and stores them in borderColor.  
 * Returns:      void (in case no property are set, the default value of 0
 *               is returned for the property value).
 */

void
NW_LMgr_Box_GetBorderColor(NW_LMgr_Box_t *box,
                           NW_LMgr_FrameInfo_t *borderColor)
{
  borderColor->left = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_leftBorderColor);
  borderColor->right = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_rightBorderColor);
  borderColor->top = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_topBorderColor);
  borderColor->bottom = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_bottomBorderColor);
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetMargins
 * Description:  Calculates the width of the box margin on all four sides
 *               and stores it in "margins".  
 * Returns:      void.
 */

void
NW_LMgr_Box_GetMargins(NW_LMgr_Box_t *box,
                       NW_LMgr_FrameInfo_t *margins,
                       NW_LMgr_FrameInfo_t* isAuto,
                       NW_Int8 aFrameSide )
{
  NW_LMgr_RootBox_t* rootBox;

  if (isAuto) 
    {
    NW_Mem_memset(isAuto, 0, sizeof(NW_LMgr_FrameInfo_t));
    }

  if( aFrameSide & ELMgrFrameLeft )
    {
    margins->left = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_leftMargin);
    }
  if( aFrameSide & ELMgrFrameRight )
    {
    margins->right = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_rightMargin);
    }
  if( aFrameSide & ELMgrFrameTop )
    {
    margins->top = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_topMargin);
    }
  if( aFrameSide & ELMgrFrameBottom )
    {
    margins->bottom = NW_LMgr_Box_GetModelProp(box, NW_CSS_Prop_bottomMargin);
    }

  if( ( aFrameSide & ELMgrFrameLeft ) && margins->left == NW_LMgr_FrameInfo_Auto) 
    {
    margins->left = 0;
    if (isAuto) 
      {
      isAuto->left = 1;
      }
    }
  if( ( aFrameSide & ELMgrFrameRight ) && margins->right == NW_LMgr_FrameInfo_Auto) 
    {
    margins->right = 0;
    if (isAuto) 
      {
      isAuto->right = 1;
      }
    }
  if( ( aFrameSide & ELMgrFrameTop ) && margins->top == NW_LMgr_FrameInfo_Auto) 
    {
    margins->top = 0;
    if (isAuto) 
      {
      isAuto->top = 1;
      }
    }
  if( ( aFrameSide & ELMgrFrameBottom ) && margins->bottom == NW_LMgr_FrameInfo_Auto) 
    {
    margins->bottom = 0;
    if (isAuto) 
      {
      isAuto->bottom = 1;
      }
    }

  rootBox = NW_LMgr_Box_GetRootBox(box);
  if( NW_LMgr_RootBox_GetSmallScreenOn( rootBox ) )
  {
    CGDIDeviceContext* deviceContext;
    const NW_GDI_Rectangle_t* rectangle;

    /* We want to limit the margin to 15% of display width */
    if ((margins->left != NW_LMgr_FrameInfo_Auto) || (margins->right != NW_LMgr_FrameInfo_Auto))
    {
      NW_GDI_Metric_t maxMargin = 0;
      deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
      rectangle = deviceContext->DisplayBounds();
      maxMargin = (NW_GDI_Metric_t)(rectangle->dimension.width*15/100);

      if( ( aFrameSide & ELMgrFrameLeft ) && margins->left > maxMargin)
      {
        margins->left = maxMargin;
      }
      if( ( aFrameSide & ELMgrFrameRight ) && margins->right > maxMargin)
      {
        margins->right = maxMargin;
      }
    }
  }
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetPadding
 * Description:  Calculates the width of the box padding on all four sides
 *               and stores it in "padding".  
 * Returns:      void
 */

void
NW_LMgr_Box_GetPadding(NW_LMgr_Box_t *box, 
                        NW_LMgr_FrameInfo_t* padding,
                        NW_Int8 aFrameSide )
  {
  // init
  padding->left = 0;
  padding->right = 0;
  padding->top = 0;
  padding->bottom = 0;
  //
  if( aFrameSide & ELMgrFrameLeft )
    {
    padding->left = NW_LMgr_Box_GetModelProp( box, NW_CSS_Prop_leftPadding );
    }
  if( aFrameSide & ELMgrFrameRight )
    {
    padding->right = NW_LMgr_Box_GetModelProp( box, NW_CSS_Prop_rightPadding );
    }
  if( aFrameSide & ELMgrFrameTop )
    {
    padding->top = NW_LMgr_Box_GetModelProp( box, NW_CSS_Prop_topPadding );
    }
  if( aFrameSide & ELMgrFrameBottom )
    {
    padding->bottom = NW_LMgr_Box_GetModelProp( box, NW_CSS_Prop_bottomPadding );
    }
  }


/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_DrawSolidBorder
 * Description:  Draws a solid border around the content of the box,
                 using the current boundaries of the box.  
 * Returns:      KBrsrSuccess, KBrsrFailure (?), KBrsrOutOfMemory.
 */

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_DrawSolidBorder
 * Description:  Draws a solid border around the content of the box,
                 using the current boundaries of the box.  
 * Returns:      KBrsrSuccess, KBrsrFailure (?), KBrsrOutOfMemory.
 */

TBrowserStatusCode
NW_LMgr_Box_DrawBorder (NW_GDI_Rectangle_t bounds, 
                        CGDIDeviceContext*  deviceContext,
                        NW_LMgr_FrameInfo_t* borderWidth, 
                        NW_LMgr_FrameInfo_t* borderStyle, 
                        NW_LMgr_FrameInfo_t* borderColor)
{
  NW_GDI_Color_t oldFg;
  NW_GDI_Pattern_t oldPat;

  oldFg = deviceContext->ForegroundColor();
  oldPat = deviceContext->LinePattern();

  NW_TRY (status) {
    NW_GDI_Metric_t innerWidth, innerHeight;
    NW_Uint8 i;
    NW_GDI_Point2D_t vertices[2];
    NW_Float32 ratioTopLeft=0, ratioBottomLeft=0, ratioTopRight=0, ratioBottomRight=0;
    NW_Float32 ratioLeftTop=0, ratioLeftBottom=0, ratioRightTop=0, ratioRightBottom=0;

    innerWidth = (NW_GDI_Metric_t)(bounds.dimension.width - borderWidth->left - borderWidth->right);
    innerHeight = (NW_GDI_Metric_t)(bounds.dimension.height - borderWidth->top - borderWidth->bottom);

    if (borderWidth->right == 0) {
      ratioTopRight = 0;
    } else {
      ratioTopRight = ((NW_Float32)borderWidth->top)/((NW_Float32)borderWidth->right);
    }
    if (ratioTopRight > 0) {
      ratioRightTop = 1/ratioTopRight;
    }

    if (borderWidth->right == 0) {
      ratioBottomRight = 0;
    } else {
      ratioBottomRight = ((NW_Float32)borderWidth->bottom)/((NW_Float32)borderWidth->right);
    }
    if (ratioBottomRight > 0) {
      ratioRightBottom = 1/ratioBottomRight;
    }

    if (borderWidth->left == 0) {
      ratioTopLeft = 0;
    } else {
      ratioTopLeft = ((NW_Float32)borderWidth->top)/((NW_Float32)borderWidth->left);
    }
    if (ratioTopLeft > 0) {
      ratioLeftTop = 1/ratioTopLeft;
    }

    if (borderWidth->left == 0) {
      ratioBottomLeft = 0;
    } else {
      ratioBottomLeft = ((NW_Float32)borderWidth->bottom)/((NW_Float32)borderWidth->left);
    }
    if (ratioBottomLeft > 0) {
      ratioLeftBottom = 1/ratioBottomLeft;
    }
    
    /* draw top border */
    if (borderWidth->top > 0)
    {
      if ( borderColor->top == NW_GDI_Color_Transparent) {
        borderStyle->top = NW_CSS_PropValue_none;
      } else {
        deviceContext->SetForegroundColor( borderColor->top);
      }
      deviceContext->SetLinePattern( NW_LMgr_Box_ConvertBorderStyle(borderStyle->top));
    
      for (i=0; i<borderWidth->top; i++) {
        if (borderStyle->top == NW_CSS_PropValue_solid ||
            borderStyle->top == NW_CSS_PropValue_dashed ||
            borderStyle->top == NW_CSS_PropValue_dotted) {
          vertices[0].x = (NW_GDI_Metric_t)(bounds.point.x + i*ratioLeftTop);
          vertices[0].y = vertices[1].y = (NW_GDI_Metric_t)(bounds.point.y + i);
          vertices[1].x = (NW_GDI_Metric_t)(bounds.point.x + bounds.dimension.width - i*ratioRightTop - 1);
        } else if (borderStyle->top == NW_CSS_PropValue_bevelled) {
          if (i >= innerWidth/2) {
            continue;
          }
          vertices[0].x = (NW_GDI_Metric_t)(bounds.point.x + borderWidth->left + i);
          vertices[0].y = vertices[1].y = (NW_GDI_Metric_t)(bounds.point.y + borderWidth->top - i - 1);
          vertices[1].x = (NW_GDI_Metric_t)(bounds.point.x + bounds.dimension.width - borderWidth->right - i - 1);
        } else {
          // skip any unknown border styles
          continue;
        }
        status = deviceContext->DrawPolyline( 2, vertices, NW_FALSE);
        _NW_THROW_ON_ERROR(status);
      }
    }

    /* draw left border */
    if (borderWidth->left > 0)
    {
      if ( borderColor->left == NW_GDI_Color_Transparent) {
        borderStyle->left = NW_CSS_PropValue_none;
      } else {
        deviceContext->SetForegroundColor( borderColor->left);
      }
      deviceContext->SetLinePattern( NW_LMgr_Box_ConvertBorderStyle(borderStyle->left));

      for (i=0; i<borderWidth->left; i++) {
        if (borderStyle->left == NW_CSS_PropValue_solid ||
            borderStyle->left == NW_CSS_PropValue_dashed ||
            borderStyle->left == NW_CSS_PropValue_dotted) {
          vertices[0].x = vertices[1].x = (NW_GDI_Metric_t)(bounds.point.x + i);
          vertices[0].y = (NW_GDI_Metric_t)(bounds.point.y + i*ratioTopLeft);
          vertices[1].y = (NW_GDI_Metric_t)(bounds.point.y + bounds.dimension.height - i*ratioBottomLeft - 1);
        } else if (borderStyle->left == NW_CSS_PropValue_bevelled) {
          if (i >= innerHeight/2) {
            continue;
          }
          vertices[0].x = vertices[1].x = (NW_GDI_Metric_t)(bounds.point.x + borderWidth->left - i - 1);
          vertices[0].y = (NW_GDI_Metric_t)(bounds.point.y + borderWidth->top + i);
          vertices[1].y = (NW_GDI_Metric_t)(bounds.point.y + bounds.dimension.height - borderWidth->bottom - i - 1);
        } else {
          // skip any unknown border styles
          continue;
        }
        status = deviceContext->DrawPolyline( 2, vertices, NW_FALSE);
        _NW_THROW_ON_ERROR(status);
      }
    }

    /* draw bottom border */
    if (borderWidth->bottom > 0)
    {
      if ( borderColor->bottom == NW_GDI_Color_Transparent) {
        borderStyle->bottom = NW_CSS_PropValue_none;
      } else {
        deviceContext->SetForegroundColor( borderColor->bottom);
      }
      deviceContext->SetLinePattern( NW_LMgr_Box_ConvertBorderStyle(borderStyle->bottom)); 
    
      for (i=0; i<borderWidth->bottom; i++) {
        if (borderStyle->bottom == NW_CSS_PropValue_solid ||
            borderStyle->bottom == NW_CSS_PropValue_dashed ||
            borderStyle->bottom == NW_CSS_PropValue_dotted) {
          vertices[0].x = (NW_GDI_Metric_t)(bounds.point.x + i*ratioLeftBottom);
          vertices[0].y = vertices[1].y = (NW_GDI_Metric_t)(bounds.point.y + bounds.dimension.height - i - 1);
          vertices[1].x = (NW_GDI_Metric_t)(bounds.point.x + bounds.dimension.width - i*ratioRightBottom - 1);
        } else if (borderStyle->bottom == NW_CSS_PropValue_bevelled) {
          if (i >= innerWidth/2) {
            continue;
          }
          vertices[0].x = (NW_GDI_Metric_t)(bounds.point.x + borderWidth->left + i);
          vertices[0].y = vertices[1].y = (NW_GDI_Metric_t)(bounds.point.y + bounds.dimension.height - borderWidth->bottom + i);
          vertices[1].x = (NW_GDI_Metric_t)(bounds.point.x + bounds.dimension.width - borderWidth->right - i - 1);
        } else {
          // skip any unknown border styles
          continue;
        }
        status = deviceContext->DrawPolyline( 2, vertices, NW_FALSE);
        _NW_THROW_ON_ERROR(status);
      }
    }

    /* draw right border */
    if (borderWidth->right > 0) 
    {
      if ( borderColor->right == NW_GDI_Color_Transparent) {
        borderStyle->right = NW_CSS_PropValue_none;
      } else {
        deviceContext->SetForegroundColor( borderColor->right);
      }
      deviceContext->SetLinePattern( NW_LMgr_Box_ConvertBorderStyle(borderStyle->right));
    
      for (i=0; i<borderWidth->right; i++) {
        if (borderStyle->right == NW_CSS_PropValue_solid ||
            borderStyle->right == NW_CSS_PropValue_dashed ||
            borderStyle->right == NW_CSS_PropValue_dotted) {
          vertices[0].x = vertices[1].x = (NW_GDI_Metric_t)(bounds.point.x + bounds.dimension.width - 1 - i);
          vertices[0].y = (NW_GDI_Metric_t)(bounds.point.y + i*ratioTopRight);
          vertices[1].y = (NW_GDI_Metric_t)(bounds.point.y + bounds.dimension.height - i*ratioBottomRight - 1);
        } else if (borderStyle->right == NW_CSS_PropValue_bevelled) {
          if (i >= innerHeight/2) {
            continue;
          }
          vertices[0].x = vertices[1].x = (NW_GDI_Metric_t)(bounds.point.x + bounds.dimension.width - borderWidth->right + i);
          vertices[0].y = (NW_GDI_Metric_t)(bounds.point.y + borderWidth->top + i);
          vertices[1].y = (NW_GDI_Metric_t)(bounds.point.y + bounds.dimension.height - borderWidth->bottom - i - 1);
        } else {
          // skip any unknown border styles
          continue;
        }
        status = deviceContext->DrawPolyline( 2, vertices, NW_FALSE);
        _NW_THROW_ON_ERROR(status);
      }
    }

} NW_CATCH (status) {
  } NW_FINALLY {
    deviceContext->SetForegroundColor( oldFg);
    deviceContext->SetLinePattern(oldPat);
    return status;
  } NW_END_TRY
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetSizeProperties
 * Description:  This method gets any size properties set on box. If the 
 *               property is not set, (-1) is returned.  This is OK because 
 *               negative values are illegal for CSS_width and CSS_height.  
 * Returns:      KBrsrSuccess
 */

TBrowserStatusCode
NW_LMgr_Box_GetSizeProperties(NW_LMgr_Box_t *box,
                              NW_GDI_Dimension2D_t *size){
  
  NW_LMgr_PropertyValue_t sizeVal;

  NW_ASSERT(box != NULL);
  NW_ASSERT(size != NULL);

  size->width = -1;
  size->height = -1;

  if(NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_width, NW_CSS_ValueType_Px, &sizeVal) == KBrsrSuccess){
    size->width = (NW_GDI_Metric_t)sizeVal.integer;
  }

  if(NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_height, NW_CSS_ValueType_Px, &sizeVal) == KBrsrSuccess){
    size->height = (NW_GDI_Metric_t)sizeVal.integer;
  }
  return KBrsrSuccess;
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetMinimumSize
 * Description:  This method first adds margins, borders, and padding to minimum 
 *               content size.  While this method is final, it invokes a virtual 
 *               method to get the minimum content size.
 * Returns:      KBrsrSuccess, KBrsrOutOfMemory
 */

TBrowserStatusCode
NW_LMgr_Box_GetMinimumSize (NW_LMgr_Box_t* box,
                            NW_GDI_Dimension2D_t* size)
{
  NW_TRY (status) {
    NW_LMgr_FrameInfo_t padding, borderWidth;

    NW_ASSERT(box != NULL);
    NW_ASSERT(size != NULL);
    
    NW_LMgr_RootBox_t* rootBox = NW_LMgr_Box_GetRootBox( box );

    // for bgsound support: in normal screen mode if it's object box, still check visibility
    if( NW_LMgr_RootBox_GetSmallScreenOn( rootBox ) ||
        NW_Object_IsInstanceOf (box, &NW_LMgr_ObjectBox_Class) )
    {
      NW_LMgr_PropertyValue_t visibilityVal;
      visibilityVal.token = NW_CSS_PropValue_visible;
      status = NW_LMgr_Box_GetPropertyValue (box, NW_CSS_Prop_visibility,
                                     NW_CSS_ValueType_Token, &visibilityVal);
      if (status  == KBrsrSuccess && visibilityVal.token == NW_CSS_PropValue_hidden) 
      {
        size->width = 0 ;
        size->height = 0;
        NW_THROW_SUCCESS(status);
      }
    }

    /* In case of vertical layout is enabled set the height and width to zero 
        if the visibility attrib is hidden*/
    /* Start with minimum content box */
    status = NW_LMgr_Box_GetMinimumContentSize (box, size);
    _NW_THROW_ON_ERROR (status);

    if ((size->width == 0) && (size->height == 0))
      NW_THROW_SUCCESS(status);

    /* Now add any border, padding */
    NW_LMgr_Box_GetPadding(box, &padding, ELMgrFrameAll );
    NW_LMgr_Box_GetBorderWidth(box, &borderWidth, ELMgrFrameAll );
  
    size->width =
      (NW_GDI_Metric_t) (size->width + padding.left + padding.right +
                         borderWidth.left + borderWidth.right);
    size->height = 
      (NW_GDI_Metric_t) (size->height + padding.top + padding.bottom + 
                         borderWidth.top + borderWidth.bottom);

} NW_CATCH (status) {
  } NW_FINALLY {
    return status;
  } NW_END_TRY
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_HasFixedWidth
 * Description:  Determines whether the box has fixed width.
 * Returns:      NW_TRUE, NW_FALSE
 */

NW_Bool
NW_LMgr_Box_HasFixedWidth(NW_LMgr_Box_t* box){

	NW_LMgr_Property_t prop;
  TBrowserStatusCode status;

	NW_ASSERT(box != NULL);

	if(NW_LMgr_Box_HasFixedContentSize(box) == NW_TRUE){
		return NW_TRUE;
	}

  prop.type = NW_CSS_ValueType_Token;
  prop.value.integer = NW_CSS_PropValue_auto;
  status = NW_LMgr_Box_GetProperty(box, NW_CSS_Prop_width, &prop);
  if (status == KBrsrSuccess && prop.type == NW_CSS_ValueType_Px) {
    return NW_TRUE;
	}

	return NW_FALSE;

}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_HasFixedHeight
 * Description:  Determines whether the box has fixed height.
 * Returns:      NW_TRUE, NW_FALSE
 */

NW_Bool
NW_LMgr_Box_HasFixedHeight(NW_LMgr_Box_t* box){

	NW_LMgr_Property_t prop;
  TBrowserStatusCode status;

	NW_ASSERT(box != NULL);

	if(NW_LMgr_Box_HasFixedContentSize(box) == NW_TRUE){
		return NW_TRUE;
	}

  prop.type = NW_CSS_ValueType_Token;
  prop.value.integer = NW_CSS_PropValue_auto;
  status = NW_LMgr_Box_GetProperty(box, NW_CSS_Prop_width, &prop);
  if (status == KBrsrSuccess && prop.type == NW_CSS_ValueType_Px) {
    return NW_TRUE;
	}

	return NW_FALSE;
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetEm
 * Description:  Calculates the em size for the box.
 * Returns:      The em size in pixels.
 */

/* TODO:  change this interface so that out-of-memory status is propagated up
 */

NW_GDI_Metric_t
NW_LMgr_Box_GetEm (NW_LMgr_Box_t* box)
  {
  NW_GDI_Metric_t em = 0;

  NW_TRY (status) 
    {
    CGDIFont *font;
    TGDIFontInfo fontInfo;

    /* Set the GDI to the box font */
    font = NW_LMgr_Box_GetFont(box);  
    NW_THROW_ON_NULL(font, status, KBrsrUnexpectedError);
    
    /* Get the em value */  
    status = font->GetFontInfo( &fontInfo);
    _NW_THROW_ON_ERROR(status);
    em = fontInfo.height;
    } 
  NW_CATCH (status) 
    {
    em = 0;
    } 
  NW_FINALLY 
    {
    return em;
    } 
  NW_END_TRY
  }

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_GetEx
 * Description:  Calculates the ex size for the box.
 * Returns:      The ex size in pixels.
 */

/* TODO:  Currently ex is set to be 1/2 of em, becuase we have no way
 *        of accessing the actual dimensions of the 'x' character.  This
 *        should be fixed. 
 * TODO:  change this interface so that out-of-memory status is propagated up
 */

NW_GDI_Metric_t
NW_LMgr_Box_GetEx (NW_LMgr_Box_t* box)
{
  return (NW_GDI_Metric_t)(NW_LMgr_Box_GetEm(box)/2);
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_FindBoxOfClass
 * Description:  Tries to find a box of a given class or, if the class is an
 *               interface specification, implementing that interface. If
 *               the derived flag is set, then the parent boxes are queried
 *               for an instance of the given class. 
 * Returns:      The box, if found.  Otherwise, NULL.
 */

NW_LMgr_Box_t*
NW_LMgr_Box_FindBoxOfClass (NW_LMgr_Box_t* box,
                            const NW_Object_Class_t* theClass,
                            NW_Bool derived)
{
  /* parameter assertion block */
  NW_ASSERT (NW_Object_IsInstanceOf (box, &NW_LMgr_Box_Class));

  /* traverse up the box tree looking for the first box of either derived from
     the specified class or, if the specified class is an interface
     specification, implementing that interface */
  while (box != NULL) {
    NW_Object_t* object;

    object = NW_Object_QueryInterface (box, theClass);
    if (object != NULL && (derived || NW_Object_IsClass (object, theClass))) {
      return box;
    }

    /* try the parent */
    box = (NW_LMgr_Box_t*) NW_LMgr_Box_GetParent (box);
  }

  /* return the result */
  return box;
}

/* ------------------------------------------------------------------------- */
NW_LMgr_RootBox_t*
_NW_LMgr_Box_GetRootBox (NW_LMgr_Box_t* box)
{
  // ZAL: temp: change rootBox back to NW_LMgr_RootBox_t*
  // parameter assertion block 
  NW_ASSERT (NW_Object_IsInstanceOf (box, &NW_LMgr_Box_Class));

  // if the rootBox is not set, then get it from the parent and then set it.
  if( !box->rootBox )
    {    
    if( box->parent )
      {
      box->rootBox = (void*)NW_LMgr_Box_GetRootBox( box->parent );
      }
    // no parent means that we are at the rootbox level
    // However if it is not the rootbox, then the box is corrupt as
    // we cannot get to the rootbox level.
    else if( NW_Object_IsClass( box, &NW_LMgr_RootBox_Class ) )
      {
      // rootbox points back to itself
      box->rootBox = (void*)NW_LMgr_RootBoxOf( box );
      }
    else
      {
      // NW_ASSERT( NW_FALSE )???
      }
  }
  return (NW_LMgr_RootBox_t*)box->rootBox;
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_Detach
 * Description:  Detaches the box from its parent.
 * Returns:      KBrsrSuccess.
 */

TBrowserStatusCode
NW_LMgr_Box_Detach (NW_LMgr_Box_t* box)
{
  NW_LMgr_ContainerBox_t* parentBox;

  /* parameter assertion block */
  NW_ASSERT(box != NULL);
  NW_ASSERT (NW_Object_IsInstanceOf (box, &NW_LMgr_Box_Class));

  /* get the parent box of the box - if it doesn't have one we simply return
     success */
  parentBox = NW_LMgr_Box_GetParent (box);
  if (parentBox == NULL) {
    return KBrsrSuccess;
  }

  /* invoke the ContainerBox's method to remove the child */
  return NW_LMgr_ContainerBox_RemoveChild (parentBox, box);
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_DrawBackground
 * Description:  Redraws the box and its descendants.  Its behavior is only 
 */

TBrowserStatusCode
NW_LMgr_Box_DrawBackground (NW_LMgr_Box_t* box, 
                            NW_LMgr_ContainerBox_t* parent,
                            CGDIDeviceContext* deviceContext)
{
  NW_TRY (status) {
    NW_LMgr_Box_t *parentBox = NW_LMgr_BoxOf(parent);
    NW_LMgr_Property_t prop;

    /* Get the rootbox */
    if (NW_Object_IsClass(parent, &NW_LMgr_RootBox_Class)) {
      return KBrsrSuccess;
    }

    status = NW_LMgr_Box_DrawBackground(box, parentBox->parent, deviceContext);
    _NW_THROW_ON_ERROR (status);

    prop.type = NW_CSS_ValueType_Token;
    prop.value.token = NW_CSS_PropValue_transparent;
    // special handling for getting background color of StaticTableCellBox
    if (NW_Object_IsInstanceOf (parent, &NW_LMgr_StaticTableCellBox_Class))
      {
      NW_LMgr_StaticTableCellBox_t *cell = NW_LMgr_StaticTableCellBoxOf(parent);
      NW_LMgr_StaticTableCellBox_GetBackground(cell, &prop);
      }
    else
      {
      NW_LMgr_Box_GetProperty(parentBox, NW_CSS_Prop_backgroundColor, &prop);
      }

    if (prop.type == NW_CSS_ValueType_Color) 
    {
      NW_LMgr_Box_t tempBox;
      // set the rootbox so that we can get the cached settings
      status = NW_LMgr_Box_Initialize (&tempBox, 1);
      tempBox.rootBox = NW_LMgr_Box_GetRootBox( box ); 
      _NW_THROW_ON_ERROR (status);
      NW_GDI_Rectangle_t boxBounds = NW_LMgr_Box_GetDisplayBounds( box );
      NW_GDI_Rectangle_t parentBoxBounds = NW_LMgr_Box_GetDisplayBounds( parentBox );
      NW_GDI_Rectangle_t tempBoxBounds = NW_LMgr_Box_GetDisplayBounds( &tempBox );

      if (NW_GDI_Rectangle_Cross (&boxBounds, &parentBoxBounds, &tempBoxBounds)) 
        { 
        /* Draw the background */
        NW_LMgr_Box_SetProperty (&tempBox, NW_CSS_Prop_backgroundColor, &prop);
        // set display bounds
        NW_LMgr_Box_UpdateDisplayBounds(&tempBox, tempBoxBounds);
        status = NW_LMgr_Box_Draw (&tempBox, deviceContext, NW_FALSE);
        if (status != KBrsrSuccess) {
          NW_Object_Terminate (&tempBox);
          if (status != KBrsrOutOfMemory) {
            status = KBrsrUnexpectedError;
          }
          return status;
        }
      }

      NW_Object_Terminate (&tempBox);
    }

} NW_CATCH (status) {
  } NW_FINALLY {
    return status;
  } NW_END_TRY
}
 

/* ------------------------------------------------------------------------- */
TBrowserStatusCode
NW_LMgr_Box_GetInnerRectangle(NW_LMgr_Box_t* box,
                              NW_GDI_Rectangle_t* innerRectangle)
{
  NW_GDI_Rectangle_t bounds;
  NW_LMgr_FrameInfo_t padding;
  NW_LMgr_FrameInfo_t borderWidth;

  /* Get all margin, border and padding settings */
  bounds = (NW_LMgr_Box_GetDisplayBounds(box));
  NW_LMgr_Box_GetPadding(box, &padding, ELMgrFrameAll );
  NW_LMgr_Box_GetBorderWidth(box, &borderWidth, ELMgrFrameAll );

  innerRectangle->point.x = 
    (NW_GDI_Metric_t)(bounds.point.x + borderWidth.left + padding.left);
  
  innerRectangle->point.y = 
    (NW_GDI_Metric_t)(bounds.point.y + borderWidth.top + padding.top);

  innerRectangle->dimension.height = (NW_GDI_Metric_t)(bounds.dimension.height - 
    (borderWidth.top + borderWidth.bottom + padding.top + padding.bottom));

  innerRectangle->dimension.width = (NW_GDI_Metric_t)(bounds.dimension.width - 
    (borderWidth.left + borderWidth.right + padding.left + padding.right));
  
  return KBrsrSuccess;
}

/* ------------------------------------------------------------------------- */
NW_Bool
NW_LMgr_Box_GetVisibleBounds(const NW_LMgr_Box_t* box,
                             NW_GDI_Rectangle_t* bounds)
{
  NW_GDI_Rectangle_t rect;
  NW_LMgr_PropertyValue_t overflow;

  if (bounds != NULL) {
    NW_Mem_memset(bounds, 0, sizeof(NW_GDI_Rectangle_t));
  }

  rect = NW_LMgr_Box_GetDisplayBounds((NW_LMgr_Box_t*)box);

  box = (NW_LMgr_Box_t*)box->parent;
  while (box != NULL) {
    if (NW_Object_IsClass(box, &NW_LMgr_BidiFlowBox_Class) ||
        NW_Object_IsClass(box, &NW_LMgr_StaticTableBox_Class) ||
        NW_Object_IsClass(box, &NW_LMgr_StaticTableCellBox_Class)) {
      overflow.token = NW_CSS_PropValue_visible;
      (void)NW_LMgr_Box_GetPropertyValue((NW_LMgr_Box_t*)box, NW_CSS_Prop_overflow,
                                         NW_CSS_ValueType_Token, &overflow);
      if (overflow.token == NW_CSS_PropValue_hidden) {
        NW_GDI_Rectangle_t temp;
        NW_GDI_Rectangle_t boxBounds = NW_LMgr_Box_GetDisplayBounds( NW_LMgr_BoxOf( box ) );
        if (!NW_GDI_Rectangle_Cross(&rect, &boxBounds, &temp)) {
          return NW_FALSE;
        }        
        rect = temp;
      }
    }

    box = (NW_LMgr_Box_t*)box->parent;
  }

  if (bounds != NULL) {
    *bounds = rect;
  }
  return NW_TRUE;
}

/* ------------------------------------------------------------------------- *
 * Function:     NW_LMgr_Box_Refresh
 * Description:  Redraws the box and its descendants.  Its behavior is only 
 *               guaranteed to be correct if "overflow: hidden" is set.  Any
 *               already displayed overflows will not be cleared.
 *               The usage of this method should be limited to the cases
 *               where an _isolated_ part of the box tree needs to be updated;
 *               in all other cases, the whole tree should be redrawn.
 *               Refresh CANNOT be called on the root box.
 * Returns:      KBrsrSuccess.
 */

TBrowserStatusCode
NW_LMgr_Box_Refresh (NW_LMgr_Box_t* box)
{
  NW_LMgr_RootBox_t* rootBox;

  NW_ASSERT (!NW_Object_IsClass(box, &NW_LMgr_RootBox_Class));

  /* Get the rootbox */
  rootBox = NW_LMgr_Box_GetRootBox (box);
//  if( !rootBox || !rootBox->renderedBoxes ){
  if( !rootBox ){
    // refresh might be called even if the rendered boxes are null (when the cache is invalidated)
    return KBrsrSuccess;
    }

  return NW_LMgr_RootBox_Refresh(rootBox, box);
}

void
NW_LMgr_Box_SetHasFocus(NW_LMgr_Box_t* box, NW_Bool hasFocus)
{
  NW_LMgr_Box_t* thisObj;

  // for convenience 
  thisObj = NW_LMgr_BoxOf (box);

  thisObj->hasFocus = hasFocus;
}

NW_Bool
NW_LMgr_Box_HasFocus(NW_LMgr_Box_t* box)
{
  NW_LMgr_Box_t* thisObj;

  // for convenience 
  thisObj = NW_LMgr_BoxOf (box);

  return thisObj->hasFocus;
}

NW_GDI_Rectangle_t 
NW_LMgr_Box_GetFormatBounds( NW_LMgr_Box_t* aBox )
  {
  if( aBox )
    {
    return aBox->iFormatBounds;
    }
  else
    {
    NW_ASSERT( 0 );
    NW_GDI_Rectangle_t invalidRect;
    invalidRect.dimension.height = -1;
    invalidRect.dimension.width = -1;
    invalidRect.point.x = -1;
    invalidRect.point.y = -1;
    return invalidRect;
    }
  }

void NW_LMgr_Box_SetFormatBounds( NW_LMgr_Box_t* aBox, NW_GDI_Rectangle_t aFormatBounds )
  {
  if( aBox )
    {
    aBox->iFormatBounds = aFormatBounds;
    }
  }

NW_GDI_Rectangle_t 
NW_LMgr_Box_GetDisplayBounds( NW_LMgr_Box_t* aBox )
  {
  if( aBox )
    {
    return aBox->iDisplayBounds;
    }
  else
    {
    NW_GDI_Rectangle_t invalidRect;
    invalidRect.dimension.height = -1;
    invalidRect.dimension.width = -1;
    invalidRect.point.x = -1;
    invalidRect.point.y = -1;
    return invalidRect;
    }
  }

void NW_LMgr_Box_UpdateDisplayBounds( NW_LMgr_Box_t* aBox, NW_GDI_Rectangle_t aDisplayBounds )
  {
  if( aBox )
    {
    aBox->iDisplayBounds = aDisplayBounds;
    }
  }

  /**
* NW_LMgr_Box_UpdateContainerBodyBox
* @description This method updates hight for displayBounds and formatBounds
*  of bodybox container to take into account body bottom margin. 
* it is called only once after page load complete
* @param NW_LMgr_RootBox_t* aRootBox: pointer to the rootBox
*
* @return void
*/
void NW_LMgr_Box_UpdateContainerBodyBox( NW_LMgr_RootBox_t* aRootBox )
{
	NW_GDI_Metric_t bottomMargin = 0;
	NW_LMgr_Box_t* bodyBox = NW_LMgr_RootBox_GetBody(aRootBox);
	if(bodyBox != NULL)
	{
		
		NW_LMgr_ContainerBox_s *parent = bodyBox->parent;
		if(parent != NULL)
		{
			
			bottomMargin =
                (NW_GDI_Metric_t)NW_LMgr_Box_GetModelProp(bodyBox,
                        NW_CSS_Prop_bottomMargin);
            if(bottomMargin > 0)
            {
				NW_GDI_Rectangle_t formatBounds =
				NW_LMgr_Box_GetFormatBounds( (NW_LMgr_Box_t* )parent);
    			formatBounds.dimension.height += bottomMargin;
    			(void) NW_LMgr_Box_SetFormatBounds( (NW_LMgr_Box_t* )parent, formatBounds );
    			NW_GDI_Rectangle_t displayBounds = NW_LMgr_Box_GetDisplayBounds((NW_LMgr_Box_t*) parent);
   				displayBounds.dimension.height += bottomMargin;
 				((NW_LMgr_Box_t* )parent)->iDisplayBounds.dimension.height =
 				displayBounds.dimension.height; 			
			}
		}
	}
 		
}
/* ------------------------------------------------------------------------- *
  convenience functions
 * ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
TBrowserStatusCode
NW_LMgr_Box_Initialize (NW_LMgr_Box_t* box,
                        NW_ADT_Vector_Metric_t numProperties)
{
  return NW_Object_Initialize (&NW_LMgr_Box_Class, box, numProperties);
}

/* ------------------------------------------------------------------------- */
NW_LMgr_Box_t*
NW_LMgr_Box_New (NW_ADT_Vector_Metric_t numProperties)
{
  return (NW_LMgr_Box_t*)
    NW_Object_New (&NW_LMgr_Box_Class, (NW_Uint32)numProperties);
}


#ifdef _DEBUG
/*lint -save -esym(960, 87) -e64 Only preprocessor statements and comments before '#include', Type mismatch */

#include "LMgrAnonBlock.h"
#include "LMgrAnonTableBox.h"
#include "LMgrMarkerImage.h"
#include "LMgrMarkerText.h"
#include "LMgrObjectBoxOOC.h"
#include "nw_fbox_buttonbox.h"
#include "nw_fbox_checkbox.h"
#include "nw_fbox_fileselectionbox.h"
#include "nw_fbox_formbox.h"
#include "nw_fbox_imagebuttonbox.h"
#include "nw_fbox_inputbox.h"
#include "nw_fbox_optgrpbox.h"
#include "nw_fbox_optionbox.h"
#include "nw_fbox_passwordbox.h"
#include "nw_fbox_hiddenbox.h"
#include "nw_fbox_radiobox.h"
#include "nw_fbox_selectbox.h"
#include "nw_fbox_textareabox.h"
#include "nw_lmgr_activebox.h"
#include "nw_lmgr_activecontainerbox.h"
#include "nw_lmgr_animatedimagebox.h"
#include "nw_lmgr_areabox.h"
#include "nw_lmgr_bidiflowbox.h"
#include "nw_lmgr_containerbox.h"
#include "nw_lmgr_breakbox.h"
#include "nw_lmgr_emptybox.h"
#include "nw_lmgr_imagebox.h"
#include "nw_lmgr_flowbox.h"
#include "nw_lmgr_formatbox.h"
#include "nw_lmgr_linebox.h"
#include "nw_lmgr_rootbox.h"
#include "nw_lmgr_mediabox.h"
#include "nw_lmgr_nobrbox.h"
#include "nw_lmgr_rulebox.h"
#include "nw_lmgr_splittextbox.h"
#include "nw_lmgr_statictablebox.h"
#include "nw_lmgr_statictablecellbox.h"
#include "nw_lmgr_statictablerowbox.h"
#include "nw_lmgr_textbox.h"



#define countof(x) (sizeof(x)/sizeof(x[0]))

typedef struct
    {
    const NW_Object_Class_t* objClass;
    const NW_Int8* className;
    } ClassNameItem_t;

const ClassNameItem_t classNames[] =
    {
        {&NW_FBox_ButtonBox_Class, (NW_Int8*)"FBox_ButtonBox"},
        {&NW_FBox_CheckBox_Class, (NW_Int8*)"FBox_CheckBox"},
        {&NW_FBox_FileSelectionBox_Class, (NW_Int8*)"FBox_FileSelectionBox"},
        {&NW_FBox_ImageButtonBox_Class, (NW_Int8*)"FBox_ImageButtonBox"},
        {&NW_FBox_InputBox_Class, (NW_Int8*)"FBox_InputBox"},
        {&NW_FBox_OptGrpBox_Class, (NW_Int8*)"FBox_OptGrpBox"},
        {&NW_FBox_OptionBox_Class, (NW_Int8*)"FBox_OptionBox"},
        {&NW_FBox_PasswordBox_Class, (NW_Int8*)"FBox_PasswordBox"},
        {&NW_FBox_HiddenBox_Class, (NW_Int8*)"FBox_HiddenBox"},
        {&NW_FBox_RadioBox_Class, (NW_Int8*)"FBox_RadioBox"},
        {&NW_FBox_SelectBox_Class, (NW_Int8*)"FBox_SelectBox"},
        {&NW_FBox_TextAreaBox_Class, (NW_Int8*)"FBox_TextAreaBox"},
        {&NW_LMgr_AbstractTextBox_Class, (NW_Int8*)"AbstractTextBox"},
        {&NW_LMgr_ActiveBox_Class, (NW_Int8*)"ActiveBox"},
        {&NW_LMgr_ActiveContainerBox_Class, (NW_Int8*)"ActiveContainerBox"},
        {&NW_LMgr_AnimatedImageBox_Class, (NW_Int8*)"AnimatedImageBox"},
        {&LMgrAnonBlock_Class, (NW_Int8*)"AnonBlockBox"},
        {&LMgrAnonTableBox_Class, (NW_Int8*)"AnonTableBox"},
        {&NW_LMgr_AreaBox_Class, (NW_Int8*)"AreaBox"},
        {&NW_LMgr_BidiFlowBox_Class, (NW_Int8*)"BidiFlowBox"},
        {&NW_LMgr_BreakBox_Class, (NW_Int8*)"BreakBox"},
        {&NW_LMgr_ContainerBox_Class, (NW_Int8*)"ContainerBox"},
        {&NW_LMgr_EmptyBox_Class, (NW_Int8*)"EmptyBox"},
        {&NW_LMgr_FlowBox_Class, (NW_Int8*)"FlowBox"},
        {&NW_LMgr_FormatBox_Class, (NW_Int8*)"FormatBox"},
        {&NW_LMgr_ImageBox_Class, (NW_Int8*)"ImageBox"},
        {&NW_LMgr_ImgContainerBox_Class, (NW_Int8*)"ImgContainerBox"},
        {&NW_LMgr_ImageMapBox_Class, (NW_Int8*)"ImageMapBox"},
        {&NW_LMgr_LineBox_Class, (NW_Int8*)"LineBox"},
        {&LMgrMarkerImage_Class, (NW_Int8*)"MarkerImageBox"},
        {&LMgrMarkerText_Class, (NW_Int8*)"MarkerTextBox"},
        {&NW_LMgr_MarqueeBox_Class, (NW_Int8*)"MarqueeBox"},
        {&NW_LMgr_MediaBox_Class, (NW_Int8*)"MediaBox"},
        {&NW_LMgr_NobrBox_Class, (NW_Int8*)"NobrBox"},
        {&NW_LMgr_ObjectBox_Class, (NW_Int8*)"ObjectBox"},
        {&NW_LMgr_PosFlowBox_Class, (NW_Int8*)"PositionedBox"},
        {&NW_LMgr_RootBox_Class, (NW_Int8*)"RootBox"},
        {&NW_LMgr_RuleBox_Class, (NW_Int8*)"RuleBox"},
        {&NW_LMgr_SplitTextBox_Class, (NW_Int8*)"SplitTextBox"},
        {&NW_LMgr_StaticTableBox_Class, (NW_Int8*)"StaticTableBox"},
        {&NW_LMgr_StaticTableCellBox_Class, (NW_Int8*)"StaticTableCellBox"},
        {&NW_LMgr_StaticTableRowBox_Class, (NW_Int8*)"StaticTableRowBox"},
        {&NW_LMgr_TextBox_Class, (NW_Int8*)"TextBox"},
        {&NW_LMgr_VerticalTableBox_Class, (NW_Int8*)"VerticalTableBox"},
        {&NW_LMgr_VerticalTableCellBox_Class, (NW_Int8*)"VerticalTableCellBox"},
        {&NW_LMgr_VerticalTableRowBox_Class, (NW_Int8*)"VerticalRowBox"},
    };
#define CLASS_NAMES_COUNT countof(classNames)

const NW_Int8*
NW_LMgr_Box_GetBoxType (NW_LMgr_Box_t *box) {

  for (int i = 0; i < CLASS_NAMES_COUNT; i++) {
      if (classNames[i].objClass == box->super.super.super.objClass) {
          return classNames[i].className;
      }
  }

  return (NW_Int8*)"Unknown box: update NW_LMgr_Box_GetBoxType and/or the classNames table in LMgrBox.cpp.";
}

/* ------------------------------------------------------------------------- */
/* HACK!  HACK!  HACK!  
 * This is here ONLY for debugging purposes.  The proper way to do this 
 * (making GetBoxInfo virtual on box) would clutter the Box interface
 * too much.
 */


static
NW_Uint16
GetBoxLevel (NW_LMgr_Box_t *box, NW_LMgr_Box_t *rootBox) {
  NW_Uint16 level;

  level = 0;
  while (box != rootBox) {
    level ++;
    box = (NW_LMgr_Box_t*)NW_LMgr_Box_GetParent (box);
    NW_ASSERT (box != NULL);
  }

  return level;
}

static
void
PrintBoxInfo (NW_LMgr_Box_t *box, NW_Uint16 level) {

  const NW_Int8 *typeStr;
  NW_Ucs2 *textBoxStr = NULL;
  NW_Ucs2 indentBuf[256];
  NW_Ucs2 typeBuf[64];
  NW_Ucs2 tableInfo[64];
  NW_Ucs2 tableInfoFormat[] = { 'S', '%', 'd', ':', 'B', '%', 'd', ':', 
                                'H', '%', 'd', ':', 'V', '%', 'd', '\0' };
  NW_Uint16 i;
  NW_LMgr_StaticTableBox_t *tableBox = NULL;
  NW_Uint16 numBorderInfos = 0;
  NW_Uint16 numSpans = 0;
  NW_Uint16 numHEdges = 0;
  NW_Uint16 numVEdges = 0;
  NW_GDI_Rectangle_t bounds;
  NW_GDI_Rectangle_t dispBounds;
  NW_Text_t *displayText = NULL;

  typeStr = NW_LMgr_Box_GetBoxType(box);

  if (NW_Object_IsInstanceOf (box, &NW_LMgr_AbstractTextBox_Class)) {
    displayText = NW_LMgr_AbstractTextBox_GetDisplayText(NW_LMgr_AbstractTextBoxOf(box), NW_TRUE);
    if( displayText )
    textBoxStr = NW_Text_GetUCS2Buffer (displayText,
                                        NW_Text_Flags_Copy, NULL, NULL);
    if (textBoxStr) {
      NW_Str_Strcharreplace (textBoxStr, '\n', '>');

      // Trunc the text to 900 (NW_Debug_Log doesn't allow a print statement larger than 1024).
      if (displayText->characterCount > 900) {
        textBoxStr[900] = '\0';
      }
    }
  }

  //NW_Str_StrcpyConst(typeBuf, (char*)typeStr);
  /* Get the box bounds */
  bounds = NW_LMgr_Box_GetFormatBounds(box);
  dispBounds = NW_LMgr_Box_GetDisplayBounds (box);
  
  /* Indent the line */
  for (i=0; i<level*2 && i < 254; i++) {
    indentBuf[i] = ' ';
  }
  indentBuf[i] = '\0';

  /* Print the info */
  if (textBoxStr) 
    {
    NW_LOG12(NW_LOG_LEVEL3, "%s%s %X [bounds:(%d,%d)-(%d,%d), dispBounds:(%d,%d)-(%d,%d)\"%s\"]",
                           indentBuf,
                           typeBuf,
                           box,
                           (NW_Uint16)bounds.point.x, 
                           (NW_Uint16)bounds.point.y,
                           (NW_Uint16)bounds.dimension.width, 
                           (NW_Uint16)bounds.dimension.height,
                           (NW_Uint16)dispBounds.point.x, 
                           (NW_Uint16)dispBounds.point.y,
                           (NW_Uint16)dispBounds.dimension.width, 
                           (NW_Uint16)dispBounds.dimension.height,
                           textBoxStr);

    NW_Str_Delete (textBoxStr);
    NW_Object_Delete(displayText);
    }
  else if (tableBox) 
    {
    NW_Str_Sprintf(tableInfo, tableInfoFormat, 
                       (NW_Uint32)numSpans,
                       (NW_Uint32)numBorderInfos,
                       (NW_Uint32)numHEdges,
                       (NW_Uint32)numVEdges);

    NW_LOG12(NW_LOG_LEVEL3, "%s%s %X [bounds:(%d,%d)-(%d,%d), dispBounds:(%d,%d)-(%d,%d) %s]", 
                           indentBuf,
                           typeBuf,
                           box,
                           (NW_Uint16)bounds.point.x, 
                           (NW_Uint16)bounds.point.y,
                           (NW_Uint16)bounds.dimension.width, 
                           (NW_Uint16)bounds.dimension.height,
                           (NW_Uint16)dispBounds.point.x, 
                           (NW_Uint16)dispBounds.point.y,
                           (NW_Uint16)dispBounds.dimension.width, 
                           (NW_Uint16)dispBounds.dimension.height,
                           tableInfo);
    }
  else 
    {
    NW_LOG11(NW_LOG_LEVEL3, "%s%s %X [bounds:(%d,%d)-(%d,%d), dispBounds:(%d,%d)-(%d,%d)]",
                           indentBuf,
                           typeBuf,
                           box,
                           (NW_Uint16)bounds.point.x, 
                           (NW_Uint16)bounds.point.y,
                           (NW_Uint16)bounds.dimension.width, 
                           (NW_Uint16)bounds.dimension.height,
                           (NW_Uint16)dispBounds.point.x, 
                           (NW_Uint16)dispBounds.point.y,
                           (NW_Uint16)dispBounds.dimension.width, 
                           (NW_Uint16)dispBounds.dimension.height);
    if( NW_Object_IsInstanceOf (box, &NW_LMgr_StaticTableBox_Class ) == NW_TRUE )
      {
      NW_LMgr_StaticTableContext_t *ctx = NW_LMgr_StaticTableBoxOf( box )->ctx;
      if( ctx != NULL )
        {
        NW_LOG4(NW_LOG_LEVEL3, "%s%s     \"    [Table - Min,Max:(%d,%d)]",
                           indentBuf,
                           typeBuf,
                           (NW_Uint16)ctx->tableMinWidth, 
                           (NW_Uint16)ctx->tableMaxWidth );
        }
      }
    else if( NW_Object_IsInstanceOf (box, &NW_LMgr_StaticTableCellBox_Class ) == NW_TRUE )
      {
      NW_LOG4(NW_LOG_LEVEL3, "%s%s     \"    [Cell - Min,Max:(%d,%d)]",
                           indentBuf,
                           typeBuf,
                           NW_LMgr_StaticTableCellBoxOf( box )->minWidth, 
                           NW_LMgr_StaticTableCellBoxOf( box )->maxWidth);
      }
    }
  }


TBrowserStatusCode
NW_LMgr_Box_DumpBoxTree(NW_LMgr_Box_t* box)
{
  NW_LMgr_BoxVisitor_t boxVisitor;
  NW_LMgr_Box_t *current;
  NW_Uint16 level;

  /* Initialize the BoxVisitor */
  NW_LMgr_BoxVisitor_Initialize (&boxVisitor, box);

  /* Dump the subtree */
  NW_LOG0(NW_LOG_LEVEL3, "Printing the box tree...");
  NW_LOG0(NW_LOG_LEVEL3, "N.B.:  The displayed class names could be names of superclasses!"); 
  while((current = NW_LMgr_BoxVisitor_NextBox (&boxVisitor, NULL)) != NULL) {

    level = GetBoxLevel (current, box);

    /* Get the boxInfo for the current box */
    PrintBoxInfo (current, level);
  }

  return KBrsrSuccess;
}

/*lint -restore*/
#endif /* _DEBUG */


