Files
core/ASCOfficeDocFile/DocDocxConverter/VMLShapeMapping.cpp
2016-12-16 12:28:17 +03:00

2106 lines
63 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2016
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
* EU, LV-1021.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "VMLShapeMapping.h"
#include "TextboxMapping.h"
#include "OfficeDrawing/Shapetypes/LineType.h"
#include "OfficeDrawing/Shapetypes/OvalType.h"
#include "OfficeDrawing/Shapetypes/RectangleType.h"
#include "OfficeDrawing/Shapetypes/RoundedRectangleType.h"
#include "OfficeDrawing/OfficeArtClientTextbox.h"
#include "OfficeDrawing/DiagramBooleanProperties.h"
#include "OfficeDrawing/GeometryBooleanProperties.h"
#include "OfficeDrawing/ShadowStyleBooleanProperties.h"
#include "OfficeDrawing/GeometryBooleanProperties.h"
#include "OfficeDrawing/FillStyleBooleanProperties.h"
#include "OfficeDrawing/GeometryBooleanProperties.h"
#include "OfficeDrawing/FillStyleBooleanProperties.h"
#include "OfficeDrawing/LineStyleBooleanProperties.h"
#include "OfficeDrawing/GeometryTextBooleanProperties.h"
#include "OfficeDrawing/GroupShapeBooleanProperties.h"
#include "OfficeDrawing/ProtectionBooleanProperties.h"
#include "DrawingPrimitives.h"
#include "../../DesktopEditor/common/String.h"
#include "../Common/FormatUtils.h"
namespace DocFileFormat
{
VMLShapeMapping::VMLShapeMapping (ConversionContext* pConv, XMLTools::CStringXmlWriter* pWriter, Spa* pSpa, PictureDescriptor* pPicture, IMapping* pCaller, bool isInlineShape) : PropertiesMapping(pWriter)
{
m_isInlineShape = isInlineShape;
m_isBullete = false;
m_pSpa = pSpa;
m_pCaller = pCaller;
m_pBlipStore = NULL;
m_context = pConv;
m_pict = pPicture;
m_nImageId = 0;
m_imagedata = XMLTools::XMLElement<wchar_t>(L"v:imagedata");
m_fill = XMLTools::XMLElement<wchar_t>(L"v:fill");
m_stroke = XMLTools::XMLElement<wchar_t>(L"v:stroke");
m_shadow = XMLTools::XMLElement<wchar_t>(L"v:shadow");
m_3dstyle = XMLTools::XMLElement<wchar_t>(L"o:extrusion");
m_textpath = XMLTools::XMLElement<wchar_t>(L"v:textpath");
Record* recBs = NULL;
if ((m_context) && (m_context->_doc))
{
OfficeArtContent* officeArt = m_context->_doc->GetOfficeArt();
if (officeArt)
{
const DrawingGroup* group = officeArt->GetDrawingGroup();
if (group)
{
recBs = group->FirstChildWithType<BlipStoreContainer>();
}
}
}
if (recBs)
{
m_pBlipStore = static_cast<BlipStoreContainer*>(recBs);
}
}
VMLShapeMapping::~VMLShapeMapping()
{
}
}
namespace DocFileFormat
{
void VMLShapeMapping::Apply(IVisitable* visited)
{
DrawingPrimitives * primitives = dynamic_cast<DrawingPrimitives *>(visited);
if ( primitives ) return ApplyPrimitives(primitives);
//----------------------------------------------------------------------------------------------
ShapeContainer* pContainer = dynamic_cast<ShapeContainer*>(visited);
if ((pContainer != NULL) && (!pContainer->Children.empty()))
{
Record* firstRecord = pContainer->Children[0];
if (firstRecord != NULL)
{
if (typeid(*firstRecord) == typeid(Shape))
{
// It's a single shape
WriteShape(pContainer);
}
else if (typeid(*firstRecord) == typeid(GroupShapeRecord))
{
// Its a group of shapes
WriteGroup(static_cast<GroupContainer*>(pContainer->_ParentRecord));
}
}
}
}
/// Converts a group of shapes
void VMLShapeMapping::WriteGroup (const GroupContainer* container)
{
if ((container != NULL) && (!container->Children.empty()))
{
ShapeContainer* groupShape = static_cast<ShapeContainer*>(container->Children[0]);
GroupShapeRecord* gsr = static_cast<GroupShapeRecord*>(groupShape->Children[0]);
Shape* shape = static_cast<Shape*>(groupShape->Children[1]);
std::list<OptionEntry> options = groupShape->ExtractOptions();
ChildAnchor* anchor = groupShape->FirstChildWithType<ChildAnchor>();
m_shapeId = GetShapeID(shape);
m_pXmlWriter->WriteNodeBegin( L"v:group", true );
m_pXmlWriter->WriteAttribute( L"id", m_shapeId .c_str());
m_pXmlWriter->WriteAttribute( L"style", FormatUtils::XmlEncode(buildStyle(shape, anchor, options, container->Index)).c_str() );
m_pXmlWriter->WriteAttribute( L"coordorigin", ( FormatUtils::IntToWideString(gsr->rcgBounds.topLeftAngle.x) + L"," + FormatUtils::IntToWideString( gsr->rcgBounds.topLeftAngle.y)).c_str() );
m_pXmlWriter->WriteAttribute( L"coordsize", ( FormatUtils::IntToWideString(gsr->rcgBounds.size.cx) + L"," + FormatUtils::IntToWideString(gsr->rcgBounds.size.cy)).c_str() );
// Write wrap coords
std::list<OptionEntry>::const_iterator end = options.end();
for (std::list<OptionEntry>::const_iterator iter = options.begin(); iter != end; ++iter)
{
switch (iter->pid)
{
case pWrapPolygonVertices:
{
std::wstring wrapCoords = getWrapCoords(*iter);
if (wrapCoords.length())
m_pXmlWriter->WriteAttribute(L"wrapcoords", wrapCoords.c_str());
}
break;
}
}
m_pXmlWriter->WriteNodeEnd(L"", true, false);
// Convert the shapes/groups in the group
size_t count = container->Children.size();
for (size_t i = 1; i < count; ++i)
{
if (container->Children[i])
{
if (typeid(*container->Children[i]) == typeid(ShapeContainer))
{
ShapeContainer* pChildShape = static_cast<ShapeContainer*>(container->Children[i]);
if (pChildShape)
{
VMLShapeMapping vmlShapeMapping(m_context, m_pXmlWriter, m_pSpa, NULL, m_pCaller);
pChildShape->Convert(&vmlShapeMapping);
}
}
else if (typeid(*container->Children[i]) == typeid(GroupContainer))
{
GroupContainer* pChildGroup = static_cast<GroupContainer*>(container->Children[i]);
m_pSpa = NULL;
WriteGroup(pChildGroup);
}
}
}
// Write wrap
if (m_pSpa)
{
std::wstring wrap = getWrapType(m_pSpa);
if (wrap != L"through")
{
m_pXmlWriter->WriteNodeBegin( L"w10:wrap", true );
m_pXmlWriter->WriteAttribute( L"type", wrap.c_str() );
m_pXmlWriter->WriteNodeEnd ( L"w10:wrap", true );
}
}
m_pXmlWriter->WriteNodeEnd( L"v:group" );
}
}
/// Converts a single shape
void VMLShapeMapping::WriteShape(const ShapeContainer* pContainer)
{
if ((NULL == pContainer) || (pContainer->Children.empty())) return;
Shape* pShape = static_cast<Shape*>(pContainer->Children[0]);
if (!pShape) return;
int indexOLE = -1;
bool freeform = true;
std::wstring sShapeId;
std::list<OptionEntry> options = pContainer->ExtractOptions();
ChildAnchor* pAnchor = pContainer->FirstChildWithType<ChildAnchor>();
ClientAnchor* clientAnchor = pContainer->FirstChildWithType<ClientAnchor>();
WriteBeginShapeNode (pShape);
m_shapeId = GetShapeID(pShape);
count_vml_objects++;
if (m_shapeId.empty())
m_shapeId = std::wstring(L"_x0000_s") + FormatUtils::IntToWideString(1024 + count_vml_objects);
m_pXmlWriter->WriteAttribute ( L"id", m_shapeId );
if ( !pShape->fBackground )
{
if (pShape->GetShapeType())
{
freeform = false;
m_pXmlWriter->WriteAttribute( L"type", (std::wstring(L"#") + VMLShapeTypeMapping::GenerateTypeId(pShape->GetShapeType())).c_str());
m_pXmlWriter->WriteAttribute( L"style", FormatUtils::XmlEncode(buildStyle(pShape, pAnchor, options, pContainer->Index)).c_str());
}
if (pShape->is<LineType>())
{
//append "from" and "to" attributes
m_pXmlWriter->WriteAttribute(L"from", GetLineFrom(pAnchor).c_str());
m_pXmlWriter->WriteAttribute(L"to", GetLineTo(pAnchor).c_str());
}
if (m_isBullete)
{
m_pXmlWriter->WriteAttribute(L"o:bullet", L"t");
}
}
EmuValue ShadowOffsetX;
EmuValue ShadowOffsetY;
EmuValue SecondShadowOffsetX;
EmuValue SecondShadowOffsetY;
EmuValue ViewPointX;
EmuValue ViewPointY;
EmuValue ViewPointZ;
double viewPointOriginX = 0;
double viewPointOriginY = 0;
double ShadowOriginX = 0;
double ShadowOriginY = 0;
unsigned int xCoord = 0;
unsigned int yCoord = 0;
bool stroked = true;
bool filled = true;
bool hasTextbox = false;
bool layoutInCell = true; //anmeldebogenfos.doc
int ndxTextLeft = -1;
int ndyTextTop = -1;
int ndxTextRight = -1;
int ndyTextBottom = -1;
bool bHavePath = false;
int nAdjValues = 0;
int nLTxID = -1;
std::wstring sTextboxStyle;
std::wstring adjValues[8];
ShadowStyleBooleanProperties shadowBoolean(0);
std::vector<std::wstring> arrInscribe;
std::list<OptionEntry>::const_iterator end = options.end();
for (std::list<OptionEntry>::const_iterator iter = options.begin(); iter != end; ++iter)
{
switch (iter->pid)
{
//BOOLEANS
case geometryBooleans:
{
GeometryBooleanProperties booleans(iter->op);
if (booleans.fUsefLineOK && !booleans.fLineOK)
{
stroked = false;
}
if (booleans.fUsefFillOK && !booleans.fFillOK)
{
filled = false;
}
}
break;
case fillStyleBooleanProperties:
{
FillStyleBooleanProperties booleans(iter->op);
if (booleans.fUsefFilled && !booleans.fFilled)
{
filled = false;
}
}break;
case lineStyleBooleans:
{
LineStyleBooleanProperties booleans(iter->op);
if (booleans.fUsefLine && !booleans.fLine)
{
stroked = false;
}
}
break;
case protectionBooleans:
{
ProtectionBooleanProperties booleans(iter->op);
}
break;
case diagramBooleans:
{
DiagramBooleanProperties booleans(iter->op);
}
break;
case groupShapeBooleans:
{
GroupShapeBooleanProperties booleans(iter->op);
if (booleans.fUsefLayoutInCell)
{
layoutInCell = booleans.fLayoutInCell;
}
}
break;
// GEOMETRY
case adjustValue:
{
adjValues[0] = FormatUtils::IntToWideString( (int)iter->op );
nAdjValues = (std::max)(nAdjValues,1);
}
break;
case adjust2Value:
{
adjValues[1] = FormatUtils::IntToWideString( (int)iter->op );
nAdjValues = (std::max)(nAdjValues,2);
}
break;
case adjust3Value:
{
adjValues[2] = FormatUtils::IntToWideString( (int)iter->op );
nAdjValues = (std::max)(nAdjValues,3);
}break;
case adjust4Value:
{
adjValues[3] = FormatUtils::IntToWideString( (int)iter->op );
nAdjValues = (std::max)(nAdjValues,4);
}break;
case adjust5Value:
{
adjValues[4] = FormatUtils::IntToWideString( (int)iter->op );
nAdjValues = (std::max)(nAdjValues,5);
}break;
case adjust6Value:
{
adjValues[5] = FormatUtils::IntToWideString( (int)iter->op );
nAdjValues = (std::max)(nAdjValues,6);
}break;
case adjust7Value:
{
adjValues[6] = FormatUtils::IntToWideString( (int)iter->op );
nAdjValues = (std::max)(nAdjValues,7);
}break;
case adjust8Value:
{
adjValues[7] = FormatUtils::IntToWideString( (int)iter->op );
nAdjValues = (std::max)(nAdjValues,8);
}break;
case pWrapPolygonVertices:
{
std::wstring wrapCoords = getWrapCoords(*iter);
if (!wrapCoords.empty())
{
m_pXmlWriter->WriteAttribute( L"wrapcoords", wrapCoords.c_str() );
}
}break;
case geoRight:
{
xCoord = iter->op;
}break;
case geoBottom:
{
yCoord = iter->op;
}break;
case pGuides:
{
}break;
case pInscribe:
{
arrInscribe = GetTextRectangles(*iter);
}break;
// OUTLINE
case lineColor:
{
RGBColor lineColor((int)iter->op, RedFirst);
if ( !pShape->fBackground )
m_pXmlWriter->WriteAttribute( L"strokecolor", (std::wstring(L"#") + lineColor.SixDigitHexCode).c_str());
}break;
case lineWidth:
{
if (iter->op > 0)
{
EmuValue eLineWidth ((int)iter->op );
m_pXmlWriter->WriteAttribute(L"strokeweight", FormatUtils::DoubleToWideString(eLineWidth.ToPoints()) + L"pt");
}
}break;
case lineDashing:
{
appendValueAttribute(&m_stroke, L"dashstyle", FormatUtils::MapValueToWideString( iter->op, &Global::DashStyleMap[0][0], 11, 16 ).c_str() );
}break;
case lineStyle:
{
appendValueAttribute(&m_stroke, L"linestyle", getLineStyle( iter->op ).c_str());
}break;
case lineEndArrowhead:
{
appendValueAttribute(&m_stroke, L"endarrow", getArrowStyle( iter->op ).c_str());
}break;
case lineEndArrowLength:
{
appendValueAttribute(&m_stroke, L"endarrowlength", getArrowLength( iter->op ).c_str());
}break;
case lineEndArrowWidth:
{
appendValueAttribute(&m_stroke, L"endarrowwidth", getArrowWidth( iter->op ).c_str());
}break;
case lineStartArrowhead:
{
appendValueAttribute(&m_stroke, L"startarrow", getArrowStyle( iter->op ).c_str());
}break;
case lineStartArrowLength:
{
appendValueAttribute(&m_stroke, L"startarrowlength", getArrowLength( iter->op ).c_str());
}break;
case lineStartArrowWidth:
{
appendValueAttribute(&m_stroke, L"startarrowwidth", getArrowWidth( iter->op ).c_str());
}break;
// FILL
case fillColor:
{
RGBColor fillColor((int)iter->op, RedFirst);
m_pXmlWriter->WriteAttribute(L"fillcolor", ( std::wstring( L"#" ) + fillColor.SixDigitHexCode ).c_str());
}break;
case fillBackColor:
{
RGBColor fillBackColor( (int)iter->op, RedFirst );
appendValueAttribute(&m_fill, L"color2", ( std::wstring( L"#" ) + fillBackColor.SixDigitHexCode ).c_str());
}break;
case fillAngle:
{
FixedPointNumber fllAngl( iter->op );
appendValueAttribute(&m_fill, L"angle", FormatUtils::DoubleToWideString( fllAngl.ToAngle() ).c_str());
}break;
case fillShadeType:
{
appendValueAttribute(&m_fill, L"method", getFillMethod( iter->op ).c_str());
}break;
case fillShadeColors:
{
appendValueAttribute(&m_fill, L"colors", getFillColorString( iter->opComplex, iter->op ).c_str());
}break;
case fillFocus:
{
appendValueAttribute(&m_fill, L"focus", ( FormatUtils::IntToWideString( iter->op ) + L"%" ).c_str());
}break;
case fillType:
{
appendValueAttribute(&m_fill, L"type", getFillType( iter->op ).c_str());
}break;
case fillBlip:
{
BlipStoreEntry* pFillBlip = NULL;
if ((m_pict != NULL ) && (m_pict->blipStoreEntry != NULL ))
{
// Word Art Texture
//fillBlip = this->_pict->BlipStoreEntry;
}
else if ( (m_pBlipStore != NULL) && ( (iter->op - 1) < m_pBlipStore->Children.size() ) )
{
pFillBlip = static_cast<BlipStoreEntry*>(m_pBlipStore->Children[iter->op - 1]);
}
if ( (pFillBlip != NULL) && copyPicture(pFillBlip) )
{
appendValueAttribute(&m_fill, L"r:id", std::wstring(( L"rId" ) + FormatUtils::IntToWideString(m_nImageId) ).c_str());
}
}break;
case fillOpacity:
{
appendValueAttribute(&m_fill, L"opacity", ( FormatUtils::IntToWideString( iter->op ) + L"f" ).c_str());
}
break;
case fillBackOpacity:
{
appendValueAttribute(&m_fill, L"opacity2", (FormatUtils::IntToWideString(iter->op) + L"f").c_str());
}break;
// SHADOW
case shadowType:
{
appendValueAttribute(&m_shadow, L"type", getShadowType(iter->op).c_str());
}break;
case shadowColor:
{
RGBColor shadowColor((int)iter->op, RedFirst);
appendValueAttribute(&m_shadow, L"color", ( std::wstring( L"#" ) + shadowColor.SixDigitHexCode ).c_str());
}break;
case shadowOffsetX:
{
ShadowOffsetX = EmuValue( (int)iter->op );
}break;
case shadowSecondOffsetX:
{
SecondShadowOffsetX = EmuValue( (int)iter->op );
}break;
case shadowOffsetY:
{
ShadowOffsetY = EmuValue( (int)iter->op );
}break;
case shadowSecondOffsetY:
{
SecondShadowOffsetY = EmuValue( (int)iter->op );
}break;
case shadowOriginX:
{
ShadowOriginX = ( iter->op / pow( (double)2, (double)16 ) );
}break;
case shadowOriginY:
{
ShadowOriginY = (iter->op / pow( (double)2, (double)16));
}break;
case shadowOpacity:
{
double shadowOpa = (iter->op / pow( (double)2, (double)16));
appendValueAttribute(&m_shadow, L"opacity", FormatUtils::DoubleToFormattedWideString( shadowOpa, L"%.2f" ).c_str());
}break;
case shadowStyleBooleanProperties:
{
shadowBoolean = ShadowStyleBooleanProperties(iter->op);
}break;
// OLE
case pictureId:
{
indexOLE = iter->op;
}break;
// PICTURE
case Pib:
{
int index = (int)( iter->op - 1 );
if ((m_pBlipStore != NULL) && (index < (int)m_pBlipStore->Children.size()))
{
BlipStoreEntry* oBlip = static_cast<BlipStoreEntry*>(m_pBlipStore->Children[index]);
if (copyPicture(oBlip))
{
appendValueAttribute(&m_imagedata, L"r:id", ( std::wstring( L"rId" ) + FormatUtils::IntToWideString(m_nImageId) ).c_str());
}
}
}break;
case pibName:
{
std::wstring name;
FormatUtils::GetSTLCollectionFromBytes<std::wstring>(&name, iter->opComplex, iter->op, ENCODING_UTF16);
if (!name.empty())
appendValueAttribute(&m_imagedata, L"o:title", FormatUtils::XmlEncode(name).c_str());
}break;
// 3D STYLE
case f3D:
case threeDStyleBooleanProperties:
case threeDObjectBooleanProperties:
break;
case c3DExtrudeBackward:
{
EmuValue backwardValue( (int)iter->op );
std::wstring depth = FormatUtils::DoubleToWideString( backwardValue.ToPoints() ) + L"pt";
appendValueAttribute(&m_3dstyle, L"backdepth", depth.c_str());
}break;
case c3DAmbientIntensity:
{
std::wstring intens = FormatUtils::IntToWideString((int)iter->op) + L"f";
appendValueAttribute(&m_3dstyle, L"brightness", intens.c_str());
}break;
case c3DSpecularAmt:
{
std::wstring amt = FormatUtils::IntToWideString((int)iter->op) + L"f";
appendValueAttribute(&m_3dstyle, L"specularity", amt.c_str());
}break;
case c3DDiffuseAmt:
{
std::wstring amt = FormatUtils::IntToWideString((int)iter->op) + L"f";
appendValueAttribute(&m_3dstyle, L"diffusity", amt.c_str());
}break;
case c3DKeyIntensity:
{
std::wstring amt = FormatUtils::IntToWideString((int)iter->op);
appendValueAttribute(&m_3dstyle, L"lightlevel", amt.c_str());
}break;
case c3DExtrusionColor:
{
std::wstring color = FormatUtils::IntToFormattedWideString(iter->op, L"#%06x");
appendValueAttribute(&m_3dstyle, L"color", color.c_str());
}break;
case c3DSkewAngle:
{
FixedPointNumber skewAngle( iter->op );
appendValueAttribute(&m_3dstyle, L"skewangle", FormatUtils::DoubleToWideString( skewAngle.ToAngle() ).c_str());
}break;
case c3DXViewpoint:
{
ViewPointX = EmuValue( FixedPointNumber( iter->op ).Integral );
}break;
case c3DYViewpoint:
{
ViewPointY = EmuValue( FixedPointNumber( iter->op ).Integral );
}break;
case c3DZViewpoint:
{
ViewPointZ = EmuValue( FixedPointNumber( iter->op ).Integral );
}break;
case c3DOriginX:
{
FixedPointNumber dOriginX( iter->op );
viewPointOriginX = ( dOriginX.Integral / 65536.0 );
}break;
case c3DOriginY:
{
FixedPointNumber dOriginY( iter->op );
viewPointOriginY = (dOriginY.Integral / 65536.0 );
}break;
// TEXTBOX
case lTxid:
{
hasTextbox = true;
nLTxID = (((iter->op) >> 16) & 0xFFFF);
}break;
case dxTextLeft: {ndxTextLeft = (int)iter->op;break;}
case dyTextTop: {ndyTextTop = (int)iter->op;break;}
case dxTextRight: {ndxTextRight = (int)iter->op;break;}
case dyTextBottom: {ndyTextBottom = (int)iter->op;break;}
case txflTextFlow:
{
switch(iter->op)
{
case 0:
case 4://обычный
break;
case 1:
case 5://верт (склони голову направо)
appendStyleProperty(&sTextboxStyle, L"layout-flow", L"vertical");
break;
case 2://верт (склони голову налево)
appendStyleProperty(&sTextboxStyle, L"layout-flow", L"vertical");
appendStyleProperty(&sTextboxStyle, L"mso-layout-flow-alt", L"bottom-to-top");
break;
}
}break;
// Word Art
case gtextUNICODE:
{
std::wstring text = NSStringExt::CConverter::GetUnicodeFromUTF16((unsigned short*)iter->opComplex, (iter->op)/2);
text = FormatUtils::XmlEncode(text);
if (0 <= text.find(L"\n"))
{
m_textpath.AppendText(text.c_str());
}
text = ReplaceString(text, L"\n", L"&#xA;");
appendValueAttribute(&m_textpath, L"string", text.c_str());
}break;
case gtextFont:
{
std::wstring font = NSStringExt::CConverter::GetUnicodeFromUTF16((unsigned short*)iter->opComplex, (iter->op)/2);
int i = font.size();
while (i > 0)
{
if (font[i-1] != 0) break;
i--;
}
if (i < font.size()) font.erase(font.begin() + i, font.end());
font = std::wstring(L"\"") + font + std::wstring(L"\"");
appendStyleProperty(&m_textPathStyle, L"font-family", font);
}break;
case gtextSize:
{
std::wstring fontSize = FormatUtils::IntToWideString(iter->op/65535);
appendStyleProperty(&m_textPathStyle, L"font-size", fontSize + L"pt");
}break;
case gtextSpacing:
{
std::wstring spacing = FormatUtils::IntToWideString(iter->op);
appendStyleProperty(&m_textPathStyle, L"v-text-spacing", spacing + L"f");
}break;
case geometryTextBooleanProperties:
{
GeometryTextBooleanProperties props(iter->op);
if (props.fUsegtextFBestFit && props.gtextFBestFit)
{
appendValueAttribute(&m_textpath, L"fitshape", L"t");
}
if (props.fUsegtextFShrinkFit && props.gtextFShrinkFit)
{
appendValueAttribute(&m_textpath, L"trim", L"t");
}
if (props.fUsegtextFVertical && props.gtextFVertical)
{
appendStyleProperty(&m_textPathStyle, L"v-rotate-letters", L"t");
//_twistDimension = true;
}
if (props.fUsegtextFKern && props.gtextFKern)
{
appendStyleProperty(&m_textPathStyle, L"v-text-kern", L"t");
}
if (props.fUsegtextFItalic && props.gtextFItalic)
{
appendStyleProperty(&m_textPathStyle, L"font-style", L"italic");
}
if (props.fUsegtextFBold && props.gtextFBold)
{
appendStyleProperty(&m_textPathStyle, L"font-weight", L"bold");
}
}break;
// PATH
case shapePath :
{
bHavePath = true;
std::wstring path = ParsePath(options);
if (false == path.empty())
m_pXmlWriter->WriteAttribute (L"path", path.c_str());
}break;
default:
{
int val = iter->op;
}break;
}
}
if (false == bHavePath) // фигура может быть задана только наборами вершин и индексов
{
std::wstring path = ParsePath(options);
if (false == path.empty())
m_pXmlWriter->WriteAttribute (L"path", path.c_str());
}
if ( !filled )
{
m_pXmlWriter->WriteAttribute( L"filled", L"f" );
}
if ( !stroked )
{
m_pXmlWriter->WriteAttribute( L"stroked", L"f" );
}
if (!layoutInCell)
{
m_pXmlWriter->WriteAttribute(L"o:allowincell", L"f");
}
if ( ( xCoord > 0 ) && ( yCoord > 0 ) )
{
m_pXmlWriter->WriteAttribute( L"coordsize", ( FormatUtils::IntToWideString( xCoord ) + L"," + FormatUtils::IntToWideString( yCoord ) ).c_str() );
}
int nCode = 0;
if (pShape->GetShapeType())
{
nCode = pShape->GetShapeType()->GetTypeCode();
}
if (DocFileFormat::msosptRoundRectangle == nCode)
{
if (nAdjValues)
{
m_pXmlWriter->WriteAttribute(L"arcsize", adjValues[0].c_str());
}
}
else
{
if (nAdjValues)
{
std::wstring adjTag = adjValues[0];
for (int i = 1; i < nAdjValues; ++i)
adjTag += std::wstring(L",") + adjValues[i];
m_pXmlWriter->WriteAttribute(L"adj", adjTag.c_str());
}
}
m_pXmlWriter->WriteNodeEnd( L"", true, false );
//build shadow offsets
std::wstring offset;
if ( ShadowOffsetX != 0 )
{
offset += FormatUtils::DoubleToWideString( ShadowOffsetX.ToPoints() );
offset += L"pt";
}
if ( ShadowOffsetY != 0 )
{
offset += L",";
offset += FormatUtils::DoubleToWideString( ShadowOffsetY.ToPoints() );
offset += L"pt";
}
if ( !offset.empty() )
{
appendValueAttribute(&m_shadow, L"offset", offset.c_str());
}
std::wstring offset2;
if ( SecondShadowOffsetX != 0 )
{
offset2 += FormatUtils::DoubleToWideString( SecondShadowOffsetX.ToPoints() );
offset2 += L"pt";
}
if ( SecondShadowOffsetY != 0 )
{
offset2 += L",";
offset2 += FormatUtils::DoubleToWideString(SecondShadowOffsetY.ToPoints());
offset2 += L"pt";
}
if (!offset2.empty())
{
appendValueAttribute(&m_shadow, L"offset2", offset2.c_str());
}
//build shadow origin
if ( ( ShadowOriginX != 0 ) && ( ShadowOriginY != 0 ) )
{
appendValueAttribute(&m_shadow, L"origin", (FormatUtils::DoubleToWideString(shadowOriginX) + std::wstring(L"," ) + FormatUtils::DoubleToWideString(shadowOriginY)).c_str());
}
// write shadow
if (m_shadow.GetAttributeCount() > 0)
{
if (shadowBoolean.fShadow)
{
appendValueAttribute(&m_shadow, L"on", L"t" );
}
m_pXmlWriter->WriteString(m_shadow.GetXMLString().c_str());
}
//write 3d style
if (m_3dstyle.GetAttributeCount() > 0)
{
appendValueAttribute(&m_3dstyle, L"v:ext", L"view" );
appendValueAttribute(&m_3dstyle, L"on", L"t" );
//write the viewpoint
if ( ( ViewPointX != 0 ) || ( ViewPointY != 0 ) || ( ViewPointZ != 0 ) )
{
std::wstring viewPoint;
if ( ViewPointX != 0 )
{
viewPoint += FormatUtils::IntToWideString( ViewPointX ) + L"pt";
}
viewPoint += L",";
if ( ViewPointY != 0 )
{
viewPoint += FormatUtils::IntToWideString( ViewPointY ) + L"pt";
}
viewPoint += L",";
if ( ViewPointZ != 0 )
{
viewPoint += FormatUtils::IntToWideString( ViewPointZ ) + L"pt";
}
appendValueAttribute(&m_3dstyle, L"viewpoint", viewPoint.c_str());
}
// write the viewpointorigin
if ( ( viewPointOriginX != 0 ) || ( viewPointOriginY != 0 ) )
{
std::wstring viewPointOrigin;
if ( viewPointOriginX != 0 )
{
viewPointOrigin += FormatUtils::DoubleToFormattedWideString( viewPointOriginX, L"%.2f" );
}
if ( viewPointOriginY != 0 )
{
viewPointOrigin += L",";
viewPointOrigin += FormatUtils::DoubleToFormattedWideString( viewPointOriginY, L"%.2f" );
}
appendValueAttribute(&m_3dstyle, L"viewpointorigin", viewPointOrigin.c_str());
}
m_pXmlWriter->WriteString(m_3dstyle.GetXMLString().c_str());
}
// write wrap
if (m_pSpa)
{
std::wstring wrap = getWrapType(m_pSpa);
if (wrap != L"through")
{
m_pXmlWriter->WriteNodeBegin( L"w10:wrap", true );
m_pXmlWriter->WriteAttribute( L"type", wrap.c_str() );
m_pXmlWriter->WriteNodeEnd ( L"w10:wrap", true );
}
}
// write fill
if (m_fill.GetAttributeCount())
{
m_pXmlWriter->WriteString(m_fill.GetXMLString().c_str());
}
// write imagedata
if (m_imagedata.GetAttributeCount())
{
m_pXmlWriter->WriteString(m_imagedata.GetXMLString().c_str());
}
if ( pShape->fBackground )
{
WriteEndShapeNode(pShape);
return;
}
// write stroke
if (m_stroke.GetAttributeCount())
{
m_pXmlWriter->WriteString(m_stroke.GetXMLString().c_str());
}
// text path
if (m_textpath.GetAttributeCount())
{
appendValueAttribute(&m_textpath, L"style", FormatUtils::XmlEncode(m_textPathStyle).c_str());
m_pXmlWriter->WriteString(m_textpath.GetXMLString().c_str());
}
if (freeform)
{
if (arrInscribe.size())
{
m_pXmlWriter->WriteNodeBegin(L"v:path", true);
m_pXmlWriter->WriteAttribute(L"textboxrect", arrInscribe[0]);
m_pXmlWriter->WriteNodeEnd(L"", true);
}
}
// TEXTBOX
OfficeArtClientTextbox* pTextBox = pContainer->FirstChildWithType<OfficeArtClientTextbox>();
if (pTextBox)
{
// Word text box
//Word appends a OfficeArtClientTextbox record to the container.
//This record stores the index of the textbox.
int nIndex = pTextBox->GetIndex();
if (nIndex)
{
TextboxMapping textboxMapping(m_context, nIndex - 1, m_pXmlWriter, m_pCaller);
textboxMapping.SetInset(ndxTextLeft, ndyTextTop, ndxTextRight, ndyTextBottom);
textboxMapping.SetTextboxStyle(sTextboxStyle);
m_context->_doc->Convert(&textboxMapping);
}
}
else if( hasTextbox )
{
//Open Office textbox
//Open Office doesn't append a OfficeArtClientTextbox record to the container.
//We don't know how Word gets the relation to the text, but we assume that the first textbox in the document
//get the index 0, the second textbox gets the index 1 (and so on).
if (-1 != nLTxID)
{
TextboxMapping textboxMapping(m_context, nLTxID - 1, m_pXmlWriter, m_pCaller);
textboxMapping.SetInset(ndxTextLeft, ndyTextTop, ndxTextRight, ndyTextBottom);
m_context->_doc->Convert(&textboxMapping);
}
else
{
TextboxMapping textboxMapping(m_context, m_pXmlWriter, m_pCaller);
textboxMapping.SetInset(ndxTextLeft, ndyTextTop, ndxTextRight, ndyTextBottom);
m_context->_doc->Convert(&textboxMapping);
}
}
WriteEndShapeNode(pShape);
// OLE
if (indexOLE >= 0 && pShape->fOleShape) //4571833.doc
{
XMLTools::CStringXmlWriter txtBoxWrapper;
TextboxMapping textboxMapping(m_context, (indexOLE >> 16) - 1, &txtBoxWrapper, m_pCaller);
textboxMapping.m_shapeIdOwner = m_shapeId;
m_context->_doc->Convert(&textboxMapping);
m_pXmlWriter->WriteString(textboxMapping.getOLEObject());
}
//ShapeType
if (NULL != pShape->GetShapeType() /* && !m_isInlineShape*/) //bullete only???
{
VMLShapeTypeMapping oXmlMapper(m_pXmlWriter, m_isInlineShape);
pShape->GetShapeType()->Convert(&oXmlMapper);
}
}
//
void VMLShapeMapping::WriteBeginShapeNode (const Shape* pShape)
{
if (NULL != pShape)
{
if (pShape->fBackground)
{
m_pXmlWriter->WriteNodeBegin( L"v:background", true );
}
else if (pShape->is<OvalType>())
{
m_pXmlWriter->WriteNodeBegin( L"v:oval", true );
}
else if (pShape->is<RoundedRectangleType>())
{
m_pXmlWriter->WriteNodeBegin( L"v:roundrect", true );
}
else if (pShape->is<RectangleType>())
{
m_pXmlWriter->WriteNodeBegin( L"v:rect", true );
}
else if (pShape->is<LineType>())
{
m_pXmlWriter->WriteNodeBegin(L"v:line", true);
}
else
{
m_pXmlWriter->WriteNodeBegin(L"v:shape", true);
}
}
}
void VMLShapeMapping::WriteEndShapeNode (const Shape* pShape)
{
if (NULL != pShape)
{
if (pShape->fBackground)
{
m_pXmlWriter->WriteNodeEnd( L"v:background" );
}
else if (pShape->is<OvalType>())
{
m_pXmlWriter->WriteNodeEnd( L"v:oval" );
}
else if (pShape->is<RoundedRectangleType>())
{
m_pXmlWriter->WriteNodeEnd( L"v:roundrect" );
}
else if (pShape->is<RectangleType>())
{
m_pXmlWriter->WriteNodeEnd( L"v:rect" );
}
else if (pShape->is<LineType>())
{
m_pXmlWriter->WriteNodeEnd( L"v:line" );
}
else
{
m_pXmlWriter->WriteNodeEnd( L"v:shape" );
}
}
}
std::wstring VMLShapeMapping::GetShapeID(const Shape* pShape) const
{
std::wstring strXmlAttr;
if (NULL != pShape)
{
strXmlAttr += std::wstring(L"_x0000_s");
strXmlAttr += FormatUtils::IntToWideString(pShape->GetShapeID());
}
return strXmlAttr;
}
std::wstring VMLShapeMapping::GetLineFrom(const ChildAnchor* pAnchor) const
{
//Если линия находится в группе, то координаты должны быть в Twips
//Если линия находится в группе, то координаты должны быть в других единицах измерения (например в twips)
std::wstring strXmlFrom;
if (NULL != pAnchor)
{
strXmlFrom += FormatUtils::IntToWideString(pAnchor->rcgBounds.topLeftAngle.x);
strXmlFrom += L",";
strXmlFrom += FormatUtils::IntToWideString(pAnchor->rcgBounds.topLeftAngle.y);
}
else if (m_pSpa)
{
TwipsValue oLeft(m_pSpa->xaLeft);
TwipsValue oTop(m_pSpa->yaTop);
strXmlFrom += FormatUtils::DoubleToWideString(oLeft.ToPoints());
strXmlFrom += L"pt,";
strXmlFrom += FormatUtils::DoubleToWideString(oTop.ToPoints());
strXmlFrom += L"pt";
}
return strXmlFrom;
}
std::wstring VMLShapeMapping::GetLineTo(const ChildAnchor* pAnchor) const
{
//Если линия находится в группе, то координаты должны быть в других единицах измерения (например в twips)
std::wstring strXmlTo;
if (NULL != pAnchor)
{
strXmlTo += FormatUtils::IntToWideString(pAnchor->rcgBounds.topLeftAngle.x + pAnchor->rcgBounds.size.cx);
strXmlTo += L",";
strXmlTo += FormatUtils::IntToWideString(pAnchor->rcgBounds.topLeftAngle.y + pAnchor->rcgBounds.size.cy);
}
else if (m_pSpa)
{
TwipsValue oRight (m_pSpa->xaRight);
TwipsValue oBottom (m_pSpa->yaBottom);
strXmlTo += FormatUtils::DoubleToWideString(oRight.ToPoints());
strXmlTo += L"pt,";
strXmlTo += FormatUtils::DoubleToWideString(oBottom.ToPoints());
strXmlTo += L"pt";
}
return strXmlTo;
}
/// Build the VML wrapcoords string for a given pWrapPolygonVertices
std::wstring VMLShapeMapping::getWrapCoords(const OptionEntry& pWrapPolygonVertices) const
{
std::wstring coords;
MemoryStream oStream(pWrapPolygonVertices.opComplex, pWrapPolygonVertices.op);
std::list<int> arrVertices;
unsigned short nElems = oStream.ReadUInt16();
unsigned short nElemsAlloc = oStream.ReadUInt16();
unsigned short cbElem = oStream.ReadUInt16();
if ( ( nElems > 0 ) && ( cbElem > 0 ) && ( nElems <= nElemsAlloc ) )
{
//!!!TODO: read the Int32 coordinates!!!
while (oStream.GetPosition() < oStream.GetSize())
{
arrVertices.push_back(oStream.ReadInt32());
}
std::list<int>::const_iterator end = arrVertices.end();
for (std::list<int>::const_iterator iter = arrVertices.begin(); iter != end; ++iter)
{
coords += FormatUtils::IntToWideString(*iter);
coords += L",";
}
coords.erase(coords.size() - 1);
}
return coords;
}
/// Copies the picture from the binary stream to the zip archive
/// and creates the relationships for the image.
bool VMLShapeMapping::copyPicture(const BlipStoreEntry* oBlip)
{
bool result = false;
//write the blip
if (oBlip)
{
VirtualStreamReader reader(m_context->_doc->WordDocumentStream, oBlip->foDelay, m_context->_doc->FIB->m_bOlderVersion);
switch (oBlip->btWin32)
{
case Global::msoblipEMF:
case Global::msoblipWMF:
{
//it's a meta image
MetafilePictBlip* metaBlip = static_cast<MetafilePictBlip*>(RecordFactory::ReadRecord(&reader, 0));
if (metaBlip)
{
//meta images can be compressed
unsigned char* decompressed = NULL;
int decompressedSize = 0;
decompressedSize = metaBlip->Decompress(&decompressed);
if (0 != decompressedSize && NULL != decompressed)
{
m_context->_docx->ImagesList.push_back(ImageFileStructure(GetTargetExt(oBlip->btWin32), std::vector<unsigned char>(decompressed, (decompressed + decompressedSize))));
RELEASEARRAYOBJECTS(decompressed);
}
RELEASEOBJECT(metaBlip);
}
}
break;
case Global::msoblipJPEG:
case Global::msoblipCMYKJPEG:
case Global::msoblipPNG:
case Global::msoblipTIFF:
case Global::msoblipDIB:
{
//it's a bitmap image
BitmapBlip* bitBlip = static_cast<BitmapBlip*>(RecordFactory::ReadRecord(&reader, 0));
if ((bitBlip) && (bitBlip->m_pvBits))
{
m_context->_docx->ImagesList.push_back(ImageFileStructure(GetTargetExt(oBlip->btWin32),
std::vector<unsigned char>(bitBlip->m_pvBits, (bitBlip->m_pvBits + bitBlip->pvBitsSize)), oBlip->btWin32));
RELEASEOBJECT (bitBlip);
}
}
break;
default:
{
result = false;
return result;
}
break;
}
m_nImageId = m_context->_docx->RegisterImage (m_pCaller, oBlip->btWin32);
result = true;
}
return result;
}
std::wstring VMLShapeMapping::GetTargetExt(Global::BlipType _type) const
{
switch ( _type )
{
case Global::msoblipDIB:
return std::wstring( L".bmp" );
case Global::msoblipEMF:
return std::wstring( L".emf" );
//case msoblipGIF:
// return std::wstring( L".gif" );
//case msoblipICON:
// return std::wstring( L".ico" );
case Global::msoblipJPEG:
case Global::msoblipCMYKJPEG:
return std::wstring( L".jpg" );
//case msoblipPCX:
// return std::wstring( L".pcx" );
case Global::msoblipPNG:
return std::wstring( L".png" );
case Global::msoblipTIFF:
return std::wstring( L".tif" );
case Global::msoblipWMF:
return std::wstring( L".wmf" );
default:
return std::wstring( L".png" );
}
}
void VMLShapeMapping::AppendDimensionToStyle(std::wstring* style, const PictureDescriptor* pict, bool twistDimensions) const
{
if ( ( style != NULL ) && ( pict != NULL ) )
{
double xScaling = pict->mx / 1000.0;
double yScaling = pict->my / 1000.0;
TwipsValue width( ( pict->dxaGoal - ( pict->dxaCropLeft + pict->dxaCropRight ) ) * xScaling );
TwipsValue height( ( pict->dyaGoal - ( pict->dyaCropTop + pict->dyaCropBottom ) ) * yScaling );
if ( twistDimensions )
{
width = TwipsValue( ( pict->dyaGoal - ( pict->dyaCropTop + pict->dyaCropBottom ) ) * yScaling );
height = TwipsValue( ( pict->dxaGoal - ( pict->dxaCropLeft + pict->dxaCropRight ) ) * xScaling );
}
std::wstring widthString = FormatUtils::DoubleToWideString( width.ToPoints() );
std::wstring heightString = FormatUtils::DoubleToWideString( height.ToPoints() );
style->operator += ( std::wstring( L"width:" ) + widthString + std::wstring( L"pt;" ) );
style->operator += ( std::wstring( L"height:" ) + heightString + std::wstring( L"pt;" ) );
}
}
void VMLShapeMapping::AppendDimensionToStyle(std::wstring* style, const Spa* pSpa, bool twistDimensions) const
{
if ( ( style != NULL ) && (pSpa != NULL ) )
{
//append size and position ...
//if (pSpa->fAnchorLock )
//if (pSpa->bx == TEXT && pSpa->by == TEXT)
//{
// appendStyleProperty( style, L"position", L"static" );
//}
//else
//{
appendStyleProperty( style, L"position", L"absolute" );
//}
TwipsValue left (pSpa->xaLeft);
TwipsValue top (pSpa->yaTop);
TwipsValue width (pSpa->xaRight - pSpa->xaLeft);
TwipsValue height(pSpa->yaBottom - pSpa->yaTop);
if (twistDimensions)
{
width = TwipsValue(pSpa->yaBottom - pSpa->yaTop);
height = TwipsValue(pSpa->xaRight - pSpa->xaLeft);
left = TwipsValue((pSpa->xaRight + pSpa->xaLeft) * 0.5 - (pSpa->yaBottom - pSpa->yaTop) * 0.5);
top = TwipsValue((pSpa->yaBottom + pSpa->yaTop) * 0.5 - (pSpa->xaRight - pSpa->xaLeft) * 0.5);
}
appendStyleProperty (style, L"margin-left", ( FormatUtils::DoubleToWideString(left.ToPoints()) + std::wstring( L"pt" ) ));
appendStyleProperty (style, L"margin-top", ( FormatUtils::DoubleToWideString(top.ToPoints()) + std::wstring( L"pt" ) ));
appendStyleProperty (style, L"width", ( FormatUtils::DoubleToWideString(width.ToPoints()) + std::wstring( L"pt" ) ));
appendStyleProperty (style, L"height", ( FormatUtils::DoubleToWideString(height.ToPoints()) + std::wstring( L"pt" ) ));
}
}
void VMLShapeMapping::AppendDimensionToStyle(std::wstring* style, const ChildAnchor* anchor, bool twistDimensions) const
{
if ((style != NULL) && (anchor != NULL))
{
DocFormatUtils::Rectangle bounds = anchor->rcgBounds;
if (twistDimensions)
{
bounds.topLeftAngle.x = static_cast<LONG>(((anchor->Right + anchor->Left) * 0.5 - (anchor->Bottom - anchor->Top) * 0.5));
bounds.topLeftAngle.y = static_cast<LONG>(((anchor->Bottom + anchor->Top) * 0.5 - (anchor->Right - anchor->Left) * 0.5));
}
appendStyleProperty(style, L"position", L"absolute");
appendStyleProperty(style, L"left", FormatUtils::IntToWideString(bounds.topLeftAngle.x));
appendStyleProperty(style, L"top", FormatUtils::IntToWideString(bounds.topLeftAngle.y));
if (twistDimensions)
{
appendStyleProperty(style, L"width", FormatUtils::IntToWideString(bounds.size.cy));
appendStyleProperty(style, L"height", FormatUtils::IntToWideString(bounds.size.cx));
}
else
{
appendStyleProperty(style, L"width", FormatUtils::IntToWideString(bounds.size.cx));
appendStyleProperty(style, L"height", FormatUtils::IntToWideString(bounds.size.cy));
}
}
}
void VMLShapeMapping::appendStyleProperty(std::wstring* b, const std::wstring& propName, const std::wstring& propValue) const
{
if ( b != NULL )
{
b->operator += ( propName );
b->operator += ( L":" );
b->operator += ( propValue );
b->operator +=( L";" );
}
}
std::wstring VMLShapeMapping::getTextboxAnchor(unsigned int anchor) const
{
switch ( anchor )
{
case 0: return L"top";
case 1: return L"middle";
case 2: return L"bottom";
case 3: return L"top-center";
case 4: return L"middle-center";
case 5: return L"bottom-center";
case 6: return L"top-baseline";
case 7: return L"bottom-baseline";
case 8: return L"top-center-baseline";
case 9: return L"bottom-center-baseline";
default:
return L"top";
}
}
std::wstring VMLShapeMapping::mapVerticalPosition(PositionVertical vPos)
{
switch ( vPos )
{
/*case msopvAbs: return L"absolute" );*/
case msopvTop: return L"top";
case msopvCenter: return L"center";
case msopvBottom: return L"bottom";
case msopvInside: return L"inside";
case msopvOutside: return L"outside";
default:
return L"absolute";
}
}
std::wstring VMLShapeMapping::mapVerticalPositionRelative(int vRel_)
{
PositionVerticalRelative vRel = (PositionVerticalRelative)vRel_;
switch ( vRel )
{
case msoprvMargin: return L"margin";
case msoprvPage: return L"page";
case msoprvText: return L"text";
case msoprvLine: return L"line";
default:
return L"margin";
}
}
std::wstring VMLShapeMapping::mapHorizontalPosition(PositionHorizontal hPos)
{
switch ( hPos )
{
/*case msophAbs: return L"absolute";*/
case msophLeft: return L"left";
case msophCenter: return L"center";
case msophRight: return L"right";
case msophInside: return L"inside";
case msophOutside: return L"outside";
default:
return L"absolute";
}
}
std::wstring VMLShapeMapping::mapHorizontalPositionRelative(int hRel_ )
{
PositionHorizontalRelative hRel = (PositionHorizontalRelative )hRel_;
switch ( hRel )
{
case msoprhMargin: return L"margin";
case msoprhPage: return L"page";
case msoprhText: return L"text";
case msoprhChar: return L"char";
default:
return L"margin";
}
}
void VMLShapeMapping::AppendOptionsToStyle (std::wstring* oStyle, const std::list<OptionEntry>& options, int zIndex) const
{
bool bRelH = false;
bool bRelV = false;
bool bPosH = false;
bool bPosV = false;
bool bZIndex = false;
std::list<OptionEntry>::const_iterator end = options.end();
for (std::list<OptionEntry>::const_iterator iter = options.begin(); iter != end; ++iter)
{
switch (iter->pid)
{
// POSITIONING
case posh:
{
appendStyleProperty(oStyle, L"mso-position-horizontal", mapHorizontalPosition((PositionHorizontal)iter->op));
bPosH = true;
}break;
case posrelh:
{
appendStyleProperty(oStyle, L"mso-position-horizontal-relative", mapHorizontalPositionRelative((PositionHorizontalRelative)iter->op));
bRelH = true;
}break;
case posv:
{
appendStyleProperty(oStyle, L"mso-position-vertical", mapVerticalPosition((PositionVertical)iter->op));
bPosV = true;
}break;
case posrelv:
{
appendStyleProperty(oStyle, L"mso-position-vertical-relative", mapVerticalPositionRelative((PositionVerticalRelative)iter->op));
bRelV = true;
}break;
// BOOLEANS
case groupShapeBooleans:
{
GroupShapeBooleanProperties groupShapeBooleans(iter->op);
if (groupShapeBooleans.fUsefBehindDocument && groupShapeBooleans.fBehindDocument && !bZIndex)
{
//The shape is behind the text, so the z-index must be negative.
appendStyleProperty(oStyle, L"z-index", L"-1" );
bZIndex = true;
}
else if (!m_isInlineShape && !bZIndex)
{
appendStyleProperty( oStyle, L"z-index", FormatUtils::IntToWideString(zIndex + 0x7ffff));
bZIndex = true;
}
if (groupShapeBooleans.fHidden && groupShapeBooleans.fUsefHidden)
{
appendStyleProperty(oStyle, L"visibility", L"hidden" );
}
}break;
// GEOMETRY
case PropertyId_rotation:
{
double dAngle = (double)((int)iter->op) / 65535.0;
if (dAngle < -360.0)
dAngle += 360.0;
appendStyleProperty(oStyle, L"rotation", FormatUtils::DoubleToWideString(dAngle));
}break;
// TEXTBOX
case anchorText:
{
appendStyleProperty(oStyle, L"v-text-anchor", getTextboxAnchor(iter->op));
}break;
// WRAP DISTANCE
case dxWrapDistLeft:
{
appendStyleProperty(oStyle, L"mso-wrap-distance-left", (FormatUtils::DoubleToWideString(EmuValue((int)iter->op).ToPoints()) + std::wstring(L"pt")));
}break;
case dxWrapDistRight:
{
appendStyleProperty(oStyle, L"mso-wrap-distance-right", (FormatUtils::DoubleToWideString(EmuValue((int)iter->op).ToPoints()) + std::wstring(L"pt")));
}break;
case dyWrapDistBottom:
{
appendStyleProperty(oStyle, L"mso-wrap-distance-bottom", (FormatUtils::DoubleToWideString(EmuValue((int)iter->op).ToPoints()) + std::wstring(L"pt")));
}break;
case dyWrapDistTop:
{
appendStyleProperty(oStyle, L"mso-wrap-distance-top", (FormatUtils::DoubleToWideString(EmuValue((int)iter->op).ToPoints()) + std::wstring(L"pt")));
}break;
}
}
if (!bRelH && m_pSpa)
{
appendStyleProperty(oStyle, L"mso-position-horizontal-relative", mapHorizontalPositionRelative(m_pSpa->bx));
}
if (!bRelV && m_pSpa)
{
appendStyleProperty(oStyle, L"mso-position-vertical-relative", mapVerticalPositionRelative(m_pSpa->bx));
}
if (!m_isInlineShape && !bZIndex)
{
appendStyleProperty( oStyle, L"z-index", FormatUtils::IntToWideString(zIndex + 0x7ffff));
bZIndex = true;
}
//if (!bPosH)
//{
// appendStyleProperty(oStyle, L"mso-position-horizontal", L"absolute" );
//}
//if (!bPosV)
//{
// appendStyleProperty(oStyle, L"mso-position-vertical", L"absolute" );
//}
}
//
std::wstring VMLShapeMapping::buildStyle (const Shape* shape, const ChildAnchor* anchor, const std::list<OptionEntry>& options, int zIndex) const
{
std::wstring style;
// Check if some properties are set that cause the dimensions to be twisted
bool twistDimensions = false;
std::list<OptionEntry>::const_iterator end = options.end();
for (std::list<OptionEntry>::const_iterator iter = options.begin(); iter != end; ++iter)
{
if (geometryTextBooleanProperties == iter->pid)
{
GeometryTextBooleanProperties props(iter->op);
if (props.fUsegtextFVertical && props.gtextFVertical)
{
twistDimensions = true;
}
}
if (PropertyId_rotation == iter->pid)
{
double dAngle = (double)((int)iter->op) / 65535.0;
if (dAngle < -360.0)
dAngle += 360.0;
if ((dAngle >= 45.0 && dAngle <= 135.0) || (dAngle >= 225.0 && dAngle <= 315.0) || (dAngle <= -45.0 && dAngle >= -135.0) || (dAngle <= -225.0 && dAngle >= -315.0))
twistDimensions = true;
}
}
//don't append the dimension info to lines,
// because they have "from" and "to" attributes to decline the dimension
if(!shape->is<LineType>())
{
if ( (m_pSpa != NULL) && ( anchor == NULL ) )
{
//this shape is placed directly in the document,
//so use the FSPA to build the style
AppendDimensionToStyle(&style, m_pSpa, twistDimensions);
}
else if (anchor)
{
//the style is part of a group,
//so use the anchor
AppendDimensionToStyle(&style, anchor, twistDimensions);
}
else if (m_pict)
{
// it is some kind of PICT shape (e.g. WordArt)
AppendDimensionToStyle(&style, m_pict, twistDimensions);
}
}
else
{
//если не написать тип позиции, то будет inline
if ( anchor != NULL )
{
appendStyleProperty( &style, L"position", L"absolute" );
}
else if (m_pSpa)
{
//append size and position ...
//if (m_pSpa->fAnchorLock)//это возможность смены привязки , а не ее тип
//if (m_pSpa->bx == TEXT && m_pSpa->by == TEXT)
//{
// appendStyleProperty( &style, L"position", L"static" );
//}
//else
{
appendStyleProperty( &style, L"position", L"absolute" );
}
}
}
if ( shape->fFlipH )
{
appendStyleProperty( &style, L"flip", L"x" );
}
if ( shape->fFlipV )
{
appendStyleProperty( &style, L"flip", L"y" );
}
AppendOptionsToStyle( &style, options, zIndex );
return style;
}
std::wstring VMLShapeMapping::getLineStyle(unsigned int p) const
{
switch (p)
{
case 0: return L"single";
case 1: return L"thinThin";
case 2: return L"thinThick";
case 3: return L"thickThin";
case 4: return L"thickBetweenThin";
default: return L"single";
}
}
std::wstring VMLShapeMapping::getArrowStyle(unsigned int op) const
{
switch ( op )
{
default: return L"none";
case 1: return L"block";
case 2: return L"classic";
case 3: return L"diamond";
case 4: return L"oval";
case 5: return L"open";
}
}
std::wstring VMLShapeMapping::getArrowLength(unsigned int op) const
{
switch ( op )
{
default: return L"short";
case 1: return L"medium";
case 2: return L"long";
}
}
std::wstring VMLShapeMapping::getArrowWidth(unsigned int op) const
{
switch ( op )
{
default: return L"narrow";
case 1: return L"medium";
case 2: return L"wide";
}
}
std::wstring VMLShapeMapping::getFillMethod(unsigned int p) const
{
short val = (short)( ( p & 0xFFFF0000 ) >> 28 );
switch ( val )
{
case 0: return L"none";
case 1: return L"any";
case 2: return L"linear";
case 4: return L"linear sigma";
default:
return L"any";
}
}
std::wstring VMLShapeMapping::getFillColorString(const unsigned char* p, unsigned int size) const
{
std::wstring result;
if ( ( p != NULL ) && ( size > 0 ) )
{
// parse the IMsoArray
unsigned short nElems = FormatUtils::BytesToUInt16(p, 0, size);
unsigned short nElemsAlloc = FormatUtils::BytesToUInt16(p, 2, size);
unsigned short cb = FormatUtils::BytesToUInt16(p, 4, size);
for ( unsigned short i = 0; i < nElems; i++ )
{
int pos = ( 6 + ( i * cb ) );
RGBColor color(FormatUtils::BytesToInt32(p, pos, size ), RedFirst);
int colorPos = FormatUtils::BytesToInt32(p, ( pos + 4 ), size);
result += FormatUtils::IntToWideString(colorPos);
result += L"f #";
result += color.SixDigitHexCode;
result += L";";
}
}
return result;
}
/// Returns the OpenXML fill type of a fill effect
std::wstring VMLShapeMapping::getFillType(unsigned int p) const
{
switch ( p )
{
case 0: return L"solid";
case 1: return L"pattern";
case 2: return L"tile";
case 3: return L"frame";
case 4: return L"gradient";
case 5: return L"gradientRadial";
case 6: return L"gradientRadial";
case 7: return L"gradient";
case 9:
default:
return L"solid";
}
}
std::wstring VMLShapeMapping::getShadowType(unsigned int p) const
{
switch ( p )
{
case 0: return L"single";
case 1: return L"double";
case 2: return L"perspective";
case 3: return L"shaperelative";
case 4: return L"drawingrelative";
case 5: return L"emboss";
default:
return L"single";
}
}
/// Returns the OpenXML wrap type of the shape
std::wstring VMLShapeMapping::getWrapType (const Spa* pSpa) const
{
// spec values
// 0 = like 2 but doesn't equire absolute object
// 1 = no text next to shape
// 2 = wrap around absolute object
// 3 = wrap as if no object present
// 4 = wrap tightly areound object
// 5 = wrap tightly but allow holes
std::wstring wrapType = L"none";
if (pSpa != NULL)
{
switch (pSpa->wr)
{
case 0:
case 2: wrapType = L"square";
case 1: wrapType = L"topAndBottom";
case 3: wrapType = L"through";
case 4:
case 5: wrapType = L"tight";
default:
wrapType = L"none";
}
}
return wrapType;
}
std::wstring VMLShapeMapping::ParsePath (const std::list<OptionEntry>& options) const
{
const unsigned char* pVP = NULL;
unsigned int nVP = 0;
const unsigned char* pSI = NULL;
unsigned int nSI = 0;
std::list<OptionEntry>::const_iterator end = options.end();
for (std::list<OptionEntry>::const_iterator iter = options.begin(); iter != end; ++iter)
{
if (iter->pid == pVertices)
{
pVP = iter->opComplex;
nVP = iter->op;
}
if (iter->pid == pSegmentInfo)
{
pSI = iter->opComplex;
nSI = iter->op;
}
}
PathParser oParser (pSI, nSI, pVP, nVP);
return oParser.GetVmlPath();
}
//
std::vector<std::wstring> VMLShapeMapping::GetTextRectangles(const OptionEntry& inscribe) const
{
MemoryStream reader(inscribe.opComplex, inscribe.op + 6);
unsigned short elems = reader.ReadUInt16();
unsigned short allocElems = reader.ReadUInt16();
unsigned short cb = reader.ReadUInt16();
std::vector<std::wstring> rectangles;
if (16 != cb) return rectangles; // TODO: доделать
int count = (inscribe.op) / 16;
for (int i = 0; i < count; ++i)
{
RECT rc;
rc.top = reader.ReadInt32();
rc.left = reader.ReadInt32();
rc.right = reader.ReadInt32();
rc.bottom = reader.ReadInt32();
std::wstringstream sstream;
sstream << boost::wformat(L"%d,%d,%d,%d") % rc.top % rc.left % rc.right % rc.bottom;
rectangles.push_back(sstream.str());
}
return rectangles;
}
//------------------------------------------------------------------------------------------------------
void VMLShapeMapping::ApplyPrimitives(DrawingPrimitives * primitives)
{
int index = 0;
while(true)
{
index = ApplyPrimitive(primitives, index);
if (index > primitives->size() - 1)
break;
}
}
static int currentTextBoxIndex = 1;
int VMLShapeMapping::ApplyPrimitive(DrawingPrimitives * primitives, int index)
{
if (!primitives) return index++;
if (index >= primitives->size()) return index++;
DrawingPrimitive *primitive = dynamic_cast<DrawingPrimitive *>(primitives->at(index));
m_pXmlWriter->WriteNodeBegin(primitive->strVmlType.c_str(), true );
if (primitive->type == 0x0007)
{
DrawingPrimitiveCTextBox * callout = dynamic_cast<DrawingPrimitiveCTextBox *>(primitive);
if ((callout) && (callout->txbx))
{
//временно обычный текстбокс
callout->txbx->xa += callout->xa;
callout->txbx->ya += callout->ya;
WritePrimitiveProps(dynamic_cast<DrawingPrimitive*>(callout->txbx), (index==0?true:false));
}
//todooo нарисовать кастомный шейп
}
else
WritePrimitiveProps(primitive, (index==0?true:false));
if (primitive->type == 0x0000)
{
index++;
while(true)
{
if (index > primitives->size() - 1)
break;
primitive = dynamic_cast<DrawingPrimitive *>(primitives->at(index));
if (primitive->type == 0x0008)
{
break;
}
index = ApplyPrimitive(primitives, index);
}
}
if (primitive->type == 0x0002 || primitive->type == 0x0007)
{
int nLTxID = currentTextBoxIndex++;;
if (-1 != nLTxID)
{
TextboxMapping textboxMapping(m_context, nLTxID - 1, m_pXmlWriter, m_pCaller);
//textboxMapping.SetInset(ndxTextLeft, ndyTextTop, ndxTextRight, ndyTextBottom);
m_context->_doc->Convert(&textboxMapping);
}
}
m_pXmlWriter->WriteNodeEnd( primitive->strVmlType.c_str() );
index++;
return index;
}
void VMLShapeMapping::WritePrimitiveProps (DrawingPrimitive * primitive, bool root)
{
TwipsValue x( primitive->xa );
TwipsValue y( primitive->ya );
TwipsValue w( primitive->dxa );
TwipsValue h( primitive->dya );
std::wstring strId = std::wstring(L"_x0000_s") + FormatUtils::IntToWideString(1024 + count_vml_objects);
count_vml_objects++;
//m_pXmlWriter->WriteAttribute ( L"id") , strId.c_str());
m_pXmlWriter->WriteAttribute ( L"o:spid", strId.c_str());
std::wstring strStyle = L"position:absolute;visibility:visible;mso-wrap-style:square;";
DrawingPrimitiveLine * line = dynamic_cast<DrawingPrimitiveLine *>(primitive);
if (line)
{
TwipsValue x1( line->xaStart );
TwipsValue y1( line->yaStart );
TwipsValue x2( line->xaEnd );
TwipsValue y2( line->yaEnd );
std::wstring strStart = FormatUtils::IntToWideString(line->xaStart + primitive->xa) + L"," + FormatUtils::IntToWideString(line->yaStart + primitive->ya);
std::wstring strEnd = FormatUtils::IntToWideString(line->xaEnd + primitive->xa) + L"," + FormatUtils::IntToWideString(line->yaEnd + primitive->ya);
m_pXmlWriter->WriteAttribute(L"from", strStart.c_str() );
m_pXmlWriter->WriteAttribute(L"to", strEnd.c_str());
}
else
{
if (root)
{
//strStyle += L"left:" + FormatUtils::IntToWideString( x.ToPoints()) + L"pt;";
//strStyle += L"top:" + FormatUtils::IntToWideString( y.ToPoints()) + L"pt;";
strStyle += L"width:" + FormatUtils::IntToWideString( w.ToPoints()) + L"pt;";
strStyle += L"height:" + FormatUtils::IntToWideString( h.ToPoints()) + L"pt;";
strStyle += L"margin-left:" + FormatUtils::IntToWideString( x.ToPoints()) + L"pt;";
strStyle += L"margin-top:" + FormatUtils::IntToWideString( y.ToPoints()) + L"pt;";
std::wstring xMargin;
std::wstring yMargin;
if (m_pSpa->bx == PAGE) xMargin = L"page;";
if (m_pSpa->by == PAGE) yMargin = L"page;";
if (m_pSpa->bx == MARGIN) xMargin = L"margin;";
if (m_pSpa->by == MARGIN) yMargin = L"margin;";
if (!xMargin.empty()) strStyle += L"mso-position-horizontal-relative:" + xMargin;
if (!yMargin.empty()) strStyle += L"mso-position-vertical-relative:" + yMargin;
std::wstring strSize = FormatUtils::IntToWideString(primitive->dxa) + L"," + FormatUtils::IntToWideString(primitive->dya);
std::wstring strOrigin = FormatUtils::IntToWideString(primitive->xa) + L"," + FormatUtils::IntToWideString(primitive->ya);
m_pXmlWriter->WriteAttribute( L"coordsize", strSize.c_str());
//m_pXmlWriter->WriteAttribute( L"coordorigin"), strOrigin.c_str());
}
else
{
strStyle += L"left:" + FormatUtils::IntToWideString( primitive->xa) + L";";
strStyle += L"top:" + FormatUtils::IntToWideString( primitive->ya) + L";";
strStyle += L"width:" + FormatUtils::IntToWideString( primitive->dxa) + L";";
strStyle += L"height:" + FormatUtils::IntToWideString( primitive->dya) + L";";
}
}
if (primitive->fillPattern == 0)
m_pXmlWriter->WriteAttribute( L"filled", L"f");
if (primitive->type > 1)
{
m_pXmlWriter->WriteAttribute( L"fillColor", FormatUtils::IntToFormattedWideString(primitive->fillFore, L"#%06x").c_str());
}
m_pXmlWriter->WriteAttribute( L"style", strStyle.c_str());
std::wstring strStrokeWeight = FormatUtils::IntToWideString(primitive->lineWeight / 20) + L"pt";
if (primitive->lineWeight > 20)
m_pXmlWriter->WriteAttribute( L"strokeweight", strStrokeWeight.c_str());
if (primitive->type > 0)
m_pXmlWriter->WriteAttribute( L"strokecolor", FormatUtils::IntToFormattedWideString(primitive->lineColor, L"#%06x").c_str());
m_pXmlWriter->WriteNodeEnd( L"", true, false );
if (primitive->type > 1 && primitive->fillPattern > 1)
{
m_pXmlWriter->WriteNodeBegin(L"v:fill", true );
m_pXmlWriter->WriteAttribute( L"color2", FormatUtils::IntToFormattedWideString(primitive->fillBack, L"#%06x").c_str());
m_pXmlWriter->WriteAttribute( L"type", L"pattern");
m_pXmlWriter->WriteNodeEnd( L"", true, false );
m_pXmlWriter->WriteNodeEnd( L"v:fill" );
}
if (primitive->lineStyle > 1)
{
m_pXmlWriter->WriteNodeBegin(L"v:stroke", true );
std::wstring strDashStyle = FormatUtils::IntToWideString(primitive->lineStyle) + L" 1";
m_pXmlWriter->WriteAttribute( L"dashstyle", strDashStyle.c_str());
m_pXmlWriter->WriteNodeEnd( L"", true, false );
m_pXmlWriter->WriteNodeEnd( L"v:stroke" );
}
}
}