<commit_before>/*
 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
 *
 * The contents of this file are subject to the Mozilla Public 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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Initial Developer of the Original Code is
 *       Miklos Vajna <vmiklos@frugalware.org>
 * Portions created by the Initial Developer are Copyright (C) 2011 the
 * Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
 * instead of those above.
 */

#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
#include <com/sun/star/text/WritingMode.hpp>

#include <ooxml/resourceids.hxx> // NS_ooxml namespace
#include <filter/msfilter/escherex.hxx>
#include <filter/msfilter/util.hxx>

#include <rtfsdrimport.hxx>

using rtl::OString;
using rtl::OStringBuffer;
using rtl::OUString;
using rtl::OUStringBuffer;
using rtl::OUStringToOString;

namespace writerfilter {
namespace rtftok {

RTFSdrImport::RTFSdrImport(RTFDocumentImpl& rDocument,
        uno::Reference<lang::XComponent> const& xDstDoc)
    : m_rImport(rDocument)
{
    uno::Reference<drawing::XDrawPageSupplier> xDrawings(xDstDoc, uno::UNO_QUERY);
    if (xDrawings.is())
        m_xDrawPage.set(xDrawings->getDrawPage(), uno::UNO_QUERY);
}

RTFSdrImport::~RTFSdrImport()
{
}

void RTFSdrImport::createShape(OUString aStr, uno::Reference<drawing::XShape>& xShape, uno::Reference<beans::XPropertySet>& xPropertySet)
{
    if (m_rImport.getModelFactory().is())
        xShape.set(m_rImport.getModelFactory()->createInstance(aStr), uno::UNO_QUERY);
    xPropertySet.set(xShape, uno::UNO_QUERY);
}

void RTFSdrImport::resolve(RTFShape& rShape)
{
    int nType = -1;
    bool bPib = false;
    bool bCustom = false;

    uno::Reference<drawing::XShape> xShape;
    uno::Reference<beans::XPropertySet> xPropertySet;
    // Create this early, as custom shapes may have properties before the type arrives.
    createShape("com.sun.star.drawing.CustomShape", xShape, xPropertySet);
    uno::Any aAny;
    beans::PropertyValue aPropertyValue;
    awt::Rectangle aViewBox;
    std::vector<beans::PropertyValue> aPathPropVec;

    for (std::vector< std::pair<rtl::OUString, rtl::OUString> >::iterator i = rShape.aProperties.begin();
            i != rShape.aProperties.end(); ++i)
    {
        if ( i->first == "shapeType" )
        {
            nType = i->second.toInt32();
            switch (nType)
            {
                case 20: // Line
                    createShape("com.sun.star.drawing.LineShape", xShape, xPropertySet);
                    break;
                default:
                    bCustom = true;
                    break;
            }

            // Defaults
            aAny <<= (sal_uInt32)0xffffff; // White in Word, kind of blue in Writer.
            if (xPropertySet.is())
                xPropertySet->setPropertyValue("FillColor", aAny);
        }
        else if ( i->first == "wzName" )
        {
            RTFValue::Pointer_t pValue(new RTFValue(i->second));
            m_rImport.getState().aCharacterAttributes.set(NS_ooxml::LN_CT_NonVisualDrawingProps_name, pValue);
        }
        else if ( i->first == "wzDescription" )
        {
            RTFValue::Pointer_t pValue(new RTFValue(i->second));
            m_rImport.getState().aCharacterAttributes.set(NS_ooxml::LN_CT_NonVisualDrawingProps_descr, pValue);
        }
        else if ( i->first == "pib" )
        {
            m_rImport.setDestinationText(i->second);
            bPib = true;
        }
        else if (i->first == "fillColor" && xPropertySet.is())
        {
            aAny <<= msfilter::util::BGRToRGB(i->second.toInt32());
            xPropertySet->setPropertyValue("FillColor", aAny);
        }
        else if ( i->first == "fillBackColor" )
            ; // Ignore: complementer of fillColor
        else if (i->first == "lineColor" && xPropertySet.is())
        {
            aAny <<= msfilter::util::BGRToRGB(i->second.toInt32());
            xPropertySet->setPropertyValue("LineColor", aAny);
        }
        else if ( i->first == "lineBackColor" )
            ; // Ignore: complementer of lineColor
        else if (i->first == "txflTextFlow" && xPropertySet.is())
        {
            if (i->second.toInt32() == 1)
            {
                aAny <<= text::WritingMode_TB_RL;
                xPropertySet->setPropertyValue("TextWritingMode", aAny);
            }
        }
        else if (i->first == "fLine" && xPropertySet.is())
        {
            if (i->second.toInt32() == 0)
            {
                aAny <<= drawing::LineStyle_NONE;
                xPropertySet->setPropertyValue("LineStyle", aAny);
            }
        }
        else if (i->first == "fillOpacity" && xPropertySet.is())
        {
           int opacity = 100 - (i->second.toInt32())*100/65536;
           aAny <<= uno::makeAny(sal_uInt32(opacity));
           xPropertySet->setPropertyValue("FillTransparence", aAny);
        }
        else if (i->first == "rotation" && xPropertySet.is())
        {
            aAny <<= i->second.toInt32()*100/65536;
            xPropertySet->setPropertyValue("RotateAngle", aAny);
        }
        else if ( i->first == "pVerticies" )
        {
            uno::Sequence<drawing::EnhancedCustomShapeParameterPair> aCoordinates;
            sal_Int32 nSize = 0; // Size of a token (it's value is hardwired in the exporter)
            sal_Int32 nCount = 0; // Number of tokens
            sal_Int32 nCharIndex = 0; // Character index
            sal_Int32 nIndex = 0; // Array index
            do
            {
                OUString aToken = i->second.getToken(0, ';', nCharIndex);
                if (!nSize)
                    nSize = aToken.toInt32();
                else if (!nCount)
                {
                    nCount = aToken.toInt32();
                    aCoordinates.realloc(nCount);
                }
                else
                {
                    // The coordinates are in an (x,y) form.
                    aToken = aToken.copy(1, aToken.getLength() - 2);
                    sal_Int32 nI = 0;
                    sal_Int32 nX = 0;
                    sal_Int32 nY = 0;
                    do
                    {
                        OUString aPoint = aToken.getToken(0, ',', nI);
                        if (!nX)
                            nX = aPoint.toInt32();
                        else
                            nY = aPoint.toInt32();
                    }
                    while (nI >= 0);
                    aCoordinates[nIndex].First.Value <<= nX;
                    aCoordinates[nIndex].Second.Value <<= nY;
                    nIndex++;
                }
            }
            while (nCharIndex >= 0);
            aPropertyValue.Name = "Coordinates";
            aPropertyValue.Value <<= aCoordinates;
            aPathPropVec.push_back(aPropertyValue);
        }
        else if ( i->first == "pSegmentInfo" )
        {
            uno::Sequence<drawing::EnhancedCustomShapeSegment> aSegments;
            sal_Int32 nSize = 0;
            sal_Int32 nCount = 0;
            sal_Int32 nCharIndex = 0;
            sal_Int32 nIndex = 0;
            do
            {
                sal_Int32 nSeg = i->second.getToken(0, ';', nCharIndex).toInt32();
                if (!nSize)
                    nSize = nSeg;
                else if (!nCount)
                {
                    nCount = nSeg;
                    aSegments.realloc(nCount);
                }
                else
                {
                    switch (nSeg)
                    {
                        case 0x0001: // lineto
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
                            aSegments[nIndex].Count = sal_Int32(1);
                            break;
                        case 0x4000: // moveto
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
                            aSegments[nIndex].Count = sal_Int32(1);
                            break;
                        case 0x2001: // curveto
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::CURVETO;
                            aSegments[nIndex].Count = sal_Int32(1);
                            break;
                        case 0xb300: // arcto
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::ARCTO;
                            aSegments[nIndex].Count = sal_Int32(0);
                            break;
                        case 0xac00:
                        case 0xaa00: // nofill
                        case 0xab00: // nostroke
                        case 0x6001: // close
                            break;
                        case 0x8000: // end
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
                            aSegments[nIndex].Count = sal_Int32(0);
                            break;
                        default:
                            SAL_INFO("writerfilter", OSL_THIS_FUNC << ": unhandled segment '" << hex << nSeg << "' in the path");
                            break;
                    }
                    nIndex++;
                }
            }
            while (nCharIndex >= 0);
            aPropertyValue.Name = "Segments";
            aPropertyValue.Value <<= aSegments;
            aPathPropVec.push_back(aPropertyValue);
        }
        else if ( i->first == "geoLeft" )
            aViewBox.X = i->second.toInt32();
        else if ( i->first == "geoTop" )
            aViewBox.Y = i->second.toInt32();
        else if ( i->first == "geoRight" )
            aViewBox.Width = i->second.toInt32();
        else if ( i->first == "geoBottom" )
            aViewBox.Height = i->second.toInt32();
        else
            SAL_INFO("writerfilter", OSL_THIS_FUNC << ": TODO handle shape property '" <<
                    OUStringToOString( i->first, RTL_TEXTENCODING_UTF8 ).getStr() << "':'" <<
                    OUStringToOString( i->second, RTL_TEXTENCODING_UTF8 ).getStr() << "'");
    }

    if (nType == ESCHER_ShpInst_PictureFrame) // picture frame
    {
        if (bPib)
            m_rImport.resolvePict(false);
        return;
    }

    if (m_xDrawPage.is())
        m_xDrawPage->add(xShape);
    if (bCustom && xShape.is())
    {
        uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(xShape, uno::UNO_QUERY);
        xDefaulter->createCustomShapeDefaults(OUString::valueOf(sal_Int32(nType)));
    }

    // Creating Path property
    uno::Sequence<beans::PropertyValue> aPathPropSeq(aPathPropVec.size());
    beans::PropertyValue* pPathValues = aPathPropSeq.getArray();
    for (std::vector<beans::PropertyValue>::iterator i = aPathPropVec.begin(); i != aPathPropVec.end(); ++i)
        *pPathValues++ = *i;

    // Creating CustomShapeGeometry property
    std::vector<beans::PropertyValue> aGeomPropVec;
    if (aViewBox.X || aViewBox.Y || aViewBox.Width || aViewBox.Height)
    {
        aPropertyValue.Name = "ViewBox";
        aPropertyValue.Value <<= aViewBox;
        aGeomPropVec.push_back(aPropertyValue);
    }
    if (aPathPropSeq.getLength())
    {
        aPropertyValue.Name = "Path";
        aPropertyValue.Value <<= aPathPropSeq;
        aGeomPropVec.push_back(aPropertyValue);
    }
    uno::Sequence<beans::PropertyValue> aGeomPropSeq(aGeomPropVec.size());
    beans::PropertyValue* pGeomValues = aGeomPropSeq.getArray();
    for (std::vector<beans::PropertyValue>::iterator i = aGeomPropVec.begin(); i != aGeomPropVec.end(); ++i)
        *pGeomValues++ = *i;
    if (aGeomPropSeq.getLength() && xPropertySet.is())
        xPropertySet->setPropertyValue("CustomShapeGeometry", uno::Any(aGeomPropSeq));

    // Set position and size
    if (xShape.is())
    {
        xShape->setPosition(awt::Point(rShape.nLeft, rShape.nTop));
        xShape->setSize(awt::Size(rShape.nRight - rShape.nLeft, rShape.nBottom - rShape.nTop));
    }

    // Send it to dmapper
    m_rImport.Mapper().startShape(xShape);
    m_rImport.Mapper().startParagraphGroup();
    m_rImport.replayShapetext();
    m_rImport.Mapper().startCharacterGroup();
    m_rImport.runBreak();
    m_rImport.Mapper().endCharacterGroup();
    m_rImport.Mapper().endParagraphGroup();
    m_rImport.Mapper().endShape();
}

} // namespace rtftok
} // namespace writerfilter

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>implement shape lineWidth<commit_after>/*
 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
 *
 * The contents of this file are subject to the Mozilla Public 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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Initial Developer of the Original Code is
 *       Miklos Vajna <vmiklos@frugalware.org>
 * Portions created by the Initial Developer are Copyright (C) 2011 the
 * Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
 * instead of those above.
 */

#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
#include <com/sun/star/text/WritingMode.hpp>

#include <ooxml/resourceids.hxx> // NS_ooxml namespace
#include <filter/msfilter/escherex.hxx>
#include <filter/msfilter/util.hxx>

#include <rtfsdrimport.hxx>

using rtl::OString;
using rtl::OStringBuffer;
using rtl::OUString;
using rtl::OUStringBuffer;
using rtl::OUStringToOString;

namespace writerfilter {
namespace rtftok {

RTFSdrImport::RTFSdrImport(RTFDocumentImpl& rDocument,
        uno::Reference<lang::XComponent> const& xDstDoc)
    : m_rImport(rDocument)
{
    uno::Reference<drawing::XDrawPageSupplier> xDrawings(xDstDoc, uno::UNO_QUERY);
    if (xDrawings.is())
        m_xDrawPage.set(xDrawings->getDrawPage(), uno::UNO_QUERY);
}

RTFSdrImport::~RTFSdrImport()
{
}

void RTFSdrImport::createShape(OUString aStr, uno::Reference<drawing::XShape>& xShape, uno::Reference<beans::XPropertySet>& xPropertySet)
{
    if (m_rImport.getModelFactory().is())
        xShape.set(m_rImport.getModelFactory()->createInstance(aStr), uno::UNO_QUERY);
    xPropertySet.set(xShape, uno::UNO_QUERY);
}

void RTFSdrImport::resolve(RTFShape& rShape)
{
    int nType = -1;
    bool bPib = false;
    bool bCustom = false;

    uno::Reference<drawing::XShape> xShape;
    uno::Reference<beans::XPropertySet> xPropertySet;
    // Create this early, as custom shapes may have properties before the type arrives.
    createShape("com.sun.star.drawing.CustomShape", xShape, xPropertySet);
    uno::Any aAny;
    beans::PropertyValue aPropertyValue;
    awt::Rectangle aViewBox;
    std::vector<beans::PropertyValue> aPathPropVec;

    for (std::vector< std::pair<rtl::OUString, rtl::OUString> >::iterator i = rShape.aProperties.begin();
            i != rShape.aProperties.end(); ++i)
    {
        if ( i->first == "shapeType" )
        {
            nType = i->second.toInt32();
            switch (nType)
            {
                case 20: // Line
                    createShape("com.sun.star.drawing.LineShape", xShape, xPropertySet);
                    break;
                default:
                    bCustom = true;
                    break;
            }

            // Defaults
            aAny <<= (sal_uInt32)0xffffff; // White in Word, kind of blue in Writer.
            if (xPropertySet.is())
                xPropertySet->setPropertyValue("FillColor", aAny);
        }
        else if ( i->first == "wzName" )
        {
            RTFValue::Pointer_t pValue(new RTFValue(i->second));
            m_rImport.getState().aCharacterAttributes.set(NS_ooxml::LN_CT_NonVisualDrawingProps_name, pValue);
        }
        else if ( i->first == "wzDescription" )
        {
            RTFValue::Pointer_t pValue(new RTFValue(i->second));
            m_rImport.getState().aCharacterAttributes.set(NS_ooxml::LN_CT_NonVisualDrawingProps_descr, pValue);
        }
        else if ( i->first == "pib" )
        {
            m_rImport.setDestinationText(i->second);
            bPib = true;
        }
        else if (i->first == "fillColor" && xPropertySet.is())
        {
            aAny <<= msfilter::util::BGRToRGB(i->second.toInt32());
            xPropertySet->setPropertyValue("FillColor", aAny);
        }
        else if ( i->first == "fillBackColor" )
            ; // Ignore: complementer of fillColor
        else if (i->first == "lineColor" && xPropertySet.is())
        {
            aAny <<= msfilter::util::BGRToRGB(i->second.toInt32());
            xPropertySet->setPropertyValue("LineColor", aAny);
        }
        else if ( i->first == "lineBackColor" )
            ; // Ignore: complementer of lineColor
        else if (i->first == "txflTextFlow" && xPropertySet.is())
        {
            if (i->second.toInt32() == 1)
            {
                aAny <<= text::WritingMode_TB_RL;
                xPropertySet->setPropertyValue("TextWritingMode", aAny);
            }
        }
        else if (i->first == "fLine" && xPropertySet.is())
        {
            if (i->second.toInt32() == 0)
            {
                aAny <<= drawing::LineStyle_NONE;
                xPropertySet->setPropertyValue("LineStyle", aAny);
            }
        }
        else if (i->first == "fillOpacity" && xPropertySet.is())
        {
           int opacity = 100 - (i->second.toInt32())*100/65536;
           aAny <<= uno::makeAny(sal_uInt32(opacity));
           xPropertySet->setPropertyValue("FillTransparence", aAny);
        }
        else if (i->first == "rotation" && xPropertySet.is())
        {
            aAny <<= i->second.toInt32()*100/65536;
            xPropertySet->setPropertyValue("RotateAngle", aAny);
        }
        else if (i->first == "lineWidth" && xPropertySet.is())
        {

            aAny <<= i->second.toInt32()/360;
            xPropertySet->setPropertyValue("LineWidth", aAny);
        }
        else if ( i->first == "pVerticies" )
        {
            uno::Sequence<drawing::EnhancedCustomShapeParameterPair> aCoordinates;
            sal_Int32 nSize = 0; // Size of a token (it's value is hardwired in the exporter)
            sal_Int32 nCount = 0; // Number of tokens
            sal_Int32 nCharIndex = 0; // Character index
            sal_Int32 nIndex = 0; // Array index
            do
            {
                OUString aToken = i->second.getToken(0, ';', nCharIndex);
                if (!nSize)
                    nSize = aToken.toInt32();
                else if (!nCount)
                {
                    nCount = aToken.toInt32();
                    aCoordinates.realloc(nCount);
                }
                else
                {
                    // The coordinates are in an (x,y) form.
                    aToken = aToken.copy(1, aToken.getLength() - 2);
                    sal_Int32 nI = 0;
                    sal_Int32 nX = 0;
                    sal_Int32 nY = 0;
                    do
                    {
                        OUString aPoint = aToken.getToken(0, ',', nI);
                        if (!nX)
                            nX = aPoint.toInt32();
                        else
                            nY = aPoint.toInt32();
                    }
                    while (nI >= 0);
                    aCoordinates[nIndex].First.Value <<= nX;
                    aCoordinates[nIndex].Second.Value <<= nY;
                    nIndex++;
                }
            }
            while (nCharIndex >= 0);
            aPropertyValue.Name = "Coordinates";
            aPropertyValue.Value <<= aCoordinates;
            aPathPropVec.push_back(aPropertyValue);
        }
        else if ( i->first == "pSegmentInfo" )
        {
            uno::Sequence<drawing::EnhancedCustomShapeSegment> aSegments;
            sal_Int32 nSize = 0;
            sal_Int32 nCount = 0;
            sal_Int32 nCharIndex = 0;
            sal_Int32 nIndex = 0;
            do
            {
                sal_Int32 nSeg = i->second.getToken(0, ';', nCharIndex).toInt32();
                if (!nSize)
                    nSize = nSeg;
                else if (!nCount)
                {
                    nCount = nSeg;
                    aSegments.realloc(nCount);
                }
                else
                {
                    switch (nSeg)
                    {
                        case 0x0001: // lineto
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
                            aSegments[nIndex].Count = sal_Int32(1);
                            break;
                        case 0x4000: // moveto
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
                            aSegments[nIndex].Count = sal_Int32(1);
                            break;
                        case 0x2001: // curveto
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::CURVETO;
                            aSegments[nIndex].Count = sal_Int32(1);
                            break;
                        case 0xb300: // arcto
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::ARCTO;
                            aSegments[nIndex].Count = sal_Int32(0);
                            break;
                        case 0xac00:
                        case 0xaa00: // nofill
                        case 0xab00: // nostroke
                        case 0x6001: // close
                            break;
                        case 0x8000: // end
                            aSegments[nIndex].Command = drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
                            aSegments[nIndex].Count = sal_Int32(0);
                            break;
                        default:
                            SAL_INFO("writerfilter", OSL_THIS_FUNC << ": unhandled segment '" << hex << nSeg << "' in the path");
                            break;
                    }
                    nIndex++;
                }
            }
            while (nCharIndex >= 0);
            aPropertyValue.Name = "Segments";
            aPropertyValue.Value <<= aSegments;
            aPathPropVec.push_back(aPropertyValue);
        }
        else if ( i->first == "geoLeft" )
            aViewBox.X = i->second.toInt32();
        else if ( i->first == "geoTop" )
            aViewBox.Y = i->second.toInt32();
        else if ( i->first == "geoRight" )
            aViewBox.Width = i->second.toInt32();
        else if ( i->first == "geoBottom" )
            aViewBox.Height = i->second.toInt32();
        else
            SAL_INFO("writerfilter", OSL_THIS_FUNC << ": TODO handle shape property '" <<
                    OUStringToOString( i->first, RTL_TEXTENCODING_UTF8 ).getStr() << "':'" <<
                    OUStringToOString( i->second, RTL_TEXTENCODING_UTF8 ).getStr() << "'");
    }

    if (nType == ESCHER_ShpInst_PictureFrame) // picture frame
    {
        if (bPib)
            m_rImport.resolvePict(false);
        return;
    }

    if (m_xDrawPage.is())
        m_xDrawPage->add(xShape);
    if (bCustom && xShape.is())
    {
        uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(xShape, uno::UNO_QUERY);
        xDefaulter->createCustomShapeDefaults(OUString::valueOf(sal_Int32(nType)));
    }

    // Creating Path property
    uno::Sequence<beans::PropertyValue> aPathPropSeq(aPathPropVec.size());
    beans::PropertyValue* pPathValues = aPathPropSeq.getArray();
    for (std::vector<beans::PropertyValue>::iterator i = aPathPropVec.begin(); i != aPathPropVec.end(); ++i)
        *pPathValues++ = *i;

    // Creating CustomShapeGeometry property
    std::vector<beans::PropertyValue> aGeomPropVec;
    if (aViewBox.X || aViewBox.Y || aViewBox.Width || aViewBox.Height)
    {
        aPropertyValue.Name = "ViewBox";
        aPropertyValue.Value <<= aViewBox;
        aGeomPropVec.push_back(aPropertyValue);
    }
    if (aPathPropSeq.getLength())
    {
        aPropertyValue.Name = "Path";
        aPropertyValue.Value <<= aPathPropSeq;
        aGeomPropVec.push_back(aPropertyValue);
    }
    uno::Sequence<beans::PropertyValue> aGeomPropSeq(aGeomPropVec.size());
    beans::PropertyValue* pGeomValues = aGeomPropSeq.getArray();
    for (std::vector<beans::PropertyValue>::iterator i = aGeomPropVec.begin(); i != aGeomPropVec.end(); ++i)
        *pGeomValues++ = *i;
    if (aGeomPropSeq.getLength() && xPropertySet.is())
        xPropertySet->setPropertyValue("CustomShapeGeometry", uno::Any(aGeomPropSeq));

    // Set position and size
    if (xShape.is())
    {
        xShape->setPosition(awt::Point(rShape.nLeft, rShape.nTop));
        xShape->setSize(awt::Size(rShape.nRight - rShape.nLeft, rShape.nBottom - rShape.nTop));
    }

    // Send it to dmapper
    m_rImport.Mapper().startShape(xShape);
    m_rImport.Mapper().startParagraphGroup();
    m_rImport.replayShapetext();
    m_rImport.Mapper().startCharacterGroup();
    m_rImport.runBreak();
    m_rImport.Mapper().endCharacterGroup();
    m_rImport.Mapper().endParagraphGroup();
    m_rImport.Mapper().endShape();
}

} // namespace rtftok
} // namespace writerfilter

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "QuickKeysMenu.h"

/* common implementation headers */
#include "OpenGLTexFont.h"
#include "TextUtils.h"
#include "StateDatabase.h"

/* local implementation headers */
#include "MenuDefaultKey.h"
#include "MainMenu.h"

QuickKeysMenu::QuickKeysMenu()
{
  // add controls
  std::vector<HUDuiControl*>& controls = getControls();

  controls.push_back(createLabel("Define Quick Keys"));
  controls.push_back(createLabel("Notice: depending on platform not all keys might work"));

  controls.push_back(createLabel("Send to All"));
  controls.push_back(createLabel("Send to Team"));

  firstKeyControl = controls.size();

  int i;
  for (i=1; i < 11; i++) {
    std::string keyLabel = string_util::format("Alt-F%d", i);
    controls.push_back(createInput(keyLabel));
  }

  for (i=1; i < 11; i++) {
    std::string keyLabel = string_util::format("Ctrl-F%d", i);
    controls.push_back(createInput(keyLabel));
  }

  initNavigation(controls, firstKeyControl, controls.size()-1);
}

QuickKeysMenu::~QuickKeysMenu()
{
}

HUDuiDefaultKey* QuickKeysMenu::getDefaultKey()
{
  return MenuDefaultKey::getInstance();
}

void QuickKeysMenu::show()
{
  std::vector<HUDuiControl*>& controls = getControls();

  int i;
  for (i=1; i < 11; i++) {
    HUDuiTypeIn *entry = static_cast<HUDuiTypeIn*>(controls[firstKeyControl + i - 1]);
    std::string keyName = string_util::format("quickMessage%d", i);
    std::string keyValue = BZDB.get(keyName);
    entry->setString(keyValue);
  }

  for (i=1; i < 11; i++) {
    HUDuiTypeIn *entry = static_cast<HUDuiTypeIn*>(controls[firstKeyControl + i + 9]);
    std::string keyName = string_util::format("quickTeamMessage%d", i);
    std::string keyValue = BZDB.get(keyName);
    entry->setString(keyValue);
  }
}

void QuickKeysMenu::dismiss()
{
  std::vector<HUDuiControl*>& controls = getControls();

  int i;
  for (i=1; i < 11; i++) {
    HUDuiTypeIn *entry = static_cast<HUDuiTypeIn*>(controls[firstKeyControl + i - 1]);
    std::string keyValue = entry->getString();
    std::string keyName = string_util::format("quickMessage%d", i);
    if (keyValue.empty() && BZDB.isSet(keyName))
      BZDB.unset(keyName);
    else if (!keyValue.empty())
      BZDB.set(keyName, keyValue);
  }

  for (i=1; i < 11; i++) {
    HUDuiTypeIn *entry = static_cast<HUDuiTypeIn*>(controls[firstKeyControl + i + 9]);
    std::string keyValue = entry->getString();
    std::string keyName = string_util::format("quickTeamMessage%d", i);
    if (keyValue.empty() && BZDB.isSet(keyName))
      BZDB.unset(keyName);
    else if (!keyValue.empty())
      BZDB.set(keyName, keyValue);
  }
}

void QuickKeysMenu::resize(int width, int height)
{
  HUDDialog::resize(width, height);

  int i;
  // use a big font for title, smaller font for the rest
  const float titleFontWidth = (float)height / 10.0f;
  const float titleFontHeight = (float)height / 10.0f;
  const float bigFontWidth = (float)height / 28.0f;
  const float bigFontHeight = (float)height / 28.0f;

  const float fontWidth = (float)height / 32.0f;
  const float fontHeight = (float)height / 32.0f;

  // reposition title
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontWidth, titleFontHeight);
  const OpenGLTexFont& titleFont = title->getFont();
  const float titleWidth = titleFont.getWidth(title->getString());
  float x = 0.5f * ((float)width - titleWidth);
  float y = (float)height - titleFont.getHeight();
  title->setPosition(x, y);

  // reposition help
  HUDuiLabel*help = (HUDuiLabel*)list[1];
  help->setFontSize( bigFontWidth, bigFontHeight);
  const OpenGLTexFont& helpFont = help->getFont();
  const float helpWidth = helpFont.getWidth(help->getString());
  x = 0.5f * ((float)width - helpWidth);
  y -= 1.1f * helpFont.getHeight();
  help->setPosition(x, y);

  // reposition column titles
  HUDuiLabel *all = (HUDuiLabel*)list[2];
  all->setFontSize(bigFontWidth, bigFontHeight);
  x = 0.1f * width;
  y -= 1.5f * helpFont.getHeight();
  all->setPosition(x, y);
  HUDuiLabel *team = (HUDuiLabel*)list[3];
  team->setFontSize(bigFontWidth, bigFontHeight);
  x = 0.6f * width;
  team->setPosition(x, y);

  // reposition options in two columns
  x = 0.10f * (float)width;
  const float topY = y - (0.6f * titleFont.getHeight());
  y = topY;
  list[4]->setFontSize(fontWidth, fontHeight);
  const float h = list[4]->getFont().getHeight();
  const int count = list.size() - firstKeyControl;
  const int mid = (count / 2) + firstKeyControl;

  for (i = firstKeyControl; i < mid; i++) {
    list[i]->setFontSize(fontWidth, fontHeight);
    list[i]->setPosition(x, y);
    y -= 1.0f * h;
  }

  x = 0.60f * (float)width;
  y = topY;
  for (;i < count + firstKeyControl; i++) {
    list[i]->setFontSize(fontWidth, fontHeight);
    list[i]->setPosition(x, y);
    y -= 1.0f * h;
  }
}

HUDuiLabel* QuickKeysMenu::createLabel(const std::string &str)
{
  HUDuiLabel* label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setString(str);
  return label;
}

HUDuiTypeIn* QuickKeysMenu::createInput(const std::string &label)
{
  HUDuiTypeIn* entry = new HUDuiTypeIn;
  entry->setFont(MainMenu::getFont());
  entry->setLabel(label);
  entry->setMaxLength(40); // some strings >20 won't already fit into column
  return entry;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>quell the vc warnings<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"
/* interface header */
#include "QuickKeysMenu.h"

/* common implementation headers */
#include "OpenGLTexFont.h"
#include "TextUtils.h"
#include "StateDatabase.h"

/* local implementation headers */
#include "MenuDefaultKey.h"
#include "MainMenu.h"

QuickKeysMenu::QuickKeysMenu()
{
  // add controls
  std::vector<HUDuiControl*>& controls = getControls();

  controls.push_back(createLabel("Define Quick Keys"));
  controls.push_back(createLabel("Notice: depending on platform not all keys might work"));

  controls.push_back(createLabel("Send to All"));
  controls.push_back(createLabel("Send to Team"));

  firstKeyControl = controls.size();

  int i;
  for (i=1; i < 11; i++) {
    std::string keyLabel = string_util::format("Alt-F%d", i);
    controls.push_back(createInput(keyLabel));
  }

  for (i=1; i < 11; i++) {
    std::string keyLabel = string_util::format("Ctrl-F%d", i);
    controls.push_back(createInput(keyLabel));
  }

  initNavigation(controls, firstKeyControl, controls.size()-1);
}

QuickKeysMenu::~QuickKeysMenu()
{
}

HUDuiDefaultKey* QuickKeysMenu::getDefaultKey()
{
  return MenuDefaultKey::getInstance();
}

void QuickKeysMenu::show()
{
  std::vector<HUDuiControl*>& controls = getControls();

  int i;
  for (i=1; i < 11; i++) {
    HUDuiTypeIn *entry = static_cast<HUDuiTypeIn*>(controls[firstKeyControl + i - 1]);
    std::string keyName = string_util::format("quickMessage%d", i);
    std::string keyValue = BZDB.get(keyName);
    entry->setString(keyValue);
  }

  for (i=1; i < 11; i++) {
    HUDuiTypeIn *entry = static_cast<HUDuiTypeIn*>(controls[firstKeyControl + i + 9]);
    std::string keyName = string_util::format("quickTeamMessage%d", i);
    std::string keyValue = BZDB.get(keyName);
    entry->setString(keyValue);
  }
}

void QuickKeysMenu::dismiss()
{
  std::vector<HUDuiControl*>& controls = getControls();

  int i;
  for (i=1; i < 11; i++) {
    HUDuiTypeIn *entry = static_cast<HUDuiTypeIn*>(controls[firstKeyControl + i - 1]);
    std::string keyValue = entry->getString();
    std::string keyName = string_util::format("quickMessage%d", i);
    if (keyValue.empty() && BZDB.isSet(keyName))
      BZDB.unset(keyName);
    else if (!keyValue.empty())
      BZDB.set(keyName, keyValue);
  }

  for (i=1; i < 11; i++) {
    HUDuiTypeIn *entry = static_cast<HUDuiTypeIn*>(controls[firstKeyControl + i + 9]);
    std::string keyValue = entry->getString();
    std::string keyName = string_util::format("quickTeamMessage%d", i);
    if (keyValue.empty() && BZDB.isSet(keyName))
      BZDB.unset(keyName);
    else if (!keyValue.empty())
      BZDB.set(keyName, keyValue);
  }
}

void QuickKeysMenu::resize(int width, int height)
{
  HUDDialog::resize(width, height);

  int i;
  // use a big font for title, smaller font for the rest
  const float titleFontWidth = (float)height / 10.0f;
  const float titleFontHeight = (float)height / 10.0f;
  const float bigFontWidth = (float)height / 28.0f;
  const float bigFontHeight = (float)height / 28.0f;

  const float fontWidth = (float)height / 32.0f;
  const float fontHeight = (float)height / 32.0f;

  // reposition title
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontWidth, titleFontHeight);
  const OpenGLTexFont& titleFont = title->getFont();
  const float titleWidth = titleFont.getWidth(title->getString());
  float x = 0.5f * ((float)width - titleWidth);
  float y = (float)height - titleFont.getHeight();
  title->setPosition(x, y);

  // reposition help
  HUDuiLabel*help = (HUDuiLabel*)list[1];
  help->setFontSize( bigFontWidth, bigFontHeight);
  const OpenGLTexFont& helpFont = help->getFont();
  const float helpWidth = helpFont.getWidth(help->getString());
  x = 0.5f * ((float)width - helpWidth);
  y -= 1.1f * helpFont.getHeight();
  help->setPosition(x, y);

  // reposition column titles
  HUDuiLabel *all = (HUDuiLabel*)list[2];
  all->setFontSize(bigFontWidth, bigFontHeight);
  x = 0.1f * width;
  y -= 1.5f * helpFont.getHeight();
  all->setPosition(x, y);
  HUDuiLabel *team = (HUDuiLabel*)list[3];
  team->setFontSize(bigFontWidth, bigFontHeight);
  x = 0.6f * width;
  team->setPosition(x, y);

  // reposition options in two columns
  x = 0.10f * (float)width;
  const float topY = y - (0.6f * titleFont.getHeight());
  y = topY;
  list[4]->setFontSize(fontWidth, fontHeight);
  const float h = list[4]->getFont().getHeight();
  const int count = list.size() - firstKeyControl;
  const int mid = (count / 2) + firstKeyControl;

  for (i = firstKeyControl; i < mid; i++) {
    list[i]->setFontSize(fontWidth, fontHeight);
    list[i]->setPosition(x, y);
    y -= 1.0f * h;
  }

  x = 0.60f * (float)width;
  y = topY;
  for (;i < count + firstKeyControl; i++) {
    list[i]->setFontSize(fontWidth, fontHeight);
    list[i]->setPosition(x, y);
    y -= 1.0f * h;
  }
}

HUDuiLabel* QuickKeysMenu::createLabel(const std::string &str)
{
  HUDuiLabel* label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setString(str);
  return label;
}

HUDuiTypeIn* QuickKeysMenu::createInput(const std::string &label)
{
  HUDuiTypeIn* entry = new HUDuiTypeIn;
  entry->setFont(MainMenu::getFont());
  entry->setLabel(label);
  entry->setMaxLength(40); // some strings >20 won't already fit into column
  return entry;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include "vendor/SPIRV-Cross/spirv_hlsl.hpp"
#include "wrapper.hpp"

#define INTERNAL_RESULT(block)              \
    try                                     \
    {                                       \
        {                                   \
            block                           \
        }                                   \
        return ScInternalResult::Success;   \
    }                                       \
    catch (const std::exception &ex)        \
    {                                       \
        return ScInternalResult::Unhandled; \
    }                                       \
    catch (...)                             \
    {                                       \
        return ScInternalResult::Unhandled; \
    }                                       \
    return ScInternalResult::Unhandled;

extern "C" {
ScInternalResult sc_internal_compiler_hlsl_new(ScInternalCompilerHlsl **compiler, const uint32_t *ir, size_t size)
{
    INTERNAL_RESULT(
            *compiler = new spirv_cross::CompilerHLSL(ir, size);)
}
ScInternalResult sc_internal_compiler_hlsl_delete(ScInternalCompilerHlsl *compiler)
{
    INTERNAL_RESULT(
        delete compiler;)
}
ScInternalResult sc_internal_compiler_hlsl_compile(const ScInternalCompilerHlsl *c, char **hlsl)
{
    INTERNAL_RESULT(*hlsl = strdup(((spirv_cross::CompilerHLSL *)c)->compile().c_str());)
}
ScInternalResult sc_internal_deallocate_string(char *str)
{
    INTERNAL_RESULT(free(str);)
}
}
<commit_msg>Add missing cast<commit_after>#include "vendor/SPIRV-Cross/spirv_hlsl.hpp"
#include "wrapper.hpp"

#define INTERNAL_RESULT(block)              \
    try                                     \
    {                                       \
        {                                   \
            block                           \
        }                                   \
        return ScInternalResult::Success;   \
    }                                       \
    catch (const std::exception &ex)        \
    {                                       \
        return ScInternalResult::Unhandled; \
    }                                       \
    catch (...)                             \
    {                                       \
        return ScInternalResult::Unhandled; \
    }                                       \
    return ScInternalResult::Unhandled;

extern "C" {
ScInternalResult sc_internal_compiler_hlsl_new(ScInternalCompilerHlsl **compiler, const uint32_t *ir, size_t size)
{
    INTERNAL_RESULT(
            *compiler = new spirv_cross::CompilerHLSL(ir, size);)
}
ScInternalResult sc_internal_compiler_hlsl_delete(ScInternalCompilerHlsl *compiler)
{
    INTERNAL_RESULT(
        delete (spirv_cross::CompilerHLSL *)compiler;)
}
ScInternalResult sc_internal_compiler_hlsl_compile(const ScInternalCompilerHlsl *compiler, char **hlsl)
{
    INTERNAL_RESULT(*hlsl = strdup(((spirv_cross::CompilerHLSL *)compiler)->compile().c_str());)
}
ScInternalResult sc_internal_deallocate_string(char *str)
{
    INTERNAL_RESULT(free(str);)
}
}
<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <set>
#include <string>
#include <tuple>
#include <utility>

namespace ContainerPrinter
{
   namespace Traits
   {
      /**
      * @brief A neat SFINAE trick.
      *
      * @see N3911
      */
      template<class...>
      using void_t = void;

      /**
      * @brief Base case for the testing of STD compatible container types.
      */
      template<
         typename /*Type*/,
         typename = void
      >
      struct is_printable_as_container : public std::false_type
      {
      };

      /**
      * @brief Specialization to ensure that Standard Library compatible containers that have
      * `begin()`, `end()`, and `empty()` member functions are treated as printable containers.
      */
      template<typename Type>
      struct is_printable_as_container<
         Type,
         void_t<
            decltype(std::declval<Type&>().begin()),
            decltype(std::declval<Type&>().end()),
            decltype(std::declval<Type&>().empty())
         >
      > : public std::true_type
      {
      };

      /**
      * @brief Specialization to treat std::pair<...> as a printable container type.
      */
      template<
         typename FirstType,
         typename SecondType
      >
      struct is_printable_as_container<std::pair<FirstType, SecondType>> : public std::true_type
      {
      };

      /**
      * @brief Specialization to treat std::tuple<...> as a printable container type.
      */
      template<typename... Args>
      struct is_printable_as_container<std::tuple<Args...>> : public std::true_type
      {
      };

      /**
      * @brief Specialization to treat arrays as printable container types.
      */
      template<
         typename ArrayType,
         std::size_t ArraySize
      >
      struct is_printable_as_container<ArrayType[ArraySize]> : public std::true_type
      {
      };

      /**
      * @brief Narrow character array specialization in order to ensure that we print character
      * arrays as string and not as delimiter containers.
      */
      template<std::size_t ArraySize>
      struct is_printable_as_container<char[ArraySize]> : public std::false_type
      {
      };

      /**
      * @brief Wide character array specialization in order to ensure that we print character arrays
      * as string and not as delimiter containers.
      */
      template<std::size_t ArraySize>
      struct is_printable_as_container<wchar_t[ArraySize]> : public std::false_type
      {
      };

      /**
      * @brief String specialization in order to ensure that we treat strings as nothing more than
      * strings.
      */
      template<
         typename CharacterType,
         typename CharacterTraitsType,
         typename AllocatorType
      >
      struct is_printable_as_container<
         std::basic_string<
            CharacterType,
            CharacterTraitsType,
            AllocatorType
         >
      > : public std::false_type
      {
      };

      /**
      * @brief Helper variable template.
      */
      template<typename Type>
      constexpr bool is_printable_as_container_v = is_printable_as_container<Type>::value;
   }

   namespace Decorator
   {
      /**
      * @brief Struct to neatly wrap up all the additional characters we'll need in order to
      * print out the containers.
      */
      template<typename CharacterType>
      struct wrapper
      {
         using type = CharacterType;

         const type* prefix;
         const type* separator;
         const type* suffix;
      };

      /**
      * @brief Additional wrapper around the `delimiter_values` struct for added convenience.
      */
      template<
         typename /*ContainerType*/,
         typename CharacterType
      >
      struct delimiters
      {
         using type = wrapper<CharacterType>;

         static const type values;
      };

      /**
      * @brief Default narrow delimiters for any container type that isn't specialized.
      */
      template<typename ContainerType>
      struct delimiters<ContainerType, char>
      {
         using type = wrapper<char>;

         static constexpr type values = { "[", ", ", "]" };
      };

      /**
      * @brief Default wide delimiters for any container type that isn't specialized.
      */
      template<typename ContainerType>
      struct delimiters<ContainerType, wchar_t>
      {
         using type = wrapper<wchar_t>;

         static constexpr type values = { L"[", L", ", L"]" };
      };

      /**
      * @brief Narrow character specialization for std::set<...>.
      */
      template<
         typename DataType,
         typename ComparatorType,
         typename AllocatorType
      >
      struct delimiters<std::set<DataType, ComparatorType, AllocatorType>, char>
      {
         static constexpr wrapper<char> values = { "{", ", ", "}" };
      };

      /**
      * @brief Wide character specialization for std::set<...>.
      */
      template<
         typename DataType,
         typename ComparatorType,
         typename AllocatorType
      >
      struct delimiters<std::set<DataType, ComparatorType, AllocatorType>, wchar_t>
      {
         static constexpr wrapper<wchar_t> values = { L"{", L", ", L"}" };
      };

      /**
      * @brief Narrow character specialization for std::multiset<...>.
      */
      template<
         typename DataType,
         typename ComparatorType,
         typename AllocatorType
      >
      struct delimiters<std::multiset<DataType, ComparatorType, AllocatorType>, char>
      {
         static constexpr wrapper<char> values = { "{", ", ", "}" };
      };

      /**
      * @brief Wide character specialization for std::multiset<...>.
      */
      template<
         typename DataType,
         typename ComparatorType,
         typename AllocatorType
      >
      struct delimiters<std::multiset<DataType, ComparatorType, AllocatorType>, wchar_t>
      {
         static constexpr wrapper<wchar_t> values = { L"{", L", ", L"}" };
      };

      /**
      * @brief Narrow character specialization for std::pair<...>.
      */
      template<
         typename FirstType,
         typename SecondType
      >
      struct delimiters<std::pair<FirstType, SecondType>, char>
      {
         static constexpr wrapper<char> values = { "(", ", ", ")" };
      };

      /**
      * @brief Wide character specialization for std::pair<...>.
      */
      template<
         typename FirstType,
         typename SecondType
      >
      struct delimiters<std::pair<FirstType, SecondType>, wchar_t>
      {
         static constexpr wrapper<wchar_t> values = { L"(", L", ", L")" };
      };

      /**
      * @brief Narrow character specialization for std::tuple<...>.
      */
      template<typename... DataType>
      struct delimiters<std::tuple<DataType...>, char>
      {
         static constexpr wrapper<char> values = { "<", ", ", ">" };
      };

      /**
      * @brief Wide character specialization for std::tuple<...>.
      */
      template<typename... DataType>
      struct delimiters<std::tuple<DataType...>, wchar_t>
      {
         static constexpr wrapper<wchar_t> values = { L"<", L", ", L">" };
      };
   }

   /**
   * @brief Default container formatter that will be used to print prefix, element, separator, and
   * suffix strings to an output stream.
   */
   template<
      typename ContainerType,
      typename StreamType
   >
   struct default_formatter
   {
      static constexpr auto decorators =
         ContainerPrinter::Decorator::delimiters<ContainerType, StreamType::char_type>::values;

      static void print_prefix(StreamType& stream) noexcept
      {
         stream << decorators.prefix;
      }

      template<typename ElementType>
      static void print_element(
         StreamType& stream,
         const ElementType& element) noexcept
      {
         stream << element;
      }

      static void print_delimiter(StreamType& stream) noexcept
      {
         stream << decorators.separator;
      }

      static void print_suffix(StreamType& stream) noexcept
      {
         stream << decorators.suffix;
      }
   };

   /**
   * @brief Helper function to determine if a container is empty.
   */
   template<typename ContainerType>
   inline bool is_empty(const ContainerType& container) noexcept
   {
      return container.empty();
   };

   /**
   * @brief Helper function to test arrays for emptiness.
   */
   template<
      typename ArrayType,
      std::size_t ArraySize
   >
   constexpr bool is_empty(const ArrayType(&)[ArraySize]) noexcept
   {
      return !static_cast<bool>(ArraySize);
   }

   /**
   * @brief Recursive tuple handler struct meant to unpack and print std::tuple<...> elements.
   */
   template<
      typename TupleType,
      std::size_t Index,
      std::size_t Last
   >
   struct tuple_handler
   {
      template<
         typename StreamType,
         typename FormatterType
      >
      inline static void print(
         StreamType& stream,
         const TupleType& container,
         FormatterType& formatter)
      {
         stream << std::get<Index>(container);
         formatter.print_delimiter(stream);
         tuple_handler<TupleType, Index + 1, Last>::print(stream, container, formatter);
      }
   };

   /**
   * @brief Specialization of tuple handler to handle empty std::tuple<...> objects.
   *
   * @note The use of "-1" as the ending index here is a bit of a hack. Since std::size_t is, by
   * definition, unsigned, this will evaluate to std::numeric_limits<std::size_t>::max().
   */
   template<typename TupleType>
   struct tuple_handler<TupleType, 0, -1>
   {
      template<
         typename StreamType,
         typename FormatterType
      >
      inline static void print(
         StreamType& /*stream*/,
         const TupleType& /*tuple*/,
         FormatterType& /*formatter*/) noexcept
      {
      };
   };

   /**
   * @brief Specialization of tuple handler for handle the last element in the std::tuple<...>
   * object.
   */
   template<
      typename TupleType,
      std::size_t Index
   >
   struct tuple_handler<TupleType, Index, Index>
   {
      template<
         typename StreamType,
         typename FormatterType
      >
      inline static void print(
         StreamType& stream,
         const TupleType& tuple,
         FormatterType& /*formatter*/) noexcept
      {
         stream << std::get<Index>(tuple);
      }
   };

   /**
   * @brief Overload meant to handle std::tuple<...> objects.
   *
   * @todo Look into using fold expressions once C++17 arrives.
   */
   template<
      typename StreamType,
      typename FormatterType,
      typename... TupleArgs
   >
   static StreamType& ToStream(
      StreamType& stream,
      const std::tuple<TupleArgs...>& container,
      FormatterType& formatter)
   {
      using ContainerType = std::decay_t<decltype(container)>;

      formatter.print_prefix(stream);
      tuple_handler<ContainerType, 0, sizeof...(TupleArgs) - 1>::print(stream, container, formatter);
      formatter.print_suffix(stream);

      return stream;
   }

   /**
   * @brief Overload meant to handle std::pair<...> objects.
   */
   template<
      typename FirstType,
      typename SecondType,
      typename StreamType,
      typename FormatterType
   >
   static StreamType& ToStream(
      StreamType& stream,
      const std::pair<FirstType, SecondType>& container,
      FormatterType& formatter)
   {
      formatter.print_prefix(stream);
      formatter.print_element(stream, container.first);
      formatter.print_delimiter(stream);
      formatter.print_element(stream, container.second);
      formatter.print_suffix(stream);

      return stream;
   }

   /**
   * @brief Overload meant to handle containers that support the notion of "emptiness".
   */
   template<
      typename ContainerType,
      typename StreamType,
      typename FormatterType
   >
   static StreamType& ToStream(
      StreamType& stream,
      const ContainerType& container,
      FormatterType& formatter)
   {
      formatter.print_prefix(stream);

      if (is_empty(container))
      {
         formatter.print_suffix(stream);

         return stream;
      }

      auto begin = std::begin(container);
      formatter.print_element(stream, *begin);

      std::advance(begin, 1);

      std::for_each(begin, std::end(container),
         [&stream, &formatter](const auto& element)
      {
         formatter.print_delimiter(stream);
         formatter.print_element(stream, element);
      });

      formatter.print_suffix(stream);

      return stream;
   }
}

/**
* @brief Overload of the stream output operator for compatible containers.
*/
template<
   typename ContainerType,
   typename StreamType,
   typename = std::enable_if_t<ContainerPrinter::Traits::is_printable_as_container_v<ContainerType>>
>
auto& operator<<(
   StreamType& stream,
   const ContainerType& container)
{
   using FormatterType = ContainerPrinter::default_formatter<ContainerType, StreamType>;
   ContainerPrinter::ToStream(stream, container, FormatterType{ });

   return stream;
}
<commit_msg>Documentation Cleanup<commit_after>#pragma once

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <set>
#include <string>
#include <tuple>
#include <utility>

namespace ContainerPrinter
{
   namespace Traits
   {
      /**
      * @brief A neat SFINAE trick.
      *
      * @see N3911
      */
      template<class...>
      using void_t = void;

      /**
      * @brief Base case for the testing of STD compatible container types.
      */
      template<
         typename /*Type*/,
         typename = void
      >
      struct is_printable_as_container : public std::false_type
      {
      };

      /**
      * @brief Specialization to ensure that Standard Library compatible containers that have
      * `begin()`, `end()`, and `empty()` member functions are treated as printable containers.
      */
      template<typename Type>
      struct is_printable_as_container<
         Type,
         void_t<
            decltype(std::declval<Type&>().begin()),
            decltype(std::declval<Type&>().end()),
            decltype(std::declval<Type&>().empty()),
            decltype(std::declval<Type&>()::iterator)
         >
      > : public std::true_type
      {
      };

      /**
      * @brief Specialization to treat std::pair<...> as a printable container type.
      */
      template<
         typename FirstType,
         typename SecondType
      >
      struct is_printable_as_container<std::pair<FirstType, SecondType>> : public std::true_type
      {
      };

      /**
      * @brief Specialization to treat std::tuple<...> as a printable container type.
      */
      template<typename... Args>
      struct is_printable_as_container<std::tuple<Args...>> : public std::true_type
      {
      };

      /**
      * @brief Specialization to treat arrays as printable container types.
      */
      template<
         typename ArrayType,
         std::size_t ArraySize
      >
      struct is_printable_as_container<ArrayType[ArraySize]> : public std::true_type
      {
      };

      /**
      * @brief Narrow character array specialization meant to ensure that we print character arrays
      * as strings and not as delimiter containers of individual characters.
      */
      template<std::size_t ArraySize>
      struct is_printable_as_container<char[ArraySize]> : public std::false_type
      {
      };

      /**
      * @brief Wide character array specialization meant to ensure that we print character arrays
      * as strings and not as delimiter containers of individual characters.
      */
      template<std::size_t ArraySize>
      struct is_printable_as_container<wchar_t[ArraySize]> : public std::false_type
      {
      };

      /**
      * @brief String specialization meant to ensure that we treat strings as nothing more than
      * strings.
      */
      template<
         typename CharacterType,
         typename CharacterTraitsType,
         typename AllocatorType
      >
      struct is_printable_as_container<
         std::basic_string<
            CharacterType,
            CharacterTraitsType,
            AllocatorType
         >
      > : public std::false_type
      {
      };

      /**
      * @brief Helper variable template.
      */
      template<typename Type>
      constexpr bool is_printable_as_container_v = is_printable_as_container<Type>::value;
   }

   namespace Decorator
   {
      /**
      * @brief Struct to neatly wrap up all the additional characters we'll need in order to
      * print out the containers.
      */
      template<typename CharacterType>
      struct wrapper
      {
         using type = CharacterType;

         const type* prefix;
         const type* separator;
         const type* suffix;
      };

      /**
      * @brief Base definition for the delimiters. This probably won't ever get invoked.
      */
      template<
         typename /*ContainerType*/,
         typename CharacterType
      >
      struct delimiters
      {
         using type = wrapper<CharacterType>;

         static const type values;
      };

      /**
      * @brief Default narrow character specialization for any container type that isn't even
      * more specialized.
      */
      template<typename ContainerType>
      struct delimiters<ContainerType, char>
      {
         using type = wrapper<char>;

         static constexpr type values = { "[", ", ", "]" };
      };

      /**
      * @brief Default wide character specialization for any container type that isn't even
      * more specialized.
      */
      template<typename ContainerType>
      struct delimiters<ContainerType, wchar_t>
      {
         using type = wrapper<wchar_t>;

         static constexpr type values = { L"[", L", ", L"]" };
      };

      /**
      * @brief Narrow character specialization for std::set<...> instances.
      */
      template<
         typename DataType,
         typename ComparatorType,
         typename AllocatorType
      >
      struct delimiters<std::set<DataType, ComparatorType, AllocatorType>, char>
      {
         static constexpr wrapper<char> values = { "{", ", ", "}" };
      };

      /**
      * @brief Wide character specialization for std::set<...> instances.
      */
      template<
         typename DataType,
         typename ComparatorType,
         typename AllocatorType
      >
      struct delimiters<std::set<DataType, ComparatorType, AllocatorType>, wchar_t>
      {
         static constexpr wrapper<wchar_t> values = { L"{", L", ", L"}" };
      };

      /**
      * @brief Narrow character specialization for std::multiset<...> instances.
      */
      template<
         typename DataType,
         typename ComparatorType,
         typename AllocatorType
      >
      struct delimiters<std::multiset<DataType, ComparatorType, AllocatorType>, char>
      {
         static constexpr wrapper<char> values = { "{", ", ", "}" };
      };

      /**
      * @brief Wide character specialization for std::multiset<...> instances.
      */
      template<
         typename DataType,
         typename ComparatorType,
         typename AllocatorType
      >
      struct delimiters<std::multiset<DataType, ComparatorType, AllocatorType>, wchar_t>
      {
         static constexpr wrapper<wchar_t> values = { L"{", L", ", L"}" };
      };

      /**
      * @brief Narrow character specialization for std::pair<...> instances.
      */
      template<
         typename FirstType,
         typename SecondType
      >
      struct delimiters<std::pair<FirstType, SecondType>, char>
      {
         static constexpr wrapper<char> values = { "(", ", ", ")" };
      };

      /**
      * @brief Wide character specialization for std::pair<...> instances.
      */
      template<
         typename FirstType,
         typename SecondType
      >
      struct delimiters<std::pair<FirstType, SecondType>, wchar_t>
      {
         static constexpr wrapper<wchar_t> values = { L"(", L", ", L")" };
      };

      /**
      * @brief Narrow character specialization for std::tuple<...> instances.
      */
      template<typename... DataType>
      struct delimiters<std::tuple<DataType...>, char>
      {
         static constexpr wrapper<char> values = { "<", ", ", ">" };
      };

      /**
      * @brief Wide character specialization for std::tuple<...> instances.
      */
      template<typename... DataType>
      struct delimiters<std::tuple<DataType...>, wchar_t>
      {
         static constexpr wrapper<wchar_t> values = { L"<", L", ", L">" };
      };
   }

   /**
   * @brief Default container formatter that will be used to print prefix, element, separator, and
   * suffix strings to an output stream.
   */
   template<
      typename ContainerType,
      typename StreamType
   >
   struct default_formatter
   {
      static constexpr auto decorators =
         ContainerPrinter::Decorator::delimiters<ContainerType, StreamType::char_type>::values;

      static void print_prefix(StreamType& stream) noexcept
      {
         stream << decorators.prefix;
      }

      template<typename ElementType>
      static void print_element(
         StreamType& stream,
         const ElementType& element) noexcept
      {
         stream << element;
      }

      static void print_delimiter(StreamType& stream) noexcept
      {
         stream << decorators.separator;
      }

      static void print_suffix(StreamType& stream) noexcept
      {
         stream << decorators.suffix;
      }
   };

   /**
   * @brief Helper function to determine if a container is empty.
   */
   template<typename ContainerType>
   inline bool is_empty(const ContainerType& container) noexcept
   {
      return container.empty();
   };

   /**
   * @brief Helper function to test arrays for emptiness.
   */
   template<
      typename ArrayType,
      std::size_t ArraySize
   >
   constexpr bool is_empty(const ArrayType(&)[ArraySize]) noexcept
   {
      return !static_cast<bool>(ArraySize);
   }

   /**
   * @brief Recursive tuple handler struct meant to unpack and print std::tuple<...> elements.
   */
   template<
      typename TupleType,
      std::size_t Index,
      std::size_t Last
   >
   struct tuple_handler
   {
      template<
         typename StreamType,
         typename FormatterType
      >
      inline static void print(
         StreamType& stream,
         const TupleType& container,
         FormatterType& formatter)
      {
         stream << std::get<Index>(container);
         formatter.print_delimiter(stream);
         tuple_handler<TupleType, Index + 1, Last>::print(stream, container, formatter);
      }
   };

   /**
   * @brief Specialization of tuple handler to deal with empty std::tuple<...> objects.
   *
   * @note The use of "-1" as the ending index here is a bit of a hack. Since std::size_t is, by
   * definition, unsigned, this will evaluate to std::numeric_limits<std::size_t>::max().
   */
   template<typename TupleType>
   struct tuple_handler<TupleType, 0, -1>
   {
      template<
         typename StreamType,
         typename FormatterType
      >
      inline static void print(
         StreamType& /*stream*/,
         const TupleType& /*tuple*/,
         FormatterType& /*formatter*/) noexcept
      {
      };
   };

   /**
   * @brief Specialization of tuple handler to deal with the last element in the std::tuple<...>
   * object.
   */
   template<
      typename TupleType,
      std::size_t Index
   >
   struct tuple_handler<TupleType, Index, Index>
   {
      template<
         typename StreamType,
         typename FormatterType
      >
      inline static void print(
         StreamType& stream,
         const TupleType& tuple,
         FormatterType& /*formatter*/) noexcept
      {
         stream << std::get<Index>(tuple);
      }
   };

   /**
   * @brief Overload to deal with std::tuple<...> objects.
   *
   * @todo Look into using fold expressions once C++17 arrives.
   */
   template<
      typename StreamType,
      typename FormatterType,
      typename... TupleArgs
   >
   static StreamType& ToStream(
      StreamType& stream,
      const std::tuple<TupleArgs...>& container,
      FormatterType& formatter)
   {
      using ContainerType = std::decay_t<decltype(container)>;

      formatter.print_prefix(stream);
      tuple_handler<ContainerType, 0, sizeof...(TupleArgs) - 1>::print(stream, container, formatter);
      formatter.print_suffix(stream);

      return stream;
   }

   /**
   * @brief Overload to handle std::pair<...> objects.
   */
   template<
      typename FirstType,
      typename SecondType,
      typename StreamType,
      typename FormatterType
   >
   static StreamType& ToStream(
      StreamType& stream,
      const std::pair<FirstType, SecondType>& container,
      FormatterType& formatter)
   {
      formatter.print_prefix(stream);
      formatter.print_element(stream, container.first);
      formatter.print_delimiter(stream);
      formatter.print_element(stream, container.second);
      formatter.print_suffix(stream);

      return stream;
   }

   /**
   * @brief Overload to handle containers that support the notion of "emptiness,"
   * and forward-iterability.
   */
   template<
      typename ContainerType,
      typename StreamType,
      typename FormatterType
   >
   static StreamType& ToStream(
      StreamType& stream,
      const ContainerType& container,
      FormatterType& formatter)
   {
      formatter.print_prefix(stream);

      if (is_empty(container))
      {
         formatter.print_suffix(stream);

         return stream;
      }

      auto begin = std::begin(container);
      formatter.print_element(stream, *begin);

      std::advance(begin, 1);

      std::for_each(begin, std::end(container),
         [&stream, &formatter](const auto& element)
      {
         formatter.print_delimiter(stream);
         formatter.print_element(stream, element);
      });

      formatter.print_suffix(stream);

      return stream;
   }
}

/**
* @brief Overload of the stream output operator for compatible containers.
*/
template<
   typename ContainerType,
   typename StreamType,
   typename = std::enable_if_t<ContainerPrinter::Traits::is_printable_as_container_v<ContainerType>>
>
auto& operator<<(
   StreamType& stream,
   const ContainerType& container)
{
   using FormatterType = ContainerPrinter::default_formatter<ContainerType, StreamType>;
   ContainerPrinter::ToStream(stream, container, FormatterType{ });

   return stream;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2006-2019, ARM Limited, All Rights Reserved
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "platform/mbed_power_mgmt.h"
#include "platform/source/mbed_os_timer.h"
#include "platform/CriticalSectionLock.h"
#include "platform/source/SysTimer.h"
#include "us_ticker_api.h"
#include "lp_ticker_api.h"
#include "mbed_critical.h"
#include "mbed_assert.h"
#include <new>

/* This provides the marshalling point for a system global SysTimer, which
 * is used to provide:
 * - timed sleeps (for default idle hook in RTOS tickless mode, or non-RTOS sleeps)
 * - regular ticks for RTOS
 * - absolute system timing (directly for non-RTOS, or indirectly via RTOS tick count)
 */

namespace mbed {
namespace internal {

OsTimer *os_timer;

namespace {
uint64_t os_timer_data[(sizeof(OsTimer) + 7) / 8];
}

OsTimer *init_os_timer()
{
    // Do not use SingletonPtr since this relies on the RTOS.
    // Locking not required as it will be first called during
    // OS init, or else we're a non-RTOS single-threaded setup.
    if (!os_timer) {
#if MBED_CONF_TARGET_TICKLESS_FROM_US_TICKER && DEVICE_USTICKER
        os_timer = new (os_timer_data) OsTimer(get_us_ticker_data());
#elif !MBED_CONF_TARGET_TICKLESS_FROM_US_TICKER && DEVICE_LPTICKER
        os_timer = new (os_timer_data) OsTimer(get_lp_ticker_data());
#else
        MBED_ASSERT("OS timer not available - check MBED_CONF_TARGET_TICKLESS_FROM_US_TICKER" && false);
        return NULL;
#endif
        //os_timer->setup_irq();
    }

    return os_timer;
}

/* These traits classes are designed to permit chunks of code to be
 * omitted - in particular eliminating timers. However, we don't want
 * to cause template bloat, so don't have too many traits variants.
 */

/* Optionally timed operation, with optional predicate */
struct timed_predicate_op {
    timed_predicate_op(uint64_t t) : wake_time(t), orig_predicate(NULL), orig_handle(NULL)
    {
        init_os_timer();
    }

    timed_predicate_op(uint64_t t, bool (*wake_predicate)(void *), void *wake_predicate_handle) : wake_time(t), orig_predicate(wake_predicate), orig_handle(wake_predicate_handle)
    {
        init_os_timer();
    }

    ~timed_predicate_op()
    {
        // Make sure wake timer is cancelled. (It may or may not be, depending on
        // why we woke).
        os_timer->cancel_wake();
    }

    bool wake_condition() const
    {
        return (orig_predicate && orig_predicate(orig_handle)) || os_timer->wake_time_passed();
    }

    void sleep_prepare()
    {
        if (wake_time != (uint64_t) -1) {
            os_timer->set_wake_time(wake_time);
        }
    }

    bool sleep_prepared()
    {
        return wake_time == (uint64_t) -1 || os_timer->wake_time_set();
    }

private:
    uint64_t wake_time;
    bool (*orig_predicate)(void *);
    void *orig_handle;
};

/* Untimed operation with predicate */
struct untimed_op {
    untimed_op(bool (*wake_predicate)(void *), void *wake_predicate_handle) : orig_predicate(wake_predicate), orig_handle(wake_predicate_handle)
    {
    }

    bool wake_condition() const
    {
        return orig_predicate(orig_handle);
    }

    void sleep_prepare()
    {
    }

    bool sleep_prepared()
    {
        return true;
    }

private:
    bool (*orig_predicate)(void *);
    void *orig_handle;
};

/* We require that this is called from thread context, outside a critical section,
 * and the kernel already suspended if an RTOS, meaning we don't have to worry
 * about any potential threading issues.
 *
 * The wake predicate will be called from both outside and inside a critical
 * section, so appropriate atomic care must be taken.
 */
template <class OpT>
void do_sleep_operation(OpT &op)
{
    // We assume the ticker is not already in use - without RTOS, it
    // is never used, with RTOS, it will have been disabled with OS_Tick_Disable
    while (!op.wake_condition()) {
        // Set (or re-set) the wake time - outside a critical section, as
        // it could take long enough to cause UART data loss on some platforms.
        op.sleep_prepare();

        // If no target sleep function, nothing else to do - just keep
        // rechecking the wake condition.
#if DEVICE_SLEEP
        // Now we need to enter the critical section for the race-free sleep
        {
            CriticalSectionLock lock;

            // Recheck wake conditions before starting sleep, avoiding race
            if (op.wake_condition()) {
                break;
            }

            // It's possible that an intermediate wake interrupt occurred
            // between "set_wake_time" and the critical lock - only sleep
            // if we see that the timer is armed or we don't need it. Otherwise,
            // we go round to set the timer again.
            if (op.sleep_prepared()) {
                // Enter HAL sleep (normal or deep)
                sleep();
            }
        }

        // Ensure interrupts get a chance to fire, which allows new result from
        // wake_predicate() and wake_time_passed()
        __ISB();
#endif
    }
}

/* We require that this is called from thread context, outside a critical section,
 * and the kernel already suspended if an RTOS, meaning we don't have to worry
 * about any potential threading issues.
 *
 * The wake predicate will be called from both outside and inside a critical
 * section, so appropriate atomic care must be taken.
 */
uint64_t do_timed_sleep_absolute(uint64_t wake_time, bool (*wake_predicate)(void *), void *wake_predicate_handle)
{
    {
        timed_predicate_op op(wake_time, wake_predicate, wake_predicate_handle);
        do_sleep_operation(op);
    }

    return os_timer->update_and_get_tick();
}

#if MBED_CONF_RTOS_PRESENT
/* The 32-bit limit is part of the API - we will always wake within 2^32 ticks */
/* This version is tuned for RTOS use, where the RTOS needs to know the time spent sleeping */
uint32_t do_timed_sleep_relative(uint32_t wake_delay, bool (*wake_predicate)(void *), void *wake_predicate_handle)
{
    uint64_t sleep_start = init_os_timer()->get_tick();
    // When running with RTOS, the requested delay will be based on the kernel's tick count.
    // If it missed a tick as entering idle, we should reflect that by moving the
    // start time back to reflect its current idea of time.
    // Example: OS tick count = 100, our tick count = 101, requested delay = 50
    // We need to schedule wake for tick 150, report 50 ticks back to our caller, and
    // clear the unacknowledged tick count.
    sleep_start -= os_timer->unacknowledged_ticks();

    uint64_t sleep_finish = do_timed_sleep_absolute(sleep_start + wake_delay, wake_predicate, wake_predicate_handle);

    return static_cast<uint32_t>(sleep_finish - sleep_start);
}

#else

void do_untimed_sleep(bool (*wake_predicate)(void *), void *wake_predicate_handle)
{
    untimed_op op(wake_predicate, wake_predicate_handle);

    do_sleep_operation(op);
}

/* (uint32_t)-1 delay is treated as "wait forever" */
/* This version is tuned for non-RTOS use, where we don't need to return sleep time, and waiting forever is possible */
void do_timed_sleep_relative_or_forever(uint32_t wake_delay, bool (*wake_predicate)(void *), void *wake_predicate_handle)
{
    // Special-case 0 delay, to save multiple callers having to do it. Just call the predicate once.
    if (wake_delay == 0) {
        wake_predicate(wake_predicate_handle);
        return;
    }

    uint64_t wake_time;
    if (wake_delay == (uint32_t) -1) {
        wake_time = (uint64_t) -1;
    } else {
        wake_time = init_os_timer()->update_and_get_tick() + wake_delay;
    }
    /* Always use timed_predicate_op here to save pulling in two templates */
    timed_predicate_op op(wake_time, wake_predicate, wake_predicate_handle);
    do_sleep_operation(op);
}

#endif

} // namespace internal
} // namespace mbed
<commit_msg>Fix thread_sleep_for zero<commit_after>/*
 * Copyright (c) 2006-2019, ARM Limited, All Rights Reserved
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "platform/mbed_power_mgmt.h"
#include "platform/source/mbed_os_timer.h"
#include "platform/CriticalSectionLock.h"
#include "platform/source/SysTimer.h"
#include "us_ticker_api.h"
#include "lp_ticker_api.h"
#include "mbed_critical.h"
#include "mbed_assert.h"
#include <new>

/* This provides the marshalling point for a system global SysTimer, which
 * is used to provide:
 * - timed sleeps (for default idle hook in RTOS tickless mode, or non-RTOS sleeps)
 * - regular ticks for RTOS
 * - absolute system timing (directly for non-RTOS, or indirectly via RTOS tick count)
 */

namespace mbed {
namespace internal {

OsTimer *os_timer;

namespace {
uint64_t os_timer_data[(sizeof(OsTimer) + 7) / 8];
}

OsTimer *init_os_timer()
{
    // Do not use SingletonPtr since this relies on the RTOS.
    // Locking not required as it will be first called during
    // OS init, or else we're a non-RTOS single-threaded setup.
    if (!os_timer) {
#if MBED_CONF_TARGET_TICKLESS_FROM_US_TICKER && DEVICE_USTICKER
        os_timer = new (os_timer_data) OsTimer(get_us_ticker_data());
#elif !MBED_CONF_TARGET_TICKLESS_FROM_US_TICKER && DEVICE_LPTICKER
        os_timer = new (os_timer_data) OsTimer(get_lp_ticker_data());
#else
        MBED_ASSERT("OS timer not available - check MBED_CONF_TARGET_TICKLESS_FROM_US_TICKER" && false);
        return NULL;
#endif
        //os_timer->setup_irq();
    }

    return os_timer;
}

/* These traits classes are designed to permit chunks of code to be
 * omitted - in particular eliminating timers. However, we don't want
 * to cause template bloat, so don't have too many traits variants.
 */

/* Optionally timed operation, with optional predicate */
struct timed_predicate_op {
    timed_predicate_op(uint64_t t) : wake_time(t), orig_predicate(NULL), orig_handle(NULL)
    {
        init_os_timer();
    }

    timed_predicate_op(uint64_t t, bool (*wake_predicate)(void *), void *wake_predicate_handle) : wake_time(t), orig_predicate(wake_predicate), orig_handle(wake_predicate_handle)
    {
        init_os_timer();
    }

    ~timed_predicate_op()
    {
        // Make sure wake timer is cancelled. (It may or may not be, depending on
        // why we woke).
        os_timer->cancel_wake();
    }

    bool wake_condition() const
    {
        return (orig_predicate && orig_predicate(orig_handle)) || os_timer->wake_time_passed();
    }

    void sleep_prepare()
    {
        if (wake_time != (uint64_t) -1) {
            os_timer->set_wake_time(wake_time);
        }
    }

    bool sleep_prepared()
    {
        return wake_time == (uint64_t) -1 || os_timer->wake_time_set();
    }

private:
    uint64_t wake_time;
    bool (*orig_predicate)(void *);
    void *orig_handle;
};

/* Untimed operation with predicate */
struct untimed_op {
    untimed_op(bool (*wake_predicate)(void *), void *wake_predicate_handle) : orig_predicate(wake_predicate), orig_handle(wake_predicate_handle)
    {
    }

    bool wake_condition() const
    {
        return orig_predicate(orig_handle);
    }

    void sleep_prepare()
    {
    }

    bool sleep_prepared()
    {
        return true;
    }

private:
    bool (*orig_predicate)(void *);
    void *orig_handle;
};

/* We require that this is called from thread context, outside a critical section,
 * and the kernel already suspended if an RTOS, meaning we don't have to worry
 * about any potential threading issues.
 *
 * The wake predicate will be called from both outside and inside a critical
 * section, so appropriate atomic care must be taken.
 */
template <class OpT>
void do_sleep_operation(OpT &op)
{
    // We assume the ticker is not already in use - without RTOS, it
    // is never used, with RTOS, it will have been disabled with OS_Tick_Disable
    while (!op.wake_condition()) {
        // Set (or re-set) the wake time - outside a critical section, as
        // it could take long enough to cause UART data loss on some platforms.
        op.sleep_prepare();

        // If no target sleep function, nothing else to do - just keep
        // rechecking the wake condition.
#if DEVICE_SLEEP
        // Now we need to enter the critical section for the race-free sleep
        {
            CriticalSectionLock lock;

            // Recheck wake conditions before starting sleep, avoiding race
            if (op.wake_condition()) {
                break;
            }

            // It's possible that an intermediate wake interrupt occurred
            // between "set_wake_time" and the critical lock - only sleep
            // if we see that the timer is armed or we don't need it. Otherwise,
            // we go round to set the timer again.
            if (op.sleep_prepared()) {
                // Enter HAL sleep (normal or deep)
                sleep();
            }
        }

        // Ensure interrupts get a chance to fire, which allows new result from
        // wake_predicate() and wake_time_passed()
        __ISB();
#endif
    }
}

/* We require that this is called from thread context, outside a critical section,
 * and the kernel already suspended if an RTOS, meaning we don't have to worry
 * about any potential threading issues.
 *
 * The wake predicate will be called from both outside and inside a critical
 * section, so appropriate atomic care must be taken.
 */
uint64_t do_timed_sleep_absolute(uint64_t wake_time, bool (*wake_predicate)(void *), void *wake_predicate_handle)
{
    {
        timed_predicate_op op(wake_time, wake_predicate, wake_predicate_handle);
        do_sleep_operation(op);
    }

    return os_timer->update_and_get_tick();
}

#if MBED_CONF_RTOS_PRESENT
/* The 32-bit limit is part of the API - we will always wake within 2^32 ticks */
/* This version is tuned for RTOS use, where the RTOS needs to know the time spent sleeping */
uint32_t do_timed_sleep_relative(uint32_t wake_delay, bool (*wake_predicate)(void *), void *wake_predicate_handle)
{
    uint64_t sleep_start = init_os_timer()->get_tick();
    // When running with RTOS, the requested delay will be based on the kernel's tick count.
    // If it missed a tick as entering idle, we should reflect that by moving the
    // start time back to reflect its current idea of time.
    // Example: OS tick count = 100, our tick count = 101, requested delay = 50
    // We need to schedule wake for tick 150, report 50 ticks back to our caller, and
    // clear the unacknowledged tick count.
    sleep_start -= os_timer->unacknowledged_ticks();

    uint64_t sleep_finish = do_timed_sleep_absolute(sleep_start + wake_delay, wake_predicate, wake_predicate_handle);

    return static_cast<uint32_t>(sleep_finish - sleep_start);
}

#else

void do_untimed_sleep(bool (*wake_predicate)(void *), void *wake_predicate_handle)
{
    untimed_op op(wake_predicate, wake_predicate_handle);

    do_sleep_operation(op);
}

/* (uint32_t)-1 delay is treated as "wait forever" */
/* This version is tuned for non-RTOS use, where we don't need to return sleep time, and waiting forever is possible */
void do_timed_sleep_relative_or_forever(uint32_t wake_delay, bool (*wake_predicate)(void *), void *wake_predicate_handle)
{
    // Special-case 0 delay, to save multiple callers having to do it. Just call the predicate once.
    if (wake_delay == 0) {
        if (wake_predicate) {
            wake_predicate(wake_predicate_handle);
        }
        return;
    }

    uint64_t wake_time;
    if (wake_delay == (uint32_t) -1) {
        wake_time = (uint64_t) -1;
    } else {
        wake_time = init_os_timer()->update_and_get_tick() + wake_delay;
    }
    /* Always use timed_predicate_op here to save pulling in two templates */
    timed_predicate_op op(wake_time, wake_predicate, wake_predicate_handle);
    do_sleep_operation(op);
}

#endif

} // namespace internal
} // namespace mbed
<|endoftext|>


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

#include "task_map/SmoothCollisionDistance.h"

REGISTER_TASKMAP_TYPE("SmoothCollisionDistance",
                      exotica::SmoothCollisionDistance);

namespace exotica
{
SmoothCollisionDistance::SmoothCollisionDistance() {}
void SmoothCollisionDistance::update(Eigen::VectorXdRefConst x,
                                     Eigen::VectorXdRef phi)
{
    if (phi.rows() != dim_) throw_named("Wrong size of phi!");
    phi.setZero();
    Eigen::MatrixXd J;
    update(x, phi, J, false);
}

void SmoothCollisionDistance::update(Eigen::VectorXdRefConst x,
                                     Eigen::VectorXdRef phi,
                                     Eigen::MatrixXdRef J)
{
    if (phi.rows() != dim_) throw_named("Wrong size of phi!");
    phi.setZero();
    J.setZero();

    update(x, phi, J, true);
}

void SmoothCollisionDistance::update(Eigen::VectorXdRefConst x,
                                     Eigen::VectorXdRef phi,
                                     Eigen::MatrixXdRef J,
                                     bool updateJacobian)
{
    double& d = phi(0);
    for (const auto& link : robotLinks_)
    {
        // Get all world collision links, then iterate through them
        // std::vector<CollisionProxy> proxies = cscene_->getCollisionDistance(scene_->getControlledLinkToCollisionLinkMap()[link], check_self_collision_);
        std::vector<CollisionProxy> proxies = cscene_->getCollisionDistance(link, check_self_collision_);

        for (const auto& proxy : proxies)
        {
            bool isRobotToRobot = (proxy.e1->isRobotLink || proxy.e1->ClosestRobotLink.lock()) && (proxy.e2->isRobotLink || proxy.e2->ClosestRobotLink.lock());
            double& margin = isRobotToRobot ? robot_margin_ : world_margin_;
            if (proxy.distance < margin)
            {
                // Cost
                d += std::pow((1. - proxy.distance / margin), linear_ ? 1 : 2);

                if (updateJacobian)
                {
                    // Jacobian
                    KDL::Frame arel = KDL::Frame(proxy.e1->Frame.Inverse(KDL::Vector(
                        proxy.contact1(0), proxy.contact1(1), proxy.contact1(2))));
                    KDL::Frame brel = KDL::Frame(proxy.e2->Frame.Inverse(KDL::Vector(
                        proxy.contact2(0), proxy.contact2(1), proxy.contact2(2))));

                    if (!linear_)
                    {
                        Eigen::MatrixXd tmpJ = scene_->getSolver().Jacobian(
                            proxy.e1, arel, nullptr, KDL::Frame());
                        J += (2. / (margin * margin)) * (proxy.normal1.transpose() * tmpJ);
                        tmpJ = scene_->getSolver().Jacobian(proxy.e2, brel, nullptr,
                                                            KDL::Frame());
                        J -= (2. / (margin * margin)) * (proxy.normal1.transpose() * tmpJ);
                    }
                    else
                    {
                        Eigen::MatrixXd tmpJ = scene_->getSolver().Jacobian(
                            proxy.e1, arel, nullptr, KDL::Frame());
                        J += 1 / margin * (proxy.normal1.transpose() * tmpJ);
                        tmpJ = scene_->getSolver().Jacobian(proxy.e2, brel, nullptr,
                                                            KDL::Frame());
                        J -= 1 / margin * (proxy.normal1.transpose() * tmpJ);
                    }
                }
            }
        }
    }
}

void SmoothCollisionDistance::Instantiate(
    SmoothCollisionDistanceInitializer& init)
{
    init_ = init;
}

void SmoothCollisionDistance::assignScene(Scene_ptr scene)
{
    scene_ = scene;
    Initialize();
}

void SmoothCollisionDistance::Initialize()
{
    cscene_ = scene_->getCollisionScene();
    world_margin_ = init_.WorldMargin;
    robot_margin_ = init_.RobotMargin;
    linear_ = init_.Linear;
    check_self_collision_ = init_.CheckSelfCollision;

    HIGHLIGHT_NAMED("Smooth Collision Distance",
                    "World Margin: " << world_margin_ << " Robot Margin: " << robot_margin_ << "\t Linear: " << linear_);

    // Get names of all controlled joints and their corresponding child links
    robotLinks_ = scene_->getControlledLinkNames();
}

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

#include "task_map/SmoothCollisionDistance.h"

REGISTER_TASKMAP_TYPE("SmoothCollisionDistance",
                      exotica::SmoothCollisionDistance);

namespace exotica
{
SmoothCollisionDistance::SmoothCollisionDistance() {}
void SmoothCollisionDistance::update(Eigen::VectorXdRefConst x,
                                     Eigen::VectorXdRef phi)
{
    if (phi.rows() != dim_) throw_named("Wrong size of phi!");
    phi.setZero();
    Eigen::MatrixXd J;
    update(x, phi, J, false);
}

void SmoothCollisionDistance::update(Eigen::VectorXdRefConst x,
                                     Eigen::VectorXdRef phi,
                                     Eigen::MatrixXdRef J)
{
    if (phi.rows() != dim_) throw_named("Wrong size of phi!");
    if (!scene_->alwaysUpdatesCollisionScene())
        cscene_->updateCollisionObjectTransforms();

    phi.setZero();
    J.setZero();

    update(x, phi, J, true);
}

void SmoothCollisionDistance::update(Eigen::VectorXdRefConst x,
                                     Eigen::VectorXdRef phi,
                                     Eigen::MatrixXdRef J,
                                     bool updateJacobian)
{
    double& d = phi(0);
    for (const auto& link : robotLinks_)
    {
        // Get all world collision links, then iterate through them
        // std::vector<CollisionProxy> proxies = cscene_->getCollisionDistance(scene_->getControlledLinkToCollisionLinkMap()[link], check_self_collision_);
        std::vector<CollisionProxy> proxies = cscene_->getCollisionDistance(link, check_self_collision_);

        for (const auto& proxy : proxies)
        {
            bool isRobotToRobot = (proxy.e1->isRobotLink || proxy.e1->ClosestRobotLink.lock()) && (proxy.e2->isRobotLink || proxy.e2->ClosestRobotLink.lock());
            double& margin = isRobotToRobot ? robot_margin_ : world_margin_;
            if (proxy.distance < margin)
            {
                // Cost
                d += std::pow((1. - proxy.distance / margin), linear_ ? 1 : 2);

                if (updateJacobian)
                {
                    // Jacobian
                    KDL::Frame arel = KDL::Frame(proxy.e1->Frame.Inverse(KDL::Vector(
                        proxy.contact1(0), proxy.contact1(1), proxy.contact1(2))));
                    KDL::Frame brel = KDL::Frame(proxy.e2->Frame.Inverse(KDL::Vector(
                        proxy.contact2(0), proxy.contact2(1), proxy.contact2(2))));

                    if (!linear_)
                    {
                        Eigen::MatrixXd tmpJ = scene_->getSolver().Jacobian(
                            proxy.e1, arel, nullptr, KDL::Frame());
                        J += (2. / (margin * margin)) * (proxy.normal1.transpose() * tmpJ);
                        tmpJ = scene_->getSolver().Jacobian(proxy.e2, brel, nullptr,
                                                            KDL::Frame());
                        J -= (2. / (margin * margin)) * (proxy.normal1.transpose() * tmpJ);
                    }
                    else
                    {
                        Eigen::MatrixXd tmpJ = scene_->getSolver().Jacobian(
                            proxy.e1, arel, nullptr, KDL::Frame());
                        J += 1 / margin * (proxy.normal1.transpose() * tmpJ);
                        tmpJ = scene_->getSolver().Jacobian(proxy.e2, brel, nullptr,
                                                            KDL::Frame());
                        J -= 1 / margin * (proxy.normal1.transpose() * tmpJ);
                    }
                }
            }
        }
    }
}

void SmoothCollisionDistance::Instantiate(
    SmoothCollisionDistanceInitializer& init)
{
    init_ = init;
}

void SmoothCollisionDistance::assignScene(Scene_ptr scene)
{
    scene_ = scene;
    Initialize();
}

void SmoothCollisionDistance::Initialize()
{
    cscene_ = scene_->getCollisionScene();
    world_margin_ = init_.WorldMargin;
    robot_margin_ = init_.RobotMargin;
    linear_ = init_.Linear;
    check_self_collision_ = init_.CheckSelfCollision;

    HIGHLIGHT_NAMED("Smooth Collision Distance",
                    "World Margin: " << world_margin_ << " Robot Margin: " << robot_margin_ << "\t Linear: " << linear_);

    // Get names of all controlled joints and their corresponding child links
    robotLinks_ = scene_->getControlledLinkNames();
}

int SmoothCollisionDistance::taskSpaceDim() { return dim_; }
}
<|endoftext|>