/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: layout.cpp,v 1.2.16.1 2004/07/09 01:58:01 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

// system
#include <time.h>
// include
#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxcom.h"
#include "hxwin.h"
#include "hxsite2.h"
#include "smiltype.h"
#include "hxxml.h"
#include "ihxpckts.h"
// pncont
#include "hxslist.h"
#include "hxstring.h"
// pnmisc
#include "hxwinver.h"
// rnxmllib
#include "hxxmlprs.h"
// rmasmil
#include "smlelem.h"
#include "smlparse.h"
// smlrendr
#include "passivsw.h"
#include "siteuser.h"
#include "layout.h"

CSmilBasicBox::CSmilBasicBox()
{
    m_pParent                = NULL;
    m_pChildList             = NULL;
    m_bWidthResolved         = FALSE;
    m_bDefaultWidthAssigned  = FALSE;
    m_bHeightResolved        = FALSE;
    m_bDefaultHeightAssigned = FALSE;
    m_Rect.left              = 0;
    m_Rect.top               = 0;
    m_Rect.right             = 0;
    m_Rect.bottom            = 0;
    m_RectNoZoom.left        = 0;
    m_RectNoZoom.top         = 0;
    m_RectNoZoom.right       = 0;
    m_RectNoZoom.bottom      = 0;
    m_pSite                  = NULL;
    m_pPassiveSiteWatcher    = NULL;
    m_pSiteUser              = NULL;
    m_bSiteChangingSize      = FALSE;
    m_bNested		     = FALSE;
    m_eResizeBehavior        = ResizeZoom;
    m_dZoomScaleFactorX      = 1.0;
    m_dZoomScaleFactorY      = 1.0;
    m_pChildRendererSiteList = NULL;
}

CSmilBasicBox::~CSmilBasicBox()
{
    HX_DELETE(m_pChildList);
    HX_RELEASE(m_pSite);
    HX_RELEASE(m_pPassiveSiteWatcher);
    HX_RELEASE(m_pSiteUser);
    HX_DELETE(m_pChildRendererSiteList);
}

HX_RESULT CSmilBasicBox::addChild(CSmilBasicBox* pBox)
{
    HX_RESULT retVal = HXR_OK;

    if (!m_pChildList)
    {
        m_pChildList = new CHXSimpleList();
    }
    if (m_pChildList)
    {
        m_pChildList->AddTail((void*) pBox);
        // Make sure our child inherits our resizeBehavior
        pBox->m_eResizeBehavior = m_eResizeBehavior;
    }
    else
    {
        retVal = HXR_OUTOFMEMORY;
    }

    return retVal;
}

HX_RESULT CSmilBasicBox::addRendererSiteChild(IHXSite* pSite)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pSite)
    {
        if (!m_pChildRendererSiteList)
        {
            m_pChildRendererSiteList = new CHXSimpleList();
        }
        if (m_pChildRendererSiteList)
        {
            m_pChildRendererSiteList->AddTail((void*) pSite);
            retVal = HXR_OK;
        }
    }

    return retVal;
}

HX_RESULT CSmilBasicBox::removeRendererSiteChild(IHXSite* pSite )
{
    if(m_pChildRendererSiteList)
    {
        LISTPOSITION pos = m_pChildRendererSiteList->Find(pSite);
        if(pos)
        {
            m_pChildRendererSiteList->RemoveAt(pos);
        }
    }
    return HXR_OK;
}


BOOL CSmilBasicBox::isResolved(BoxDimension eDim)
{
    BOOL bRet = FALSE;
    if (eDim == BoxDimensionWidth)
    {
        bRet = m_bWidthResolved;
    }
    else
    {
        bRet = m_bHeightResolved;
    }
    return bRet;
}

HX_RESULT CSmilBasicBox::computeChildrenMax(BoxDimension eDim,
                                            BOOL         bAllMustBeValid,
                                            REF(INT32)   rlMax)
{
    HX_RESULT retVal = HXR_FAIL;

    // Do we have any children to resolve from? If
    // not, then we can't resolve, so this is failure
    if (m_pChildList &&
        m_pChildList->GetCount() > 0)
    {
        // Now if we are having to compute our dimensions from
        // our children, then we need to loop through our immediate
        // children and compute their maximum value. NOTE: this 
        // assumes that the values of m_cRect.left and m_cRect.top
        // have already been set in this box.
        UINT32       ulNumValid = 0;
        INT32        lMax       = 0;
        LISTPOSITION pos        = m_pChildList->GetHeadPosition();
        while (pos)
        {
            CSmilBasicBox* pListBox = (CSmilBasicBox*) m_pChildList->GetNext(pos);
            if (pListBox)
            {
                INT32 lDim = 0;
                if (eDim == BoxDimensionWidth)
                {
                    if (pListBox->m_bWidthResolved)
                    {
                        lDim = pListBox->m_Rect.right;
                        ulNumValid++;
                    }
                }
                else
                {
                    if (pListBox->m_bHeightResolved)
                    {
                        lDim = pListBox->m_Rect.bottom;
                        ulNumValid++;
                    }
                }
                if (lDim > lMax)
                {
                    lMax = lDim;
                }
            }
        }
        // If we required all to be valid, then we
        // need ulNumValid == num children. If not,
        // then we just need at least 1 valid.
        if ((bAllMustBeValid  && ulNumValid == (UINT32) m_pChildList->GetCount()) ||
            (!bAllMustBeValid && ulNumValid > 0))
        {
            // Assign the out parameter
            rlMax = lMax;
            // Clear the return value
            retVal = HXR_OK;
        }
    }

    return retVal;
}

/*
 * CSmilBasicRegion methods
 */
CSmilBasicRegion::CSmilBasicRegion(CSmilRegion* pSmilRegion) :
    CSmilBasicBox()
{
    m_pSmilRegion              = pSmilRegion;
    m_rect.left                = 0;
    m_rect.top                 = 0;
    m_rect.right               = 0;
    m_rect.bottom              = 0;
    m_originalRect.left        = 0;
    m_originalRect.top         = 0;
    m_originalRect.right       = 0;
    m_originalRect.bottom      = 0;
    m_mediaSize.cx             = 0;
    m_mediaSize.cy             = 0;
    m_originalMediaSize.cx     = 0;
    m_originalMediaSize.cy     = 0;
    m_bMediaSizeSet            = FALSE;
    m_LayoutRect.m_dLeft       = 0.0;
    m_LayoutRect.m_eLeftType   = CSS2TypeAuto;
    m_LayoutRect.m_dTop        = 0.0;
    m_LayoutRect.m_eTopType    = CSS2TypeAuto;
    m_LayoutRect.m_dRight      = 0.0;
    m_LayoutRect.m_eRightType  = CSS2TypeAuto;
    m_LayoutRect.m_dBottom     = 0.0;
    m_LayoutRect.m_eBottomType = CSS2TypeAuto;
    m_LayoutRect.m_dWidth      = 0.0;
    m_LayoutRect.m_eWidthType  = CSS2TypeAuto;
    m_LayoutRect.m_dHeight     = 0.0;
    m_LayoutRect.m_eHeightType = CSS2TypeAuto;
    m_lZIndex                  = 0;
    m_eFit                     = FitHidden;
    m_ulBackgroundColor        = 0xFF000000;
    m_eBackgroundColorType     = CSS2TypeTransparent;
    m_bImplicitRegion          = FALSE;
    m_bWidthUnspecified        = FALSE;
    m_bHeightUnspecified       = FALSE;
    m_dSoundLevel              = 100.0;
    m_eShowBackground          = ShowBackgroundAlways;
    m_bUnderRootLayout         = TRUE;

    if (pSmilRegion)
    {
        // Copy the layout rect
        m_LayoutRect = pSmilRegion->m_Rect;
        // Set the z-index attribute
        m_lZIndex = pSmilRegion->m_lZIndex;
        // Set the fit attribute
        m_eFit = pSmilRegion->m_eFit;
        // Set the sound level
        m_dSoundLevel = pSmilRegion->m_dSoundLevel;
        // Set the region name
        if (pSmilRegion->m_pNode)
        {
            m_region = pSmilRegion->m_pNode->m_id;
        }
        // Set the background color
        m_ulBackgroundColor    = pSmilRegion->m_ulBackgroundColor;
        m_eBackgroundColorType = pSmilRegion->m_eBackgroundColorType;
        // Set the showBackground attribute
        m_eShowBackground = pSmilRegion->m_eShowBackground;
    }
}

CSmilBasicRegion::~CSmilBasicRegion()
{
}

HX_RESULT CSmilBasicRegion::computeDimension(BoxDimension eDim)
{
    HX_RESULT retVal = HXR_OK;

    if (eDim == BoxDimensionWidth)
    {
        if (!m_bWidthResolved)
        {
            // Is our parent width available?
            BOOL   bParentAvailable = FALSE;
            double dParentWidth     = 0.0;
            if (m_pParent && m_pParent->m_bWidthResolved)
            {
                bParentAvailable = TRUE;
                if (m_dZoomScaleFactorX != 1.0 ||
                    m_dZoomScaleFactorY != 1.0)
                {
                    dParentWidth = (double) HXxRECT_WIDTH(m_pParent->m_RectNoZoom);
                }
                else
                {
                    dParentWidth = (double) HXxRECT_WIDTH(m_pParent->m_Rect);
                }
            }
            // Now resolve left/right/width
            retVal = resolveDimension(m_LayoutRect.m_dLeft,
                                      m_LayoutRect.m_eLeftType,
                                      m_LayoutRect.m_dRight,
                                      m_LayoutRect.m_eRightType,
                                      m_LayoutRect.m_dWidth,
                                      m_LayoutRect.m_eWidthType,
                                      bParentAvailable,
                                      dParentWidth,
                                      m_Rect.left,
                                      m_Rect.right);
            if (SUCCEEDED(retVal))
            {
                m_bWidthResolved = TRUE;
                // XXXMEH - these are holdover members which currently
                // need to be set, but should be taken out soon
                m_rect.left          = m_Rect.left;
                m_rect.right         = m_Rect.right;
                m_originalRect.left  = m_Rect.left;
                m_originalRect.right = m_Rect.right;
                m_bWidthUnspecified  = (m_LayoutRect.m_eWidthType  == CSS2TypeAuto ? TRUE : FALSE);
            }
        }
    }
    else
    {
        if (!m_bHeightResolved)
        {
            // Is our parent width available?
            BOOL   bParentAvailable = FALSE;
            double dParentHeight    = 0.0;
            if (m_pParent && m_pParent->m_bHeightResolved)
            {
                bParentAvailable = TRUE;
                if (m_dZoomScaleFactorX != 1.0 ||
                    m_dZoomScaleFactorY != 1.0)
                {
                    dParentHeight = (double) HXxRECT_HEIGHT(m_pParent->m_RectNoZoom);
                }
                else
                {
                    dParentHeight = (double) HXxRECT_HEIGHT(m_pParent->m_Rect);
                }
            }
            // Now resolve top/bottom/height
            retVal = resolveDimension(m_LayoutRect.m_dTop,
                                      m_LayoutRect.m_eTopType,
                                      m_LayoutRect.m_dBottom,
                                      m_LayoutRect.m_eBottomType,
                                      m_LayoutRect.m_dHeight,
                                      m_LayoutRect.m_eHeightType,
                                      bParentAvailable,
                                      dParentHeight,
                                      m_Rect.top,
                                      m_Rect.bottom);
            if (SUCCEEDED(retVal))
            {
                m_bHeightResolved = TRUE;
                // XXXMEH - these are holdover members which currently
                // need to be set, but should be taken out soon
                m_rect.top            = m_Rect.top;
                m_rect.bottom         = m_Rect.bottom;
                m_originalRect.top    = m_Rect.top;
                m_originalRect.bottom = m_Rect.bottom;
                m_bHeightUnspecified  = (m_LayoutRect.m_eHeightType == CSS2TypeAuto ? TRUE : FALSE);
            }
        }
    }

    return retVal;
}

HX_RESULT CSmilBasicRegion::resolveFromChildren(BoxDimension eDim)
{
    HX_RESULT retVal = HXR_OK;

    INT32 lMax = 0;
    retVal     = computeChildrenMax(eDim, TRUE, lMax);
    if (SUCCEEDED(retVal))
    {
        if (eDim == BoxDimensionWidth)
        {
            m_bWidthResolved = TRUE;
            if (m_LayoutRect.m_eLeftType == CSS2TypeLength)
            {
                m_Rect.left = (INT32) (m_LayoutRect.m_dLeft + 0.5);
            }
            m_Rect.right = m_Rect.left + lMax;
            // XXXMEH - these are holdover members which currently
            // need to be set, but should be taken out soon
            m_rect.left          = m_Rect.left;
            m_rect.right         = m_Rect.right;
            m_originalRect.left  = m_Rect.left;
            m_originalRect.right = m_Rect.right;
            m_bWidthUnspecified  = (m_LayoutRect.m_eWidthType  == CSS2TypeAuto ? TRUE : FALSE);
        }
        else
        {
            m_bHeightResolved = TRUE;
            if (m_LayoutRect.m_eTopType == CSS2TypeLength)
            {
                m_Rect.top = (INT32) (m_LayoutRect.m_dTop + 0.5);
            }
            m_Rect.bottom = m_Rect.top + lMax;
            // XXXMEH - these are holdover members which currently
            // need to be set, but should be taken out soon
            m_rect.top            = m_Rect.top;
            m_rect.bottom         = m_Rect.bottom;
            m_originalRect.top    = m_Rect.top;
            m_originalRect.bottom = m_Rect.bottom;
            m_bHeightUnspecified  = (m_LayoutRect.m_eHeightType == CSS2TypeAuto ? TRUE : FALSE);
        }
    }

    return retVal;
}

HX_RESULT CSmilBasicRegion::resolveDimension(double dLeft,  CSS2Type eLeftType,
                                             double dRight, CSS2Type eRightType,
                                             double dWidth, CSS2Type eWidthType,
                                             BOOL bHaveParentWidth, double dParentWidth,
                                             REF(INT32) rlRectMin,
                                             REF(INT32) rlRectMax)
{
    HX_RESULT retVal = HXR_OK;

    // Convert any percentage values
    if (eLeftType  == CSS2TypePercentage ||
        eRightType == CSS2TypePercentage ||
        eWidthType == CSS2TypePercentage)
    {
        if (bHaveParentWidth)
        {
            if (eLeftType == CSS2TypePercentage)
            {
                eLeftType = CSS2TypeLength;
                dLeft     = dLeft * dParentWidth / 100.0;
            }
            if (eRightType == CSS2TypePercentage)
            {
                eRightType = CSS2TypeLength;
                dRight     = dRight * dParentWidth / 100.0;
            }
            if (eWidthType == CSS2TypePercentage)
            {
                eWidthType = CSS2TypeLength;
                dWidth     = dWidth * dParentWidth / 100.0;
            }
        }
        else
        {
            retVal = HXR_FAIL;
        }
    }
    if (SUCCEEDED(retVal))
    {
        // Apply the following algorithm, where bbw
        // is the "bounding box width" or in this
        // case, the parent dimension (pw). See the SMIL 2.0 Layout
        // module for full detail.
        //
        //        Attribute values       Resulting value             RECT values
        // Case left   width  right   left     width    right    min(=left) max(=pw-right)
        // =============================================================================
        //  0   auto   auto   auto      0       pw        0         0         pw
        //  1   auto   auto     R       0      pw-R       R         0        pw-R
        //  2   auto     W    auto      0        W       pw-W       0          W
        //  3   auto     W      R    pw-R-W      W        R      pw-R-W      pw-R
        //  4     L    auto   auto      L      pw-L       0         L         pw
        //  5     L    auto     R       L     pw-R-L      R         L        pw-R
        //  6     L      W    auto      L        W     pw-L-W       L         L+W
        //  7     L      W      R       L        W     pw-L-W       L         L+W
        //
        // The algorithm is the same for top/height/bottom.
        //
        double dMin = 0.0;
        double dMax = 0.0;
        // Which case do we have?
        if (eLeftType == CSS2TypeAuto)
        {
            if (eWidthType == CSS2TypeAuto)
            {
                if (eRightType == CSS2TypeAuto)
                {
                    // Case 0
                    if (bHaveParentWidth)
                    {
                        dMin = 0.0;
                        dMax = dParentWidth;
                    }
                    else
                    {
                        retVal = HXR_FAIL;
                    }
                }
                else
                {
                    // Case 1
                    if (bHaveParentWidth)
                    {
                        dMin = 0.0;
                        dMax = dParentWidth - dRight;
                    }
                    else
                    {
                        retVal = HXR_FAIL;
                    }
                }
            }
            else
            {
                if (eRightType == CSS2TypeAuto)
                {
                    // Case 2
                    dMin = 0.0;
                    dMax = dWidth;
                }
                else
                {
                    // Case 3
                    if (bHaveParentWidth)
                    {
                        dMin = dParentWidth - dRight - dWidth;
                        dMax = dParentWidth - dRight;
                    }
                    else
                    {
                        retVal = HXR_FAIL;
                    }
                }
            }
        }
        else
        {
            if (eWidthType == CSS2TypeAuto)
            {
                if (eRightType == CSS2TypeAuto)
                {
                    // Case 4
                    if (bHaveParentWidth)
                    {
                        dMin = dLeft;
                        dMax = dParentWidth;
                    }
                    else
                    {
                        retVal = HXR_FAIL;
                    }
                }
                else
                {
                    // Case 5
                    if (bHaveParentWidth)
                    {
                        dMin = dLeft;
                        dMax = dParentWidth - dRight;
                    }
                    else
                    {
                        retVal = HXR_FAIL;
                    }
                }
            }
            else
            {
                if (eRightType == CSS2TypeAuto)
                {
                    // Case 6
                    dMin = dLeft;
                    dMax = dLeft + dWidth;
                }
                else
                {
                    // Case 7
                    dMin = dLeft;
                    dMax = dLeft + dWidth;
                }
            }
        }
        // Now assign the out parameters
        if (SUCCEEDED(retVal))
        {
            rlRectMin = (INT32) (dMin + 0.5);
            rlRectMax = (INT32) (dMax + 0.5);
        }
    }

    return retVal;
}

CSmilBasicRootLayout::CSmilBasicRootLayout() :
    CSmilBasicBox()
{
    m_pRoot              = NULL;
    m_OriginalSize.cx    = 0;
    m_OriginalSize.cy    = 0;
    m_bOriginalWidthSet  = FALSE;
    m_bOriginalHeightSet = FALSE;
}

CSmilBasicRootLayout::~CSmilBasicRootLayout()
{
}

HX_RESULT CSmilBasicRootLayout::computeDimension(BoxDimension eDim)
{
    HX_RESULT retVal = HXR_OK;

    // There's nothing to do here really. For <root-layout>
    // and <viewport>, the width and height will get resolved
    // either from the values of "width" and "height" themselves,
    // or they will get resolved from their children's width
    // and height. So if we are already resolved, we will stay
    // resolved and return HXR_OK. If not, we will stay not resolved
    // and return HXR_FAIL.
    if ((eDim == BoxDimensionWidth  && !m_bWidthResolved) ||
        (eDim == BoxDimensionHeight && !m_bHeightResolved))
    {
        retVal = HXR_FAIL;
    }

    return retVal;
}

HX_RESULT CSmilBasicRootLayout::resolveFromChildren(BoxDimension eDim)
{
    HX_RESULT retVal = HXR_OK;

    INT32 lMax = 0;
    retVal     = computeChildrenMax(eDim, TRUE, lMax);
    if (SUCCEEDED(retVal))
    {
        if (eDim == BoxDimensionWidth)
        {
            m_bWidthResolved    = TRUE;
            m_Rect.left         = 0;
            m_Rect.right        = lMax;
            if (!m_bOriginalWidthSet)
            {
                m_OriginalSize.cx   = m_Rect.right;
                m_bOriginalWidthSet = TRUE;
            }
        }
        else
        {
            m_bHeightResolved = TRUE;
            m_Rect.top        = 0;
            m_Rect.bottom     = lMax;
            if (!m_bOriginalHeightSet)
            {
                m_OriginalSize.cy    = m_Rect.bottom;
                m_bOriginalHeightSet = TRUE;
            }
        }
    }

    return retVal;
}

void CSmilBasicRootLayout::SetParserRootLayout(CSmilRootLayout* pRoot)
{
    // Assign the member variable
    m_pRoot = pRoot;
    // Set up the box parameters
    if (pRoot)
    {
        // Get the resizeBehavior from our CSmilRootLayout element
        m_eResizeBehavior = pRoot->m_eResizeBehavior;
        // Check if the width is resolved on its own.
        // Based on its values along, the width of the
        // root-layout is only resolved if the width
        // is specified as an absolute length
        if (pRoot->m_eWidthType == CSS2TypeLength)
        {
            // Assign the rect values
            m_Rect.left  = 0;
            m_Rect.right = (INT32) (pRoot->m_dWidth + 0.5);
            // Set the resolved flag
            m_bWidthResolved = TRUE;
            // Set the original width and the flag
            if (!m_bOriginalWidthSet)
            {
                m_OriginalSize.cx   = m_Rect.right;
                m_bOriginalWidthSet = TRUE;
            }
        }
        // Check if the height is resolved on its own.
        // Based on its values along, the height of the
        // root-layout is only resolved if the height
        // is specified as an absolute length
        if (pRoot->m_eHeightType == CSS2TypeLength)
        {
            // Assign the rect values
            m_Rect.top    = 0;
            m_Rect.bottom = (INT32) (pRoot->m_dHeight + 0.5);
            // Set the resolved flag
            m_bHeightResolved = TRUE;
            // Set the original height and the flag
            if (!m_bOriginalHeightSet)
            {
                m_OriginalSize.cy    = m_Rect.bottom;
                m_bOriginalHeightSet = TRUE;
            }
        }
    }
}

BOOL CSmilBasicRootLayout::IsWidthSet() const
{
    return m_bWidthResolved;
}

BOOL CSmilBasicRootLayout::IsHeightSet() const
{
    return m_bHeightResolved;
}

UINT32 CSmilBasicRootLayout::GetWidth() const
{
    return (UINT32) HXxRECT_WIDTH(m_Rect);
}

UINT32 CSmilBasicRootLayout::GetHeight() const
{
    return (UINT32) HXxRECT_HEIGHT(m_Rect);
}

UINT32 CSmilBasicRootLayout::GetBackgroundColor() const
{
    UINT32 ulRet = 0;
    if (m_pRoot)
    {
        ulRet = m_pRoot->m_ulBackgroundColor;
    }
    return ulRet;
}

#if defined(HELIX_FEATURE_SMIL2_MULTIWINDOWLAYOUT)

CSmilBasicViewport::CSmilBasicViewport(CSmilViewport* pPort) :
    CSmilBasicBox()
{
    // Assign member variables
    m_pPort              = pPort;
    m_ulNumActiveMedia   = 0;
    m_bOpen              = FALSE;
    m_OriginalSize.cx    = 0;
    m_OriginalSize.cy    = 0;
    m_bOriginalWidthSet  = FALSE;
    m_bOriginalHeightSet = FALSE;
    m_bViewportIsSetup   = FALSE;
    // Determine if the width and height are resolved
    if (pPort)
    {
        // Get the resize behavior from our CSmilViewport element
        m_eResizeBehavior = pPort->m_eResizeBehavior;
        // Copy the id for convenience
        m_id = pPort->m_pNode->m_id;
        // Check if the width is resolved on its own.
        // Based on its values along, the width of the
        // viewport is only resolved if the width
        // is specified as an absolute length
        if (pPort->m_eWidthType == CSS2TypeLength)
        {
            // Assign the rect values
            m_Rect.left  = 0;
            m_Rect.right = (INT32) (pPort->m_dWidth + 0.5);
            // Set the resolved flag
            m_bWidthResolved = TRUE;
            // Set the original width and flag
            if (!m_bOriginalWidthSet)
            {
                m_OriginalSize.cx   = m_Rect.right;
                m_bOriginalWidthSet = TRUE;
            }
        }
        // Check if the height is resolved on its own.
        // Based on its values along, the height of the
        // viewport is only resolved if the height
        // is specified as an absolute length
        if (pPort->m_eHeightType == CSS2TypeLength)
        {
            // Assign the rect values
            m_Rect.top    = 0;
            m_Rect.bottom = (INT32) (pPort->m_dHeight + 0.5);
            // Set the resolved flag
            m_bHeightResolved = TRUE;
            // Set the original height and flag
            if (!m_bOriginalHeightSet)
            {
                m_OriginalSize.cy    = m_Rect.bottom;
                m_bOriginalHeightSet = TRUE;
            }
        }
    }
}

CSmilBasicViewport::~CSmilBasicViewport()
{
}

HX_RESULT CSmilBasicViewport::computeDimension(BoxDimension eDim)
{
    HX_RESULT retVal = HXR_OK;

    // There's nothing to do here really. For <root-layout>
    // and <viewport>, the width and height will get resolved
    // either from the values of "width" and "height" themselves,
    // or they will get resolved from their children's width
    // and height. So if we are already resolved, we will stay
    // resolved and return HXR_OK. If not, we will stay not resolved
    // and return HXR_FAIL.
    if ((eDim == BoxDimensionWidth  && !m_bWidthResolved) ||
        (eDim == BoxDimensionHeight && !m_bHeightResolved))
    {
        retVal = HXR_FAIL;
    }

    return retVal;
}

HX_RESULT CSmilBasicViewport::resolveFromChildren(BoxDimension eDim)
{
    HX_RESULT retVal = HXR_OK;

    INT32 lMax = 0;
    retVal     = computeChildrenMax(eDim, TRUE, lMax);
    if (SUCCEEDED(retVal))
    {
        if (eDim == BoxDimensionWidth)
        {
            m_bWidthResolved = TRUE;
            m_Rect.left      = 0;
            m_Rect.right     = lMax;
            if (!m_bOriginalWidthSet)
            {
                m_OriginalSize.cx   = m_Rect.right;
                m_bOriginalWidthSet = TRUE;
            }
        }
        else
        {
            m_bHeightResolved = TRUE;
            m_Rect.top        = 0;
            m_Rect.bottom     = lMax;
            if (!m_bOriginalHeightSet)
            {
                m_OriginalSize.cy    = m_Rect.bottom;
                m_bOriginalHeightSet = TRUE;
            }
        }
    }

    return retVal;
}

#endif /* #if defined(HELIX_FEATURE_SMIL2_MULTIWINDOWLAYOUT) */
