/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: IBM Corporation
 *
 *  Copyright: 2008 by IBM Corporation
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
/*************************************************************************
 * @file
 *  the class for VO_FrameLayout
 ************************************************************************/
 
#include <memory>
#include <lwpfilehdr.hxx>
#include "lwpcelllayout.hxx"
#include "lwpframelayout.hxx"
#include "lwppara.hxx"
#include <xfilter/xfstylemanager.hxx>
#include <xfilter/xffloatframe.hxx>
#include <xfilter/xfrubystyle.hxx>
#include "lwpoleobject.hxx"
#include <lwpglobalmgr.hxx>
 
LwpFrame::LwpFrame(LwpPlacableLayout* pLayout)
    : m_pLayout(pLayout)
{
}
 
LwpFrame::~LwpFrame() {}
/**
* @descr:  parse frame
* @param:  register frame style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::RegisterStyle(std::unique_ptr<XFFrameStyle>& rFrameStyle)
{
    ApplyWrapType(rFrameStyle.get());
    ApplyMargins(rFrameStyle.get());
    ApplyPadding(rFrameStyle.get());
    ApplyBorders(rFrameStyle.get());
    ApplyColumns(rFrameStyle.get());
    ApplyShadow(rFrameStyle.get());
    ApplyBackGround(rFrameStyle.get());
    ApplyWatermark(rFrameStyle.get());
    ApplyProtect(rFrameStyle.get());
    ApplyTextDir(rFrameStyle.get());
    ApplyPosType(rFrameStyle.get());
 
    rFrameStyle->SetStyleName(m_pLayout->GetName().str());
    XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
    m_StyleName = pXFStyleManager->AddStyle(std::move(rFrameStyle)).m_pStyle->GetStyleName();
    m_pLayout->SetStyleName(m_StyleName);
}
 
/**
* @descr:  parse frame and set frame properties
* @param:   pXFFrame - XFFrame object
* @param:  nPageNo - the page number that the frame anchors
*
*/
void LwpFrame::Parse(XFFrame* pXFFrame, sal_Int32 nPageNo)
{
    //set the frame style name
    pXFFrame->SetStyleName(m_StyleName);
 
    //SetAnchorType and position,if it's page anchor,set the page number.
    ParseAnchorType(pXFFrame);
    if (nPageNo > 0)
    {
        pXFFrame->SetAnchorPage(nPageNo);
    }
 
    //Set frame Name
    OUString aFrameName = m_pLayout->GetName().str();
    if (!aFrameName.isEmpty())
    {
        //cause the bug of SODC, the linkframe name can not be "Frame1", so I change the frame name
        /*if(aFrameName.equals("Frame1"))
        {
            aFrameName = "Frame1_COPY";
        }
        pXFFrame->SetName(aFrameName);*/
        pXFFrame->SetName(m_StyleName);
    }
 
    LwpLayoutGeometry* pLayoutGeo = m_pLayout->GetGeometry();
    //Set frame Width and height
    if (pLayoutGeo)
    {
        double fWidth = m_pLayout->GetWidth();
        double fHeight = m_pLayout->GetHeight();
 
        pXFFrame->SetWidth(fWidth);
        pXFFrame->SetHeight(fHeight);
 
        //Get content obj;
        /*LwpObject* pObj =*/m_pLayout->GetContent().obj();
        if (m_pLayout->IsGroupHead() && (m_pLayout->IsMinimumHeight()))
        {
            //process grouplayout height. there is problems now
            pXFFrame->SetHeight(fHeight);
        }
        /*
        else if(m_pLayout->IsFitGraphic() && pObj && pObj->GetTag() == VO_GRAPHIC)
        {
            //If is graphic, get original size and set it;
            LwpGraphicObject* pGrpObj = static_cast<LwpGraphicObject*>(pObj);
            long nHeight =0, nWidth =0;
            pGrpObj->GetGrafOrgSize(nWidth, nHeight);
            //add margins to the width and height;
            fWidth = (double)nWidth/TWIPS_PER_CM + m_pLayout->GetMarginsValue(MARGIN_LEFT) + m_pLayout->GetMarginsValue(MARGIN_RIGHT);
            fHeight = (double)nHeight/TWIPS_PER_CM + m_pLayout->GetMarginsValue(MARGIN_TOP) + m_pLayout->GetMarginsValue(MARGIN_BOTTOM);
            pXFFrame->SetWidth(fWidth);
            pXFFrame->SetHeight(fHeight);
        }
        */
        else if (m_pLayout->IsAutoGrow())
        {
            pXFFrame->SetMinHeight(fHeight);
        }
    }
 
    if (m_pLayout->IsFrame())
    {
        //Set frame link. Only frame layout has this feature
        LwpFrameLayout* pLayout = static_cast<LwpFrameLayout*>(m_pLayout);
        pXFFrame->SetNextLink(pLayout->GetNextLinkName());
    }
}
/**
* @descr:  parse frame relative to page, frame or cell
* @param:   pCont - content container which contains the frame
*
*/
void LwpFrame::XFConvert(XFContentContainer* pCont)
{
    // parse the frame which anchor to page
    rtl::Reference<LwpVirtualLayout> xParent = m_pLayout->GetParentLayout();
    if (!xParent.is())
        throw std::runtime_error("missing Parent Layout");
    if (xParent->IsPage() && xParent->GetParentLayout().is()
        && xParent->GetParentLayout()->IsPage())
    {
        //for mirror page, problems exist if the parent layout is header or footer layout,
        xParent = xParent->GetParentLayout();
    }
    if (m_pLayout->IsAnchorPage() && xParent->IsPage())
    {
        //get parent layout
        if (m_pLayout->IsUseOnPage())
        {
            sal_Int32 nPageNo = xParent->GetPageNumber(m_pLayout->GetUsePage());
            if (nPageNo > 0)
                m_pLayout->XFConvertFrame(pCont, nPageNo);
        }
        else if (m_pLayout->IsUseOnAllPages())
        {
            sal_Int32 nFirst = xParent->GetPageNumber(FIRST_LAYOUTPAGENO);
            sal_Int32 nLast = xParent->GetPageNumber(LAST_LAYOUTPAGENO);
            if (nLast > 0)
                m_pLayout->XFConvertFrame(pCont, nFirst, nLast, true);
        }
        else if (m_pLayout->IsUseOnAllOddPages() || m_pLayout->IsUseOnAllEvenPages())
        {
            sal_Int32 nFirst = xParent->GetPageNumber(FIRST_LAYOUTPAGENO);
            sal_Int32 nLast = xParent->GetPageNumber(LAST_LAYOUTPAGENO);
            if (nLast > 0)
            {
                sal_uInt16 first = static_cast<sal_uInt16>(nFirst);
                if ((m_pLayout->IsUseOnAllOddPages() && !LwpTools::IsOddNumber(first))
                    || (m_pLayout->IsUseOnAllEvenPages() && !LwpTools::IsEvenNumber(first)))
                    nFirst++;
                if (nFirst <= nLast)
                {
                    m_pLayout->XFConvertFrame(pCont, nFirst, nLast);
                }
            }
        }
    }
    else
    {
        m_pLayout->XFConvertFrame(pCont);
    }
}
/**
* @descr:  set frame wrap type style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyWrapType(XFFrameStyle* pFrameStyle)
{
    enumXFWrap eWrap = enumXFWrapNone;
    switch (m_pLayout->GetWrapType())
    {
        case LwpPlacableLayout::LAY_WRAP_AROUND: //fall through
        case LwpPlacableLayout::LAY_WRAP_IRREG_BIGGEST:
        {
            //In SODC, if Optimal wrap type is used and the distance between the frame object
            //and page margins is less than 2cm, the text is not wrapped. While there is no this feature in Word Pro
            //So the optimal wrap type is translated to left side or right side wrap type according to the distance
            //between the frame object and page margins
 
            eWrap = enumXFWrapBest;
            rtl::Reference<LwpVirtualLayout> xContainer(m_pLayout->GetContainerLayout());
            LwpMiddleLayout* pParent = dynamic_cast<LwpMiddleLayout*>(xContainer.get());
            if (pParent)
            {
                if (IsLeftWider())
                    eWrap = enumXFWrapLeft;
                else
                    eWrap = enumXFWrapRight;
            }
            break;
        }
        case LwpPlacableLayout::LAY_NO_WRAP_BESIDE:
        {
            eWrap = enumXFWrapNone;
            break;
        }
        case LwpPlacableLayout::LAY_NO_WRAP_AROUND:
        {
            eWrap = enumXFWrapRunThrough;
            if (!m_pLayout->GetBackColor() && !m_pLayout->GetWaterMarkLayout().is())
            {
                //pFrameStyle->SetBackGround(sal_True);
                XFColor aXFColor(0xffffff); //white color
                pFrameStyle->SetBackColor(aXFColor);
                pFrameStyle->SetTransparency(100); //transparency
            }
            break;
        }
        case LwpPlacableLayout::LAY_WRAP_LEFT: //fall through
        case LwpPlacableLayout::LAY_WRAP_IRREG_LEFT:
        {
            eWrap = enumXFWrapLeft;
            break;
        }
        case LwpPlacableLayout::LAY_WRAP_RIGHT: //fall through
        case LwpPlacableLayout::LAY_WRAP_IRREG_RIGHT:
        {
            eWrap = enumXFWrapRight;
            break;
        }
        case LwpPlacableLayout::LAY_WRAP_BOTH: //fall through
        case LwpPlacableLayout::LAY_WRAP_IRREG_BOTH:
        {
            eWrap = enumXFWrapParallel;
            break;
        }
        default:
            break;
    }
 
    //If it is the type of with para above, wrap type is enumXFWrapNone
    if (m_pLayout->GetRelativeType() == LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE)
    {
        eWrap = enumXFWrapNone;
    }
 
    pFrameStyle->SetWrapType(eWrap);
}
/**
* @descr:   set frame margins style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyMargins(XFFrameStyle* pFrameStyle)
{
    double fLeft = m_pLayout->GetExtMarginsValue(MARGIN_LEFT);
    double fRight = m_pLayout->GetExtMarginsValue(MARGIN_RIGHT);
    double fTop = m_pLayout->GetExtMarginsValue(MARGIN_TOP);
    double fBottom = m_pLayout->GetExtMarginsValue(MARGIN_BOTTOM);
    pFrameStyle->SetMargins(fLeft, fRight, fTop, fBottom);
}
/**
* @descr:  set padding border style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyPadding(XFFrameStyle* pFrameStyle)
{
    double fLeft = m_pLayout->GetMarginsValue(MARGIN_LEFT);
    double fRight = m_pLayout->GetMarginsValue(MARGIN_RIGHT);
    double fTop = m_pLayout->GetMarginsValue(MARGIN_TOP);
    double fBottom = m_pLayout->GetMarginsValue(MARGIN_BOTTOM);
    pFrameStyle->SetPadding(fLeft, fRight, fTop, fBottom);
}
/**
* @descr:  set frame border style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyBorders(XFFrameStyle* pFrameStyle)
{
    std::unique_ptr<XFBorders> pBordres = m_pLayout->GetXFBorders();
    if (pBordres)
    {
        pFrameStyle->SetBorders(std::move(pBordres));
    }
}
/**
* @descr:  set frame columns style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyColumns(XFFrameStyle* pFrameStyle)
{
    XFColumns* pColumns = m_pLayout->GetXFColumns();
    if (pColumns)
    {
        pFrameStyle->SetColumns(pColumns);
    }
}
/**
* @descr:  set frame shadow style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyShadow(XFFrameStyle* pFrameStyle)
{
    XFShadow* pXFShadow = m_pLayout->GetXFShadow();
    if (pXFShadow)
    {
        pFrameStyle->SetShadow(pXFShadow);
    }
}
/**
* @descr:  set frame back color style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyBackColor(XFFrameStyle* pFrameStyle)
{
    LwpColor* pColor = m_pLayout->GetBackColor();
    if (pColor)
    {
        XFColor aXFColor(pColor->To24Color());
        pFrameStyle->SetBackColor(aXFColor);
    }
}
/**
* @descr:  set frame protect style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyProtect(XFFrameStyle* pFrameStyle)
{
    if (m_pLayout->GetIsProtected())
    {
        pFrameStyle->SetProtect(true, true, true);
    }
}
/**
* @descr:  set frame text direction style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyTextDir(XFFrameStyle* pFrameStyle)
{
    pFrameStyle->SetTextDir(m_pLayout->GetTextDirection());
}
/**
* @descr:  set frame position type style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyPosType(XFFrameStyle* pFrameStyle)
{
    enumXFFrameXPos eXPos = enumXFFrameXPosCenter;
    enumXFFrameXRel eXRel = enumXFFrameXRelPara;
    enumXFFrameYPos eYPos = enumXFFrameYPosMiddle;
    enumXFFrameYRel eYRel = enumXFFrameYRelPara;
    sal_uInt8 nType = m_pLayout->GetRelativeType();
    switch (nType)
    {
        case LwpLayoutRelativityGuts::LAY_PARENT_RELATIVE: //fall through
        case LwpLayoutRelativityGuts::LAY_CONTENT_RELATIVE:
        {
            //anchor to page, frame and cell
            eXPos = enumXFFrameXPosFromLeft;
            eXRel = enumXFFrameXRelPage;
            //set vertical position
            if (m_pLayout->IsAnchorPage()) //in page
            {
                rtl::Reference<LwpVirtualLayout> xContainer(m_pLayout->GetContainerLayout());
                if (xContainer.is() && (xContainer->IsHeader() || xContainer->IsFooter()))
                {
                    //Only anchor to para, the frame can display in header and footer of each page
                    eYPos = enumXFFrameYPosFromTop; //from top
                    eYRel = enumXFFrameYRelPara; //from margin
                }
                else
                {
                    eYPos = enumXFFrameYPosFromTop;
                    eYRel = enumXFFrameYRelPage;
                }
            }
            if (m_pLayout->IsAnchorFrame()) //in frame
            {
                eYPos = enumXFFrameYPosFromTop;
                eYRel = enumXFFrameYRelPage;
            }
            if (m_pLayout->IsAnchorCell())
            {
                //SODC has no this type, simulate this feature
                eYPos = enumXFFrameYPosFromTop; //from top
                eYRel = enumXFFrameYRelPara; //from margin
            }
            break;
        }
        case LwpLayoutRelativityGuts::LAY_PARA_RELATIVE: //same page as text
        {
            eXPos = enumXFFrameXPosFromLeft;
            eXRel = enumXFFrameXRelPage;
            //set vertical position
            rtl::Reference<LwpVirtualLayout> xContainer(m_pLayout->GetContainerLayout());
            if (xContainer.is() && xContainer->IsPage()) //in page
            {
                //eYPos = enumXFFrameYPosFromTop;
                //eYRel = enumXFFrameYRelPage;
                eYPos = enumXFFrameYPosBelow;
                eYRel = enumXFFrameYRelChar;
            }
            else if (xContainer.is() && xContainer->IsFrame()) //in frame
            {
                eYPos = enumXFFrameYPosFromTop;
                eYRel = enumXFFrameYRelPage;
            }
            else
            {
                eYPos = enumXFFrameYPosFromTop; //from top
                eYRel = enumXFFrameYRelPara; //from margin
            }
            break;
        }
        case LwpLayoutRelativityGuts::LAY_INLINE: //in text
        {
            eXPos = enumXFFrameXPosFromLeft; //need not be set
            eXRel = enumXFFrameXRelParaContent; //need not be set
            eYPos = enumXFFrameYPosTop; //should be from top
            eYRel = enumXFFrameYRelBaseLine;
            sal_Int32 nOffset = m_pLayout->GetBaseLineOffset();
            if (nOffset > 0)
            {
                eYPos = enumXFFrameYPosFromTop;
            }
            break;
        }
        case LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE: //with para above
        {
            eXPos = enumXFFrameXPosFromLeft;
            eXRel = enumXFFrameXRelParaContent;
            //eYPos = enumXFFrameYPosTop;
            eYPos = enumXFFrameYPosBottom;
            eYRel = enumXFFrameYRelParaContent;
            break;
        }
        case LwpLayoutRelativityGuts::LAY_INLINE_VERTICAL: //in text - vertical
        {
            eXPos = enumXFFrameXPosFromLeft;
            eXRel = enumXFFrameXRelPage;
            eYPos = enumXFFrameYPosFromTop; //should be below position
            eYRel = enumXFFrameYRelChar;
            break;
        }
        default:
            break;
    }
 
    pFrameStyle->SetXPosType(eXPos, eXRel);
    pFrameStyle->SetYPosType(eYPos, eYRel);
}
/**
* @descr:  set frame watermark style
* @param:  pFrameStyle - Frame Style object
*
*/
void LwpFrame::ApplyWatermark(XFFrameStyle* pFrameStyle)
{
    std::unique_ptr<XFBGImage> xBGImage(m_pLayout->GetXFBGImage());
    if (xBGImage)
    {
        pFrameStyle->SetBackImage(xBGImage);
        //set watermark transparent
        rtl::Reference<LwpVirtualLayout> xWaterMarkLayout(m_pLayout->GetWaterMarkLayout());
        LwpMiddleLayout* pLay = dynamic_cast<LwpMiddleLayout*>(xWaterMarkLayout.get());
        LwpBackgroundStuff* pBackgroundStuff = pLay ? pLay->GetBackgroundStuff() : nullptr;
        if (pBackgroundStuff && !pBackgroundStuff->IsTransparent())
        {
            pFrameStyle->SetTransparency(100);
        }
    }
}
 
/**
 * @short   Apply pattern fill to frame style
 * @param pFrameStyle - pointer of XFFrameStyle
 * @return
 */
void LwpFrame::ApplyPatternFill(XFFrameStyle* pFrameStyle)
{
    std::unique_ptr<XFBGImage> xXFBGImage(m_pLayout->GetFillPattern());
    if (xXFBGImage)
    {
        pFrameStyle->SetBackImage(xXFBGImage);
    }
}
 
/**
 * @short   Apply background to frame style
 * @param pFrameStyle - pointer of XFFrameStyle
 * @return
 */
void LwpFrame::ApplyBackGround(XFFrameStyle* pFrameStyle)
{
    if (!m_pLayout)
    {
        return;
    }
 
    if (m_pLayout->IsPatternFill())
    {
        ApplyPatternFill(pFrameStyle);
    }
    else
    {
        ApplyBackColor(pFrameStyle);
    }
}
 
/**
* @descr:  set frame size, anchor type, anchored page number
* @param:  pXFFrame - XFFrame  object
*
*/
void LwpFrame::ParseAnchorType(XFFrame* pXFFrame)
{
    //set position
    double fXOffset = 0;
    double fYOffset = 0;
    //set anchor type
    enumXFAnchor eAnchor = enumXFAnchorNone;
 
    LwpLayoutGeometry* pLayoutGeo = m_pLayout->GetGeometry();
    if (pLayoutGeo)
    {
        LwpPoint aPoint = pLayoutGeo->GetOrigin();
        fXOffset = LwpTools::ConvertFromUnits(aPoint.GetX());
        fYOffset = LwpTools::ConvertFromUnits(aPoint.GetY());
    }
    //set anchor type
    eAnchor = enumXFAnchorNone;
    sal_uInt8 nType = m_pLayout->GetRelativeType();
    switch (nType)
    {
        case LwpLayoutRelativityGuts::LAY_PARENT_RELATIVE: //fall through
        case LwpLayoutRelativityGuts::LAY_CONTENT_RELATIVE:
        {
            //anchor to page, frame and cell
            if (m_pLayout->IsAnchorPage()) //in page
            {
                rtl::Reference<LwpVirtualLayout> xContainer(m_pLayout->GetContainerLayout());
                if (xContainer.is() && (xContainer->IsHeader() || xContainer->IsFooter()))
                {
                    eAnchor = enumXFAnchorPara;
                    fYOffset -= xContainer->GetMarginsValue(MARGIN_TOP);
                }
                else
                    eAnchor = enumXFAnchorPage;
            }
            if (m_pLayout->IsAnchorFrame()) //in frame
            {
                eAnchor = enumXFAnchorFrame;
            }
            if (m_pLayout->IsAnchorCell()) //in cell
            {
                //eAnchor = enumXFAnchorChar;
                eAnchor = enumXFAnchorPara;
                rtl::Reference<LwpVirtualLayout> xContainer(m_pLayout->GetContainerLayout());
                LwpMiddleLayout* pContainer = dynamic_cast<LwpMiddleLayout*>(xContainer.get());
                if (pContainer)
                {
                    fYOffset -= pContainer->GetMarginsValue(MARGIN_TOP);
                }
            }
            break;
        }
        case LwpLayoutRelativityGuts::LAY_PARA_RELATIVE: //same page as text
        {
            eAnchor = enumXFAnchorChar;
            rtl::Reference<LwpVirtualLayout> xContainer(m_pLayout->GetContainerLayout());
            if (xContainer.is() && xContainer->IsPage()) //in page
            {
                //eAnchor = enumXFAnchorPage;
                eAnchor = enumXFAnchorChar; // to character
            }
            else if (xContainer.is() && xContainer->IsFrame()) //in frame
            {
                eAnchor = enumXFAnchorFrame;
            }
            else if (xContainer.is() && xContainer->IsCell()) //in cell
            {
                //eAnchor = enumXFAnchorChar;
                eAnchor = enumXFAnchorPara;
                fYOffset -= xContainer->GetMarginsValue(MARGIN_TOP);
            }
            else if (xContainer.is()
                     && (xContainer->IsHeader() || xContainer->IsFooter())) //in header or footer
            {
                eAnchor = enumXFAnchorPara;
                fYOffset -= xContainer->GetMarginsValue(MARGIN_TOP);
            }
            break;
        }
        case LwpLayoutRelativityGuts::LAY_INLINE: //in text
        {
            eAnchor = enumXFAnchorAsChar;
            sal_Int32 nOffset = m_pLayout->GetBaseLineOffset();
            if (nOffset > 0 && pLayoutGeo)
            {
                //experiential value
                fYOffset = -(m_pLayout->GetGeometryHeight()
                             + 2 * m_pLayout->GetExtMarginsValue(MARGIN_BOTTOM)
                             - LwpTools::ConvertFromUnits(nOffset));
            }
            break;
        }
        case LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE: //with para above
        {
            eAnchor = enumXFAnchorPara;
            break;
        }
        case LwpLayoutRelativityGuts::LAY_INLINE_VERTICAL: //in text - vertical
        {
            eAnchor = enumXFAnchorChar;
            //set vertical position
            double offset = 0;
 
            //because of the different feature between Word Pro and SODC, I simulate the vertical base offset
            //between anchor and frame origin using the font height.
            rtl::Reference<XFFont> pFont = m_pLayout->GetFont();
            if (pFont.is())
            {
                offset = o3tl::convert<double>(pFont->GetFontSize(), o3tl::Length::pt,
                                               o3tl::Length::cm);
            }
            fYOffset = offset - fYOffset;
            break;
        }
        default:
            break;
    }
 
    pXFFrame->SetX(fXOffset);
    pXFFrame->SetY(fYOffset);
    pXFFrame->SetAnchorPage(0);
    pXFFrame->SetAnchorType(eAnchor);
}
 
/**
 * @descr Calculate the distance between the frame object and the page margins.
 *       And determine which side(left or right) is wider
 */
bool LwpFrame::IsLeftWider()
{
    rtl::Reference<LwpVirtualLayout> xLayout(m_pLayout->GetContainerLayout());
    LwpVirtualLayout* pParent = xLayout.get();
    if (!pParent)
        return false;
    LwpPoint aPoint = m_pLayout->GetOrigin();
    double fXOffset = LwpTools::ConvertFromUnits(aPoint.GetX());
    double fWidth = m_pLayout->GetWidth();
    double fWrapLeft = m_pLayout->GetExtMarginsValue(MARGIN_LEFT);
    double fWrapRight = m_pLayout->GetExtMarginsValue(MARGIN_RIGHT);
 
    //LwpPoint aParentPoint = pParent->GetOrigin();
    //double fParentXOffset = LwpTools::ConvertFromUnitsToMetric(aParentPoint.GetX());
    double fParentWidth = pParent->GetWidth();
    if (pParent->IsCell())
    {
        //Get actual width of this cell layout
        fParentWidth = static_cast<LwpCellLayout*>(pParent)->GetActualWidth();
    }
    double fParentMarginLeft = pParent->GetMarginsValue(MARGIN_LEFT);
    double fParentMarginRight = pParent->GetMarginsValue(MARGIN_RIGHT);
 
    double fLeft = fXOffset - fWrapLeft - fParentMarginLeft;
    double fRight = fParentWidth - fParentMarginRight - (fXOffset + fWidth + fWrapRight);
    if (fLeft > fRight)
        return true;
    return false;
}
 
LwpFrameLink::LwpFrameLink() {}
 
/**
 * @descr frame link information
 *
 */
void LwpFrameLink::Read(LwpObjectStream* pStrm)
{
    m_PreviousLayout.ReadIndexed(pStrm);
    m_NextLayout.ReadIndexed(pStrm);
    pStrm->SkipExtra();
}
 
LwpFrameLayout::LwpFrameLayout(LwpObjectHeader const& objHdr, LwpSvStream* pStrm)
    : LwpPlacableLayout(objHdr, pStrm)
    , m_bGettingMaxWidth(false)
{
}
 
LwpFrameLayout::~LwpFrameLayout() {}
 
/**
 * @descr read frame layout object
 *
 */
void LwpFrameLayout::Read()
{
    LwpPlacableLayout::Read();
    if (LwpFileHeader::m_nFileRevision >= 0x000B)
    {
        if (m_pObjStrm->QuickReaduInt16())
        {
            m_Link.Read(m_pObjStrm.get());
        }
    }
    m_pObjStrm->SkipExtra();
}
 
/**
 * @descr create a xfframe and add into content container
 * @param:  pCont - content container that contains the frame.
 *
 */
void LwpFrameLayout::XFConvert(XFContentContainer* pCont)
{
    if (!m_pFrame)
        return;
 
    //parse the frame which anchor to paragraph
    if (IsRelativeAnchored())
    {
        XFConvertFrame(pCont);
    }
    else
    {
        m_pFrame->XFConvert(pCont);
    }
}
/**
 * @descr create a xfframe and add into content container, called by XFConvert
 * @param:  pCont - content container that contains the frame.
 * @param:  nPageNo - the page number that the frame anchors
 *
 */
void LwpFrameLayout::XFConvertFrame(XFContentContainer* pCont, sal_Int32 nStart, sal_Int32 nEnd,
                                    bool bAll)
{
    if (!m_pFrame)
        return;
 
    rtl::Reference<XFFrame> xXFFrame;
    if (nEnd < nStart)
    {
        xXFFrame.set(new XFFrame);
    }
    else
    {
        xXFFrame.set(new XFFloatFrame(nStart, nEnd, bAll));
    }
 
    m_pFrame->Parse(xXFFrame.get(), nStart);
    //if it is a link frame, parse contents only once
    if (!HasPreviousLinkLayout())
    {
        rtl::Reference<LwpObject> content = m_Content.obj();
        if (content.is())
        {
            content->DoXFConvert(xXFFrame.get());
            //set frame size according to ole size
            ApplyGraphicSize(xXFFrame.get());
        }
    }
    pCont->Add(xXFFrame.get());
}
/**
 * @descr register frame style
 *
 */
void LwpFrameLayout::RegisterStyle()
{
    //if it is for water mark, don't register style
    if (IsForWaterMark())
        return;
 
    if (m_pFrame)
        return;
 
    //register frame style
    std::unique_ptr<XFFrameStyle> xFrameStyle(new XFFrameStyle);
    m_pFrame.reset(new LwpFrame(this));
    m_pFrame->RegisterStyle(xFrameStyle);
 
    //register content style
    rtl::Reference<LwpObject> content = m_Content.obj();
    if (content.is())
    {
        content->SetFoundry(m_pFoundry);
        content->DoRegisterStyle();
    }
 
    //register child frame style
    RegisterChildStyle();
}
 
/**
 * @descr get the name of the frame that current frame links
 *
 */
OUString LwpFrameLayout::GetNextLinkName()
{
    OUString aName;
    LwpObjectID& rObjectID = m_Link.GetNextLayout();
    if (!rObjectID.IsNull())
    {
        LwpLayout* pLayout = dynamic_cast<LwpLayout*>(rObjectID.obj().get());
        if (pLayout)
        {
            LwpAtomHolder& rHolder = pLayout->GetName();
            aName = rHolder.str();
            //for division name conflict
            if (!pLayout->GetStyleName().isEmpty())
                aName = pLayout->GetStyleName();
        }
    }
    return aName;
}
/**
 * @descr whether current frame is linked by other frame
 *
 */
bool LwpFrameLayout::HasPreviousLinkLayout()
{
    LwpObjectID& rObjectID = m_Link.GetPreviousLayout();
    return !rObjectID.IsNull();
}
/**
 * @descr whether current frame is for water mark. Problem maybe exists by this method, must be tracking
 *
 */
bool LwpFrameLayout::IsForWaterMark()
{
    if (m_nBuoyancy >= LAY_BUOYLAYER)
    {
        if (m_Content.IsNull())
            return false;
        rtl::Reference<LwpObject> content = m_Content.obj();
        if (!content.is())
            return false;
        if (content->GetTag() == VO_GRAPHIC)
            return true;
    }
    return false;
}
 
/**
 * @descr Get frame width
 *
 */
double LwpFrameLayout::GetWidth()
{
    double fWidth = LwpMiddleLayout::GetWidth();
    if (IsInlineToMargin() && IsAutoGrowWidth())
    {
        //for text field entry when choosing maximize field length
        fWidth = GetMaxWidth();
    }
    return fWidth;
}
 
/**
 * @descr Get frame width when the text field chooses maximize field length
 *
 */
double LwpFrameLayout::GetMaxWidth()
{
    if (m_bGettingMaxWidth)
        throw std::runtime_error("recursive GetMaxWidth");
 
    m_bGettingMaxWidth = true;
    double fActualWidth = 0;
    rtl::Reference<LwpVirtualLayout> xLayout(GetContainerLayout());
    LwpMiddleLayout* pParent = dynamic_cast<LwpMiddleLayout*>(xLayout.get());
    if (pParent)
    {
        LwpPoint aPoint = GetOrigin();
        double fXOffset = LwpTools::ConvertFromUnits(aPoint.GetX());
        double fWrapRight = GetExtMarginsValue(MARGIN_RIGHT);
 
        //Get parent layout width
        double fParentWidth = pParent->GetWidth();
        if (pParent->IsCell())
        {
            //Get actual width of this cell layout
            fParentWidth = static_cast<LwpCellLayout*>(pParent)->GetActualWidth();
        }
 
        double fParentMarginRight = 0;
        sal_uInt8 nType = GetRelativeType();
        if (nType == LwpLayoutRelativityGuts::LAY_INLINE
            || nType == LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE)
        {
            fParentMarginRight = pParent->GetMarginsValue(MARGIN_RIGHT);
        }
 
        fActualWidth = fParentWidth - fXOffset - fParentMarginRight - fWrapRight;
    }
 
    m_bGettingMaxWidth = false;
    return fActualWidth;
}
 
/**
 * @descr Set frame size according to graphic size
 *
 */
void LwpFrameLayout::ApplyGraphicSize(XFFrame* pXFFrame)
{
    rtl::Reference<LwpObject> content = m_Content.obj();
    if (!(content.is() && (content->GetTag() == VO_GRAPHIC || content->GetTag() == VO_OLEOBJECT)))
        return;
 
    LwpGraphicOleObject* pGraOle = static_cast<LwpGraphicOleObject*>(content.get());
    //Get frame geometry size
    double fWidth = 0;
    double fHeight = 0;
    pGraOle->GetGrafScaledSize(fWidth, fHeight);
    if (IsFitGraphic())
    {
        //graphic scaled sze
        fWidth += GetMarginsValue(MARGIN_LEFT) + GetMarginsValue(MARGIN_RIGHT);
        fHeight += GetMarginsValue(MARGIN_TOP) + GetMarginsValue(MARGIN_BOTTOM);
    }
    else if (IsAutoGrowDown() || IsAutoGrowUp())
    {
        fWidth = GetWidth();
        fHeight += GetMarginsValue(MARGIN_TOP) + GetMarginsValue(MARGIN_BOTTOM);
    }
    else if (IsAutoGrowLeft() || IsAutoGrowRight())
    {
        fHeight = GetHeight();
        fWidth += GetMarginsValue(MARGIN_LEFT) + GetMarginsValue(MARGIN_RIGHT);
    }
    else
    {
        fWidth = GetWidth();
        fHeight = GetHeight();
    }
    pXFFrame->SetWidth(fWidth);
    pXFFrame->SetHeight(fHeight);
}
 
LwpGroupLayout::LwpGroupLayout(LwpObjectHeader const& objHdr, LwpSvStream* pStrm)
    : LwpPlacableLayout(objHdr, pStrm)
{
}
 
LwpGroupLayout::~LwpGroupLayout() {}
/**
 * @descr read group layout object
 *
 */
void LwpGroupLayout::Read()
{
    LwpPlacableLayout::Read();
    m_pObjStrm->SkipExtra();
}
/**
 * @descr register group frame style
 *
 */
void LwpGroupLayout::RegisterStyle()
{
    if (m_pFrame)
        return;
 
    //register frame style
    std::unique_ptr<XFFrameStyle> xFrameStyle(new XFFrameStyle);
    m_pFrame.reset(new LwpFrame(this));
    m_pFrame->RegisterStyle(xFrameStyle);
 
    //register child frame style
    RegisterChildStyle();
}
/**
 * @descr create a xfframe and add into content container
 * @param:  pCont - content container that contains the frame.
 *
 */
void LwpGroupLayout::XFConvert(XFContentContainer* pCont)
{
    if (!m_pFrame)
        return;
 
    //parse the frame which anchor to paragraph
    if (IsRelativeAnchored())
    {
        XFConvertFrame(pCont);
    }
    else
    {
        m_pFrame->XFConvert(pCont);
    }
}
/**
 * @descr create a xfframe and add into content container, called by XFConvert
 * @param:  pCont - content container that contains the frame.
 * @param:  nPageNo - the page number that the frame anchors
 *
 */
void LwpGroupLayout::XFConvertFrame(XFContentContainer* pCont, sal_Int32 nStart, sal_Int32 nEnd,
                                    bool bAll)
{
    if (!m_pFrame)
        return;
 
    rtl::Reference<XFFrame> xXFFrame;
    if (nEnd < nStart)
    {
        xXFFrame.set(new XFFrame);
    }
    else
    {
        xXFFrame.set(new XFFloatFrame(nStart, nEnd, bAll));
    }
 
    m_pFrame->Parse(xXFFrame.get(), nStart);
 
    //add child frame into group
    LwpVirtualLayout* pLayout = dynamic_cast<LwpVirtualLayout*>(GetChildHead().obj().get());
 
    while (pLayout && pLayout != this)
    {
        pLayout->DoXFConvert(xXFFrame.get());
        pLayout = dynamic_cast<LwpVirtualLayout*>(pLayout->GetNext().obj().get());
    }
 
    pCont->Add(xXFFrame.get());
}
 
LwpGroupFrame::LwpGroupFrame(LwpObjectHeader const& objHdr, LwpSvStream* pStrm)
    : LwpContent(objHdr, pStrm)
{
}
 
LwpGroupFrame::~LwpGroupFrame() {}
 
void LwpGroupFrame::Read()
{
    LwpContent::Read();
    m_pObjStrm->SkipExtra();
}
 
void LwpGroupFrame::RegisterStyle() {}
 
void LwpGroupFrame::XFConvert(XFContentContainer* /*pCont*/) {}
 
LwpDropcapLayout::LwpDropcapLayout(LwpObjectHeader const& objHdr, LwpSvStream* pStrm)
    : LwpFrameLayout(objHdr, pStrm)
    , m_nLines(3)
    , m_nChars(1)
{
}
 
void LwpDropcapLayout::Read()
{
    LwpFrameLayout::Read();
    m_nLines = m_pObjStrm->QuickReaduInt16();
    m_pObjStrm->SeekRel(1);
    m_pObjStrm->SkipExtra();
}
 
void LwpDropcapLayout::Parse(IXFStream* pOutputStream)
{
    LwpStory* pStory = static_cast<LwpStory*>(m_Content.obj(VO_STORY).get());
    if (!pStory)
        return;
    rtl::Reference<LwpObject> pPara = pStory->GetFirstPara().obj(VO_PARA);
    if (pPara.is())
    {
        pPara->SetFoundry(m_pFoundry);
        pPara->DoParse(pOutputStream);
    }
}
 
void LwpDropcapLayout::XFConvert(XFContentContainer* pCont)
{
    LwpStory* pStory = static_cast<LwpStory*>(m_Content.obj(VO_STORY).get());
    if (pStory)
    {
        pStory->SetFoundry(m_pFoundry);
        pStory->XFConvert(pCont);
    }
}
 
void LwpDropcapLayout::RegisterStyle(LwpFoundry* pFoundry)
{
    LwpStory* pStory = dynamic_cast<LwpStory*>(m_Content.obj(VO_STORY).get());
    if (pStory)
    {
        pStory->SetDropcapFlag(true);
        pStory->SetFoundry(pFoundry);
        LwpPara* pPara = dynamic_cast<LwpPara*>(pStory->GetFirstPara().obj().get());
        while (pPara)
        {
            pPara->SetFoundry(pFoundry);
            pPara->RegisterStyle();
            pPara = dynamic_cast<LwpPara*>(pPara->GetNext().obj().get());
        }
    }
}
 
/**
 * @descr  do nothing
 *
 */
void LwpDropcapLayout::RegisterStyle() {}
 
LwpRubyLayout::LwpRubyLayout(LwpObjectHeader const& objHdr, LwpSvStream* pStrm)
    : LwpFrameLayout(objHdr, pStrm)
    , m_nPlacement(0)
    , m_nAlignment(0)
    , m_nStateFlag(0)
    , m_nXOffset(0)
    , m_nYOffset(0)
{
}
 
void LwpRubyLayout::Read()
{
    LwpFrameLayout::Read();
    m_nPlacement = m_pObjStrm->QuickReaduInt8();
    m_nAlignment = m_pObjStrm->QuickReaduInt8();
    m_nStateFlag = m_pObjStrm->QuickReaduInt16();
    m_nXOffset = m_pObjStrm->QuickReadInt32();
    m_nYOffset = m_pObjStrm->QuickReadInt32();
    m_objRubyMarker.ReadIndexed(m_pObjStrm.get());
    m_pObjStrm->SkipExtra();
}
 
LwpRubyMarker* LwpRubyLayout::GetMarker()
{
    return static_cast<LwpRubyMarker*>(m_objRubyMarker.obj(VO_RUBYMARKER).get());
}
 
LwpStory* LwpRubyLayout::GetContentStory()
{
    return static_cast<LwpStory*>(m_Content.obj(VO_STORY).get());
}
 
void LwpRubyLayout::ConvertContentText()
{
    LwpStory* pStory = GetContentStory();
    LwpRubyMarker* pMarker = GetMarker();
    if (pStory && pMarker)
        pMarker->SetRubyText(pStory->GetContentText(true));
}
 
void LwpRubyLayout::RegisterStyle()
{
    LwpRubyMarker* pMarker = GetMarker();
    if (!pMarker)
        throw std::runtime_error("missing Ruby Marker");
 
    std::unique_ptr<XFRubyStyle> xRubyStyle(new XFRubyStyle);
 
    enumXFRubyPosition eType = enumXFRubyLeft;
    if (m_nAlignment == LEFT)
    {
        eType = enumXFRubyLeft;
    }
    else if (m_nAlignment == RIGHT)
    {
        eType = enumXFRubyRight;
    }
    else if (m_nAlignment == CENTER)
    {
        eType = enumXFRubyCenter;
    }
    xRubyStyle->SetAlignment(eType);
 
    eType = enumXFRubyTop;
    if (m_nPlacement == TOP)
    {
        eType = enumXFRubyTop;
    }
    else if (m_nPlacement == BOTTOM)
    {
        eType = enumXFRubyBottom;
    }
    xRubyStyle->SetPosition(eType);
 
    XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
    OUString rubyStyle = pXFStyleManager->AddStyle(std::move(xRubyStyle)).m_pStyle->GetStyleName();
    pMarker->SetRubyStyleName(rubyStyle);
 
    LwpStory* pStory = GetContentStory();
    pStory->SetFoundry(m_pFoundry);
    OUString textStyle = pStory->RegisterFirstFribStyle();
    pMarker->SetTextStyleName(textStyle);
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V1048 The 'eYRel' variable was assigned the same value.

V1048 The 'eYRel' variable was assigned the same value.

V1048 The 'eAnchor' variable was assigned the same value.

V1048 The 'eType' variable was assigned the same value.

V1048 The 'eType' variable was assigned the same value.