summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorMarco Cecchetti <mrcekets@gmail.com>2012-08-11 22:23:22 +0200
committerThorsten Behrens <tbehrens@suse.com>2012-10-10 12:03:28 +0200
commitb76628acb1ae4fc06f8c1b70ec2e0cf39356deef (patch)
tree23d2bc9d6e763c601db80e38bf4901dcdd5a4474 /filter
parent5626e723945eb39ed211a26ba5386ee486b8a4e8 (diff)
text export support for bullets and hyperlinks
SVGFilter: - new: implExportTextShapeIndex, implEmbedBulletGlyphs, implEmbedBulletGlyph, implExportTextEmbeddedBitmaps - modified: implExportShape, implCreateObjectsFromShapes, implCreateObjectsFromShape SVGActionWriter: - new: GetChecksum - modified: ImplWriteActions, WriteMetaFile SVGTextWriter: -new: implExportHyperlinkIds, implWriteBulletChars, writeBitmapPlaceholder, implWriteEmbeddedBitmaps, setTextShape, implRegisterInterface, implGetValidIDFromInterface -modified: nextParagraph, nextTextPortion, startTextShape, endTextShape, startTextParagraph, endTextParagraph, writeTextPortion, implWriteTextPortion
Diffstat (limited to 'filter')
-rw-r--r--filter/source/svg/svgexport.cxx234
-rw-r--r--filter/source/svg/svgfilter.hxx79
-rw-r--r--filter/source/svg/svgwriter.cxx641
-rw-r--r--filter/source/svg/svgwriter.hxx103
4 files changed, 1022 insertions, 35 deletions
diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx
index ebb88e0ffc0d..ae2d6dc23403 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -89,6 +89,7 @@ static const char aOOOAttrDateTimeField[] = NSPREFIX "date-time-field";
static const char aOOOAttrFooterField[] = NSPREFIX "footer-field";
static const char aOOOAttrHeaderField[] = NSPREFIX "header-field";
static const char aOOOAttrHasTransition[] = NSPREFIX "has-transition";
+static const char aOOOAttrIdList[] = NSPREFIX "id-list";
// ooo xml attributes for pages and shapes
static const char aOOOAttrName[] = NSPREFIX "name";
@@ -800,12 +801,16 @@ sal_Bool SVGFilter::implExportDocument()
mpSVGFontExport = new SVGFontExport( *mpSVGExport, aObjects );
mpSVGWriter = new SVGActionWriter( *mpSVGExport, *mpSVGFontExport );
-
if( mpSVGExport->IsEmbedFonts() )
{
mpSVGFontExport->EmbedFonts();
}
-
+ if( !mpSVGExport->IsUsePositionedCharacters() )
+ {
+ implExportTextShapeIndex();
+ implEmbedBulletGlyphs();
+ implExportTextEmbeddedBitmaps();
+ }
implExportMasterPages( mMasterPageTargets, 0, mMasterPageTargets.getLength() - 1 );
implExportDrawPages( mSelectedPages, 0, nLastPage );
@@ -1138,6 +1143,154 @@ sal_Bool SVGFilter::implExportAnimations()
return bRet;
}
+// -----------------------------------------------------------------------------
+
+void SVGFilter::implExportTextShapeIndex()
+{
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextShapeIndex" ) );
+ SvXMLElementExport aDefsContainerElem( *mpSVGExport, XML_NAMESPACE_NONE, "defs", sal_True, sal_True );
+
+ sal_Int32 nCount = mSelectedPages.getLength();
+ for( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ const Reference< XDrawPage > & xDrawPage = mSelectedPages[i];
+ if( mTextShapeIdListMap.find( xDrawPage ) != mTextShapeIdListMap.end() )
+ {
+ OUString sTextShapeIdList = mTextShapeIdListMap[xDrawPage].trim();
+
+ Reference< XInterface > xRef( xDrawPage, UNO_QUERY );
+ const OUString& rPageId = implGetValidIDFromInterface( xRef );
+ if( !rPageId.isEmpty() && !sTextShapeIdList.isEmpty() )
+ {
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrSlide, rPageId );
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrIdList, sTextShapeIdList );
+ SvXMLElementExport aGElem( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void SVGFilter::implEmbedBulletGlyphs()
+{
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "EmbeddedBulletChars" ) );
+ SvXMLElementExport aDefsContainerElem( *mpSVGExport, XML_NAMESPACE_NONE, "defs", sal_True, sal_True );
+
+ OUString sPathData = B2UCONST( "M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z" );
+ implEmbedBulletGlyph( 57356, sPathData );
+ sPathData = B2UCONST( "M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z" );
+ implEmbedBulletGlyph( 57354, sPathData );
+ sPathData = B2UCONST( "M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z" );
+ implEmbedBulletGlyph( 10146, sPathData );
+ sPathData = B2UCONST( "M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z" );
+ implEmbedBulletGlyph( 10132, sPathData );
+ sPathData = B2UCONST( "M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z" );
+ implEmbedBulletGlyph( 10007, sPathData );
+ sPathData = B2UCONST( "M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z" );
+ implEmbedBulletGlyph( 10004, sPathData );
+ sPathData = B2UCONST( "M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z" );
+ implEmbedBulletGlyph( 9679, sPathData );
+ sPathData = B2UCONST( "M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z" );
+ implEmbedBulletGlyph( 8226, sPathData );
+ sPathData = B2UCONST( "M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z" );
+ implEmbedBulletGlyph( 8211, sPathData );
+}
+
+// -----------------------------------------------------------------------------
+
+void SVGFilter::implEmbedBulletGlyph( sal_Unicode cBullet, const ::rtl::OUString & sPathData )
+{
+ OUString sId = B2UCONST( "bullet-char-template(" );
+ sId += OUString::valueOf( (sal_Int32)cBullet );
+ sId += B2UCONST( ")" );
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sId );
+
+ double fFactor = 1.0 / 2048;
+ OUString sFactor = OUString::valueOf( fFactor );
+ OUString sTransform = B2UCONST( "scale(" );
+ sTransform += sFactor; sTransform += B2UCONST( ",-" ); sTransform += sFactor;
+ sTransform += B2UCONST( ")" );
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "transform", sTransform );
+
+ SvXMLElementExport aGElem( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
+
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "d", sPathData );
+ SvXMLElementExport aPathElem( *mpSVGExport, XML_NAMESPACE_NONE, "path", sal_True, sal_True );
+
+}
+
+// -----------------------------------------------------------------------------
+
+/** SVGFilter::implExportTextEmbeddedBitmaps
+ * We export bitmaps embedded into text shapes, such as those used by list
+ * items with image style, only once in a specic <defs> element.
+ */
+sal_Bool SVGFilter::implExportTextEmbeddedBitmaps()
+{
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextEmbeddedBitmaps" ) );
+ SvXMLElementExport aDefsContainerElem( *mpSVGExport, XML_NAMESPACE_NONE, "defs", sal_True, sal_True );
+
+ OUString sId;
+
+ MetaBitmapActionSet::const_iterator it = mEmbeddedBitmapActionSet.begin();
+ MetaBitmapActionSet::const_iterator end = mEmbeddedBitmapActionSet.end();
+ for( ; it != end; ++it)
+ {
+ const GDIMetaFile& aMtf = it->GetRepresentation();
+
+ if( aMtf.GetActionSize() == 1 )
+ {
+ MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*) aMtf.GetAction( 0 );
+ if( pAction )
+ {
+ sal_uLong nId = pAction->GetBitmapEx().GetChecksum();
+ sId = B2UCONST( "bitmap(" );
+ sId += OUString::valueOf( (sal_Int64)nId );
+ sId += B2UCONST( ")" );
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sId );
+
+ const Reference< XShape >& rxShape = (const Reference< XShape >&)( it->GetObject() );
+ Reference< XPropertySet > xShapePropSet( rxShape, UNO_QUERY );
+ ::com::sun::star::awt::Rectangle aBoundRect;
+ if( xShapePropSet.is() && ( xShapePropSet->getPropertyValue( B2UCONST( "BoundRect" ) ) >>= aBoundRect ) )
+ {
+ // Origin of the coordinate device must be (0,0).
+ const Point aTopLeft;
+ const Size aSize( aBoundRect.Width, aBoundRect.Height );
+
+ const Point aPt = pAction->GetPoint();
+ // The image must be exported with x, y attribute set to 0,
+ // on the contrary when referenced by a <use> element,
+ // specifying the wanted position, they will result
+ // misplaced.
+ pAction->Move( -aPt.X(), -aPt.Y() );
+ mpSVGWriter->WriteMetaFile( aTopLeft, aSize, aMtf, SVGWRITER_WRITE_ALL, NULL );
+ // We reset to the original values so that when the <use>
+ // element is created the x, y attributes are correct.
+ pAction->Move( aPt.X(), aPt.Y() );
+ }
+ else
+ {
+ OSL_FAIL( "implExportTextEmbeddedBitmaps: no shape bounding box." );
+ return sal_False;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "implExportTextEmbeddedBitmaps: metafile should have MetaBmpExScaleAction only." );
+ return sal_False;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "implExportTextEmbeddedBitmaps: metafile should have a single action." );
+ return sal_False;
+ }
+
+ }
+ return sal_True;
+}
// -----------------------------------------------------------------------------
@@ -1572,11 +1725,21 @@ sal_Bool SVGFilter::implExportShape( const Reference< XShape >& rxShape )
//mpSVGExport->AddAttributeIdLegacy( XML_NAMESPACE_DRAW, rShapeId );
}
+ const GDIMetaFile* pEmbeddedBitmapsMtf = NULL;
+ if( mEmbeddedBitmapActionMap.find( rxShape ) != mEmbeddedBitmapActionMap.end() )
+ {
+ pEmbeddedBitmapsMtf = &( mEmbeddedBitmapActionMap[ rxShape ].GetRepresentation() );
+ }
+
{
- Reference< XText > xText( rxShape, UNO_QUERY );
- mpSVGWriter->bIsTextShape = xText.is();
+// Reference< XText > xText( rxShape, UNO_QUERY );
+// mpSVGWriter->bIsTextShape = xText.is();
SvXMLElementExport aExp2( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
- mpSVGWriter->WriteMetaFile( aTopLeft, aSize, rMtf, SVGWRITER_WRITE_ALL, pElementId );
+ mpSVGWriter->WriteMetaFile( aTopLeft, aSize, rMtf,
+ SVGWRITER_WRITE_ALL,
+ pElementId,
+ &rxShape,
+ pEmbeddedBitmapsMtf );
}
}
@@ -1606,7 +1769,7 @@ sal_Bool SVGFilter::implCreateObjects()
Reference< XShapes > xShapes( xMasterPage, UNO_QUERY );
if( xShapes.is() )
- implCreateObjectsFromShapes( xShapes );
+ implCreateObjectsFromShapes( xMasterPage, xShapes );
}
}
@@ -1641,7 +1804,7 @@ sal_Bool SVGFilter::implCreateObjects()
Reference< XShapes > xShapes( xDrawPage, UNO_QUERY );
if( xShapes.is() )
- implCreateObjectsFromShapes( xShapes );
+ implCreateObjectsFromShapes( xDrawPage, xShapes );
}
}
return sal_True;
@@ -1649,7 +1812,7 @@ sal_Bool SVGFilter::implCreateObjects()
// -----------------------------------------------------------------------------
-sal_Bool SVGFilter::implCreateObjectsFromShapes( const Reference< XShapes >& rxShapes )
+sal_Bool SVGFilter::implCreateObjectsFromShapes( const Reference< XDrawPage > & rxPage, const Reference< XShapes >& rxShapes )
{
Reference< XShape > xShape;
sal_Bool bRet = sal_False;
@@ -1657,7 +1820,7 @@ sal_Bool SVGFilter::implCreateObjectsFromShapes( const Reference< XShapes >& rxS
for( sal_Int32 i = 0, nCount = rxShapes->getCount(); i < nCount; ++i )
{
if( ( rxShapes->getByIndex( i ) >>= xShape ) && xShape.is() )
- bRet = implCreateObjectsFromShape( xShape ) || bRet;
+ bRet = implCreateObjectsFromShape( rxPage, xShape ) || bRet;
xShape = NULL;
}
@@ -1667,15 +1830,16 @@ sal_Bool SVGFilter::implCreateObjectsFromShapes( const Reference< XShapes >& rxS
// -----------------------------------------------------------------------------
-sal_Bool SVGFilter::implCreateObjectsFromShape( const Reference< XShape >& rxShape )
+sal_Bool SVGFilter::implCreateObjectsFromShape( const Reference< XDrawPage > & rxPage, const Reference< XShape >& rxShape )
{
sal_Bool bRet = sal_False;
+
if( rxShape->getShapeType().lastIndexOf( B2UCONST( "drawing.GroupShape" ) ) != -1 )
{
Reference< XShapes > xShapes( rxShape, UNO_QUERY );
if( xShapes.is() )
- bRet = implCreateObjectsFromShapes( xShapes );
+ bRet = implCreateObjectsFromShapes( rxPage, xShapes );
}
else
{
@@ -1700,8 +1864,54 @@ sal_Bool SVGFilter::implCreateObjectsFromShape( const Reference< XShape >& rxSha
(*mpObjects)[ rxShape ] = ObjectRepresentation( rxShape, aMtf );
}
else
- (*mpObjects)[ rxShape ] = ObjectRepresentation( rxShape, aGraphic.GetGDIMetaFile() );
+ {
+ Reference< XText > xText( rxShape, UNO_QUERY );
+ sal_Bool bIsTextShape = xText.is();
+
+ if( !mpSVGExport->IsUsePositionedCharacters() && bIsTextShape )
+ {
+ // We create a map of text shape ids.
+ implRegisterInterface( rxShape );
+ Reference< XInterface > xRef( rxShape, UNO_QUERY );
+ const OUString& rShapeId = implGetValidIDFromInterface( xRef );
+ if( !rShapeId.isEmpty() )
+ {
+ mTextShapeIdListMap[rxPage] += rShapeId;
+ mTextShapeIdListMap[rxPage] += B2UCONST( " " );
+ }
+
+ // We create a set of bitmaps embedded into text shape.
+ GDIMetaFile aMtf;
+ const Point aNullPt;
+ const Size aSize( pObj->GetCurrentBoundRect().GetSize() );
+ MetaAction* pAction;
+ const GDIMetaFile& rMtf = aGraphic.GetGDIMetaFile();
+ sal_uLong nCount = rMtf.GetActionSize();
+ for( sal_uLong nCurAction = 0; nCurAction < nCount; ++nCurAction )
+ {
+ pAction = rMtf.GetAction( nCurAction );
+ const sal_uInt16 nType = pAction->GetType();
+
+ if( nType == META_BMPEXSCALE_ACTION )
+ {
+ GDIMetaFile aEmbeddedBitmapMtf;
+ pAction->Duplicate();
+ aEmbeddedBitmapMtf.AddAction( pAction );
+ aEmbeddedBitmapMtf.SetPrefSize( aSize );
+ aEmbeddedBitmapMtf.SetPrefMapMode( MAP_100TH_MM );
+ mEmbeddedBitmapActionSet.insert( ObjectRepresentation( rxShape, aEmbeddedBitmapMtf ) );
+ pAction->Duplicate();
+ aMtf.AddAction( pAction );
+ }
+ }
+ aMtf.SetPrefSize( aSize );
+ aMtf.SetPrefMapMode( MAP_100TH_MM );
+ mEmbeddedBitmapActionMap[ rxShape ] = ObjectRepresentation( rxShape, aMtf );
+ }
+
+ (*mpObjects)[ rxShape ] = ObjectRepresentation( rxShape, aGraphic.GetGDIMetaFile() );
+ }
bRet = sal_True;
}
}
diff --git a/filter/source/svg/svgfilter.hxx b/filter/source/svg/svgfilter.hxx
index 50d66f6e81bc..9a0ba8f09ac8 100644
--- a/filter/source/svg/svgfilter.hxx
+++ b/filter/source/svg/svgfilter.hxx
@@ -226,6 +226,70 @@ struct HashUChar
size_t operator()( const sal_Unicode uchar ) const { return static_cast< size_t >( uchar ); }
};
+// ---------------------------
+// - HashBmpExScale -
+// ---------------------------
+
+struct HashBmpExScale
+{
+ size_t operator()( const ObjectRepresentation& rObjRep ) const
+ {
+ const GDIMetaFile& aMtf = rObjRep.GetRepresentation();
+ if( aMtf.GetActionSize() == 1 )
+ {
+ const MetaBmpExScaleAction* pAction = (const MetaBmpExScaleAction*) aMtf.GetAction( 0 );
+ if( pAction )
+ {
+ return static_cast< size_t >( pAction->GetBitmapEx().GetChecksum() );
+ }
+ else
+ {
+ OSL_FAIL( "HashBmpExScale: metafile should have MetaBmpExScaleAction only." );
+ return 0;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "HashBmpExScale: metafile should have a single action." );
+ return 0;
+ }
+ }
+};
+
+// ---------------------------
+// - EqualityBmpExScale -
+// ---------------------------
+
+struct EqualityBmpExScale
+{
+ bool operator()( const ObjectRepresentation& rObjRep1,
+ const ObjectRepresentation& rObjRep2 ) const
+ {
+ const GDIMetaFile& aMtf1 = rObjRep1.GetRepresentation();
+ const GDIMetaFile& aMtf2 = rObjRep2.GetRepresentation();
+ if( aMtf1.GetActionSize() == 1 && aMtf2.GetActionSize() == 1 )
+ {
+ const MetaBmpExScaleAction* pA1 = (const MetaBmpExScaleAction*) aMtf1.GetAction( 0 );
+ const MetaBmpExScaleAction* pA2 = (const MetaBmpExScaleAction*) aMtf2.GetAction( 0 );
+ if( pA1 && pA2 )
+ {
+ return ( pA1->GetBitmapEx().GetChecksum() == pA2->GetBitmapEx().GetChecksum() );
+ }
+ else
+ {
+ OSL_FAIL( "EqualityBmpExScale: metafile should have MetaBmpExScaleAction only." );
+ return false;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "EqualityBmpExScale: metafile should have a single action." );
+ return false;
+ }
+
+ }
+};
+
// -------------
// - SVGFilter -
@@ -250,6 +314,10 @@ public:
typedef ::boost::unordered_map< ::rtl::OUString, UCharSet, HashOUString > UCharSetMap;
typedef ::boost::unordered_map< Reference< XInterface >, UCharSetMap, HashReferenceXInterface > UCharSetMapMap;
+ typedef ::boost::unordered_map< Reference< XInterface >, ::rtl::OUString, HashReferenceXInterface > UOStringMap;
+
+ typedef ::boost::unordered_set< ObjectRepresentation, HashBmpExScale, EqualityBmpExScale > MetaBitmapActionSet;
+
private:
Reference< XMultiServiceFactory > mxMSF;
@@ -267,6 +335,9 @@ private:
::rtl::OUString msClipPathId;
UCharSetMapMap mTextFieldCharSets;
Reference< XInterface > mCreateOjectsCurrentMasterPage;
+ UOStringMap mTextShapeIdListMap;
+ MetaBitmapActionSet mEmbeddedBitmapActionSet;
+ ObjectMap mEmbeddedBitmapActionMap;
ObjectMap* mpObjects;
Reference< XComponent > mxSrcDoc;
@@ -285,6 +356,10 @@ private:
sal_Bool implGetPagePropSet( const Reference< XDrawPage > & rxPage );
sal_Bool implGenerateMetaData();
+ void implExportTextShapeIndex();
+ void implEmbedBulletGlyphs();
+ void implEmbedBulletGlyph( sal_Unicode cBullet, const ::rtl::OUString & sPathData );
+ sal_Bool implExportTextEmbeddedBitmaps();
sal_Bool implGenerateScript();
sal_Bool implExportDocument();
@@ -303,8 +378,8 @@ private:
sal_Bool implExportShape( const Reference< XShape >& rxShape );
sal_Bool implCreateObjects();
- sal_Bool implCreateObjectsFromShapes( const Reference< XShapes >& rxShapes );
- sal_Bool implCreateObjectsFromShape( const Reference< XShape >& rxShape );
+ sal_Bool implCreateObjectsFromShapes( const Reference< XDrawPage > & rxPage, const Reference< XShapes >& rxShapes );
+ sal_Bool implCreateObjectsFromShape( const Reference< XDrawPage > & rxPage, const Reference< XShape >& rxShape );
sal_Bool implCreateObjectsFromBackground( const Reference< XDrawPage >& rxMasterPage );
::rtl::OUString implGetClassFromShape( const Reference< XShape >& rxShape );
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index 772867472627..4880161338b9 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -31,9 +31,10 @@
#include "svgfontexport.hxx"
#include "svgwriter.hxx"
+#include <rtl/crc.h>
#include <vcl/unohelp.hxx>
#include <tools/helpers.hxx>
-
+#include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
#include <sax/tools/converter.hxx>
#include <boost/shared_array.hpp>
@@ -97,8 +98,19 @@ static const char aXMLAttrPatternUnits[] = "patternUnits";
static const char aXMLAttrOffset[] = "offset";
static const char aXMLAttrStopColor[] = "stop-color";
+
+#define NSPREFIX "ooo:"
+
+static const char aOOOAttrNumberingType[] = NSPREFIX "numbering-type";
+
+
+static sal_Char const XML_UNO_NAME_NRULE_NUMBERINGTYPE[] = "NumberingType";
+static sal_Char const XML_UNO_NAME_NRULE_BULLET_CHAR[] = "BulletChar";
// -----------------------------------------------------------------------------
+
+
+
// ----------------------
// - SVGAttributeWriter -
// ----------------------
@@ -443,12 +455,25 @@ SVGTextWriter::SVGTextWriter( SVGExport& rExport, SVGFontExport& rFontExport )
mrFontExport( rFontExport ),
mpContext( NULL ),
mpVDev( NULL ),
+ mrTextShape(),
+ mrParagraphEnumeration(),
+ mrTextPortionEnumeration(),
+ mrCurrentTextPortion(),
+ mpTextEmbeddedBitmapMtf( NULL ),
mpTargetMapMode( NULL ),
mpTextShapeElem( NULL ),
mpTextParagraphElem( NULL ),
mpTextPositionElem( NULL ),
+ mnLeftTextPortionLength( 0 ),
maTextPos(0,0),
mnTextWidth(0),
+ mbPositioningNeeded( sal_False ),
+ mbIsNumbering( sal_False ),
+ maBulletListItemMap(),
+ mbIsListLevelStyleImage( sal_False ),
+ mbLineBreak( sal_False ),
+ mbIsURLField( sal_False ),
+ msUrl(),
mbIsPlacehlolderShape( sal_False ),
mbIWS( sal_False ),
maCurrentFont(),
@@ -465,6 +490,21 @@ SVGTextWriter::~SVGTextWriter()
// -----------------------------------------------------------------------------
+void SVGTextWriter::implRegisterInterface( const Reference< XInterface >& rxIf )
+{
+ if( rxIf.is() )
+ (mrExport.getInterfaceToIdentifierMapper()).registerReference( rxIf );
+}
+
+// -----------------------------------------------------------------------------
+
+const ::rtl::OUString & SVGTextWriter::implGetValidIDFromInterface( const Reference< XInterface >& rxIf )
+{
+ return (mrExport.getInterfaceToIdentifierMapper()).getIdentifier( rxIf );
+}
+
+// -----------------------------------------------------------------------------
+
void SVGTextWriter::implMap( const Size& rSz, Size& rDstSz ) const
{
if( mpVDev && mpTargetMapMode )
@@ -818,8 +858,236 @@ void SVGTextWriter::implSetFontFamily()
// -----------------------------------------------------------------------------
+sal_Bool SVGTextWriter::nextParagraph()
+{
+ mrTextPortionEnumeration.clear();
+ if( mrParagraphEnumeration.is() && mrParagraphEnumeration->hasMoreElements() )
+ {
+ Reference < XTextContent > xTextContent( mrParagraphEnumeration->nextElement(), UNO_QUERY_THROW );
+ if( xTextContent.is() )
+ {
+ Reference< XServiceInfo > xServiceInfo( xTextContent, UNO_QUERY_THROW );
+ if( xServiceInfo.is() )
+ {
+ OUString sInfo;
+ if( xServiceInfo->supportsService( B2UCONST( "com.sun.star.text.Paragraph" ) ) )
+ {
+ Reference< XPropertySet > xPropSet( xTextContent, UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
+ mbIsNumbering = sal_False;
+ mbIsListLevelStyleImage = sal_False;
+ if( xPropSetInfo->hasPropertyByName( B2UCONST( "NumberingLevel" ) ) )
+ {
+ sal_Int16 nListLevel = 0;
+ if( xPropSet->getPropertyValue( B2UCONST( "NumberingLevel" ) ) >>= nListLevel )
+ {
+ mbIsNumbering = sal_True;
+ sInfo = B2UCONST( "NumberingLevel: " );
+ sInfo += OUString::valueOf( (sal_Int32)nListLevel );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "style", sInfo );
+
+ Reference< XIndexReplace > xNumRules;
+ if( xPropSetInfo->hasPropertyByName( B2UCONST( "NumberingRules" ) ) )
+ {
+ xPropSet->getPropertyValue( B2UCONST( "NumberingRules" ) ) >>= xNumRules;
+ }
+ if( xNumRules.is() && ( nListLevel < xNumRules->getCount() ) )
+ {
+ Sequence<PropertyValue> aProps;
+ if( xNumRules->getByIndex( nListLevel ) >>= aProps )
+ {
+ sal_Int16 eType = NumberingType::CHAR_SPECIAL;
+ sal_Unicode cBullet = 0xf095;
+ const sal_Int32 nCount = aProps.getLength();
+ const PropertyValue* pPropArray = aProps.getConstArray();
+ for( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ const PropertyValue& rProp = pPropArray[i];
+ if( rProp.Name.equalsAsciiL( XML_UNO_NAME_NRULE_NUMBERINGTYPE, sizeof(XML_UNO_NAME_NRULE_NUMBERINGTYPE)-1 ) )
+ {
+ rProp.Value >>= eType;
+ }
+ else if( rProp.Name.equalsAsciiL( XML_UNO_NAME_NRULE_BULLET_CHAR, sizeof(XML_UNO_NAME_NRULE_BULLET_CHAR)-1 ) )
+ {
+ OUString sValue;
+ rProp.Value >>= sValue;
+ if( !sValue.isEmpty() )
+ {
+ cBullet = (sal_Unicode)sValue[0];
+ }
+ }
+ }
+ meNumberingType = eType;
+ mbIsListLevelStyleImage = ( NumberingType::BITMAP == meNumberingType );
+ if( NumberingType::CHAR_SPECIAL == meNumberingType )
+ {
+ if( cBullet )
+ {
+ if( cBullet < ' ' )
+ {
+ cBullet = 0xF000 + 149;
+ }
+ mcBulletChar = cBullet;
+ // text:bullet-char="..."
+ sInfo = OUString::valueOf( (sal_Int32) cBullet );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "bullet-char", sInfo );
+ }
+
+ }
+ }
+ }
+
+ }
+ }
+
+ Reference< XEnumerationAccess > xEnumerationAccess( xTextContent, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
+ if( xEnumeration.is() && xEnumeration->hasMoreElements() )
+ {
+ mrTextPortionEnumeration.set( xEnumeration );
+ }
+ sInfo = B2UCONST( "Paragraph" );
+ }
+ else if( xServiceInfo->supportsService( B2UCONST( "com.sun.star.text.Table" ) ) )
+ {
+ sInfo = B2UCONST( "Table" );
+ }
+ else
+ {
+ OSL_FAIL( "SVGTextWriter::nextParagraph: Unknown text content." );
+ return sal_False;
+ }
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", sInfo );
+ SvXMLElementExport aParaElem( mrExport, XML_NAMESPACE_NONE, "desc", mbIWS, mbIWS );
+ }
+
+ Reference< XInterface > xRef( xTextContent, UNO_QUERY );
+ const OUString& rParagraphId = implGetValidIDFromInterface( xRef );
+ if( !rParagraphId.isEmpty() )
+ {
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rParagraphId );
+ }
+ return sal_True;
+ }
+ }
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Bool SVGTextWriter::nextTextPortion()
+{
+ mrCurrentTextPortion.clear();
+ mbIsURLField = sal_False;
+ if( mrTextPortionEnumeration.is() && mrTextPortionEnumeration->hasMoreElements() )
+ {
+ OUString sInfo;
+ Reference< XPropertySet > xPortionPropSet( mrTextPortionEnumeration->nextElement(), UNO_QUERY );
+ Reference< XPropertySetInfo > xPortionPropInfo( xPortionPropSet->getPropertySetInfo() );
+ Reference < XTextRange > xPortionTextRange( xPortionPropSet, UNO_QUERY);
+ if( xPortionPropSet.is() && xPortionPropInfo.is()
+ && xPortionPropInfo->hasPropertyByName( B2UCONST( "TextPortionType" ) ) )
+ {
+ ::rtl::OUString sPortionType;
+ if( xPortionPropSet->getPropertyValue( B2UCONST( "TextPortionType" ) ) >>= sPortionType )
+ {
+ sInfo = B2UCONST( "type: " );
+ sInfo += sPortionType;
+ sInfo += B2UCONST( "; " );
+ }
+ if( xPortionTextRange.is() )
+ {
+ sInfo += B2UCONST( "content: " );
+ sInfo += xPortionTextRange->getString();
+ sInfo += B2UCONST( "; " );
+
+ mrCurrentTextPortion.set( xPortionTextRange );
+
+ Reference < XPropertySet > xRangePropSet( xPortionTextRange, UNO_QUERY );
+ if( xRangePropSet.is() && xRangePropSet->getPropertySetInfo()->hasPropertyByName( B2UCONST( "TextField" ) ) )
+ {
+ Reference < XTextField > xTextField( xRangePropSet->getPropertyValue( B2UCONST( "TextField" ) ), UNO_QUERY );
+ if( xTextField.is() )
+ {
+ const ::rtl::OUString sServicePrefix( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.textfield.") );
+ Reference< XServiceInfo > xService( xTextField, UNO_QUERY );
+ const Sequence< OUString > aServices = xService->getSupportedServiceNames();
+ const OUString* pNames = aServices.getConstArray();
+ sal_Int32 nCount = aServices.getLength();
+
+ OUString sFieldName; // service name postfix of current field
+
+ // search for TextField service name
+ while( nCount-- )
+ {
+ if ( pNames->matchIgnoreAsciiCase( sServicePrefix ) )
+ {
+ // TextField found => postfix is field type!
+ sFieldName = pNames->copy( sServicePrefix.getLength() );
+ break;
+ }
+
+ ++pNames;
+ }
+
+ sInfo += B2UCONST( "text field type: " );
+ sInfo += sFieldName;
+ sInfo += B2UCONST( "; " );
+
+ mbIsURLField = sFieldName.equalsAscii( "URL" );
+ if( mbIsURLField )
+ {
+ Reference<XPropertySet> xTextFieldPropSet(xTextField, UNO_QUERY);
+ if( xTextFieldPropSet.is() )
+ {
+ OUString sURL;
+ if( ( xTextFieldPropSet->getPropertyValue( sFieldName ) ) >>= sURL )
+ {
+ sInfo += B2UCONST( "url: " );
+ sInfo += mrExport.GetRelativeReference( sURL );
+
+ msUrl = mrExport.GetRelativeReference( sURL );
+ if( !msUrl.isEmpty() )
+ {
+ implRegisterInterface( xPortionTextRange );
+
+ Reference< XInterface > xRef( xPortionTextRange, UNO_QUERY );
+ const OUString& rTextPortionId = implGetValidIDFromInterface( xRef );
+ if( !rTextPortionId.isEmpty() )
+ {
+ msHyperlinkIdList += rTextPortionId;
+ msHyperlinkIdList += B2UCONST( " " );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextPortion" ) );
+ SvXMLElementExport aPortionElem( mrExport, XML_NAMESPACE_NONE, "desc", mbIWS, mbIWS );
+ mrExport.GetDocHandler()->characters( sInfo );
+ return sal_True;
+ }
+ }
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------------
+
void SVGTextWriter::startTextShape()
{
+ if( mrTextShape.is() )
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( mrTextShape, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
+ if( xEnumeration.is() && xEnumeration->hasMoreElements() )
+ {
+ mrParagraphEnumeration.set( xEnumeration );
+ }
+ }
+
if( mpTextShapeElem )
{
OSL_FAIL( "SVGTextWriter::startTextShape: text shape already defined." );
@@ -827,6 +1095,7 @@ void SVGTextWriter::startTextShape()
else
{
maParentFont = Font();
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextShape" ) );
mpTextShapeElem = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, mbIWS );
startTextParagraph();
}
@@ -837,11 +1106,20 @@ void SVGTextWriter::startTextShape()
void SVGTextWriter::endTextShape()
{
endTextParagraph();
+ if( mrTextShape.is() )
+ mrTextShape.clear();
+ if( mrParagraphEnumeration.is() )
+ mrParagraphEnumeration.clear();
if( mpTextShapeElem )
{
delete mpTextShapeElem;
mpTextShapeElem = NULL;
}
+ // these need to be invoked after the <text> element has been closed
+ implExportHyperlinkIds();
+ implWriteBulletChars();
+ implWriteEmbeddedBitmaps();
+
}
// -----------------------------------------------------------------------------
@@ -849,11 +1127,36 @@ void SVGTextWriter::endTextShape()
void SVGTextWriter::startTextParagraph()
{
endTextParagraph();
- mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextParagraph" ) );
+ nextParagraph();
+ if( mbIsNumbering )
+ {
+ OUString sNumberingType;
+ switch( meNumberingType )
+ {
+ case( NumberingType::CHAR_SPECIAL ):
+ sNumberingType = B2UCONST( "bullet-style" );
+ break;
+ case( NumberingType::BITMAP ):
+ sNumberingType = B2UCONST( "image-style" );
+ break;
+ default:
+ sNumberingType = B2UCONST( "number-style" );
+ break;
+ }
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aOOOAttrNumberingType, sNumberingType );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "ListItem" ) );
+ }
+ else
+ {
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextParagraph" ) );
+ }
maParentFont = Font();
addFontAttributes( /* isTexTContainer: */ true );
mpTextParagraphElem = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
- startTextPosition();
+ if( !mbIsListLevelStyleImage )
+ {
+ startTextPosition();
+ }
}
// -----------------------------------------------------------------------------
@@ -861,11 +1164,16 @@ void SVGTextWriter::startTextParagraph()
void SVGTextWriter::endTextParagraph()
{
endTextPosition();
+ mbIsNumbering = sal_False;
+ mbIsListLevelStyleImage = sal_False;
+ mbPositioningNeeded = sal_False;
+
if( mpTextParagraphElem )
{
delete mpTextParagraphElem;
mpTextParagraphElem = NULL;
}
+
}
// -----------------------------------------------------------------------------
@@ -895,10 +1203,215 @@ void SVGTextWriter::endTextPosition()
// -----------------------------------------------------------------------------
+void SVGTextWriter::implExportHyperlinkIds()
+{
+ if( !msHyperlinkIdList.isEmpty() )
+ {
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "HyperlinkIdList" ) );
+ SvXMLElementExport aDescElem( mrExport, XML_NAMESPACE_NONE, "desc", sal_True, sal_True );
+ mrExport.GetDocHandler()->characters( msHyperlinkIdList.trim() );
+ msHyperlinkIdList = OUString();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void SVGTextWriter::implWriteBulletChars()
+{
+ if( maBulletListItemMap.empty() )
+ return;
+
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "BulletChars" ) );
+ SvXMLElementExport aGroupElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
+
+ BulletListItemInfoMap::const_iterator it = maBulletListItemMap.begin();
+ BulletListItemInfoMap::const_iterator end = maBulletListItemMap.end();
+ OUString sId, sPosition, sScaling, sRefId;
+ for( ; it != end; ++it )
+ {
+ // <g id="?" > (used by animations)
+ {
+ // As id we use the id of the text portion placeholder wrapped
+ // by bullet-char(*)
+ sId = B2UCONST( "bullet-char(" );
+ sId += it->first;
+ sId += B2UCONST( ")" );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
+ SvXMLElementExport aBulletCharElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
+
+ // <g transform="translate(x,y)" >
+ {
+ const BulletListItemInfo& rInfo = it->second;
+
+ // Add positioning attribute through a translation
+ sPosition = B2UCONST( "translate(" );
+ sPosition += OUString::valueOf( rInfo.aPos.X() );
+ sPosition += B2UCONST( "," );
+ sPosition += OUString::valueOf( rInfo.aPos.Y() );
+ sPosition += B2UCONST( ")" );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "transform", sPosition );
+
+ mpContext->AddPaintAttr( COL_TRANSPARENT, rInfo.aColor );
+
+ SvXMLElementExport aPositioningElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
+
+ // <use transform="scale(font-size)" xlink:ref="/" >
+ {
+ // Add size attribute through a scaling
+ sScaling = B2UCONST( "scale(" );
+ sScaling += OUString::valueOf( rInfo.nFontSize );
+ sScaling += B2UCONST( "," );
+ sScaling += OUString::valueOf( rInfo.nFontSize );
+ sScaling += B2UCONST( ")" );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "transform", sScaling );
+
+ // Add ref attribute
+ sRefId = B2UCONST( "#bullet-char-template(" );
+ sRefId += OUString::valueOf( (sal_Int32)( rInfo.cBulletChar ) );
+ sRefId += B2UCONST( ")" );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, sRefId );
+
+ SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, "use", sal_True, sal_True );
+ }
+ } // close aPositioningElem
+ } // close aBulletCharElem
+ }
+
+
+ // clear the map
+ maBulletListItemMap.clear();
+}
+
+// -----------------------------------------------------------------------------
+
+void SVGTextWriter::writeBitmapPlaceholder( const MetaBmpExScaleAction* pAction )
+{
+ // text position element
+ const Point& rPos = pAction->GetPoint();
+ implMap( rPos, maTextPos );
+ startTextPosition();
+ mbPositioningNeeded = sal_True;
+ if( mbIsNumbering )
+ {
+ mbIsNumbering = sal_False;
+ mbIsListLevelStyleImage = sal_False;
+ }
+
+ // bitmap placeholder element
+ sal_uLong nId = SVGActionWriter::GetChecksum( pAction );
+ OUString sId = B2UCONST( "bitmap-placeholder(" );
+ sId += OUString::valueOf( (sal_Int64)nId );
+ sId += B2UCONST( ")" );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
+
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "BitmapPlaceholder" ) );
+ SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
+}
+
+// -----------------------------------------------------------------------------
+
+void SVGTextWriter::implWriteEmbeddedBitmaps()
+{
+ if( mpTextEmbeddedBitmapMtf && mpTextEmbeddedBitmapMtf->GetActionSize() )
+ {
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "EmbeddedBitmaps" ) );
+ SvXMLElementExport aEmbBitmapGroupElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
+
+ const GDIMetaFile& rMtf = *mpTextEmbeddedBitmapMtf;
+
+ OUString sId, sRefId;
+ sal_uLong nId;
+ sal_uLong nCount = rMtf.GetActionSize();
+ for( sal_uLong nCurAction = 0; nCurAction < nCount; nCurAction++ )
+ {
+ MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*) rMtf.GetAction( nCurAction );
+
+ // <g id="?" > (used by animations)
+ {
+ // embedded bitmap id
+ nId = SVGActionWriter::GetChecksum( pAction );
+ sId = B2UCONST( "embedded-bitmap(" );
+ sId += OUString::valueOf( (sal_Int64)nId );
+ sId += B2UCONST( ")" );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
+
+ SvXMLElementExport aEmbBitmapElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
+
+ // <use x="?" y="?" xlink:ref="?" >
+ {
+ // referenced bitmap template
+ nId = pAction->GetBitmapEx().GetChecksum();
+ sRefId = B2UCONST( "#bitmap(" );
+ sRefId += OUString::valueOf( (sal_Int64)nId );
+ sRefId += B2UCONST( ")" );
+
+ const Point& rPt = pAction->GetPoint();
+ const Size& rSz = pAction->GetSize();
+ Point aPt;
+ Size aSz;
+ implMap( rPt, aPt );
+ implMap( rSz, aSz );
+
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aPt.X() ) );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aPt.Y() ) );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, sRefId );
+
+ SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, "use", sal_True, sal_True );
+ }
+ } // close aEmbBitmapElem
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
void SVGTextWriter::writeTextPortion( const Point& rPos,
const String& rText,
sal_Bool bApplyMapping )
{
+ if( rText.Len() == 0 )
+ return;
+
+ mbLineBreak = sal_False;
+
+ if( !mbIsNumbering || mbIsListLevelStyleImage )
+ {
+ bool bNotSync = true;
+ OUString sContent;
+ sal_Int32 nStartPos;
+ do
+ {
+ while( bNotSync )
+ {
+ if( mnLeftTextPortionLength <= 0 )
+ {
+ if( !nextTextPortion() )
+ break;
+ else
+ {
+ sContent = mrCurrentTextPortion->getString();
+ mnLeftTextPortionLength = sContent.getLength();
+ }
+ }
+ else
+ {
+ sContent = mrCurrentTextPortion->getString();
+ }
+
+ nStartPos = sContent.getLength() - mnLeftTextPortionLength;
+ if( nStartPos < 0 ) nStartPos = 0;
+ mnLeftTextPortionLength -= rText.Len();
+
+ if( sContent.isEmpty() )
+ continue;
+ if( sContent.equalsAscii( "\n" ) )
+ mbLineBreak = sal_True;
+ if( sContent.match( rText, nStartPos ) )
+ bNotSync = false;
+ }
+ } while( bNotSync && nextParagraph() );
+ }
+
if( !mpVDev )
OSL_FAIL( "SVGTextWriter::writeTextPortion: invalid virtual device." );
@@ -1014,24 +1527,72 @@ void SVGTextWriter::implWriteTextPortion( const Point& rPos,
else
aPos = rPos;
-
- if( maTextPos.Y() != aPos.Y() )
+ if( mbPositioningNeeded )
+ {
+ mbPositioningNeeded = sal_False;
+ maTextPos.setX( aPos.X() );
+ maTextPos.setY( aPos.Y() );
+ startTextPosition();
+ }
+ else if( maTextPos.Y() != aPos.Y() )
{
// In case the text position moved backward we could have a line break
// so we end the current line and start a new one.
- if( ( maTextPos.X() + mnTextWidth ) > aPos.X() )
+ if( mbLineBreak || ( ( maTextPos.X() + mnTextWidth ) > aPos.X() ) )
{
+ mbLineBreak = sal_False;
maTextPos.setX( aPos.X() );
maTextPos.setY( aPos.Y() );
startTextPosition();
}
- else // superscript, subscript, bullets
+ else // superscript, subscript, list item numbering
{
- //mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) );
maTextPos.setY( aPos.Y() );
startTextPosition( sal_False /* do not export x attribute */ );
}
}
+ // we are dealing with a bullet, so set up this for the next text portion
+ if( mbIsNumbering )
+ {
+ mbIsNumbering = sal_False;
+ mbPositioningNeeded = sal_True;
+
+ if( meNumberingType == NumberingType::CHAR_SPECIAL )
+ {
+ // Create an id for the current text portion
+ implRegisterInterface( mrCurrentTextPortion );
+
+ // Add the needed info to the BulletListItemMap
+ Reference< XInterface > xRef( mrCurrentTextPortion, UNO_QUERY );
+ const OUString& rId = implGetValidIDFromInterface( xRef );
+ if( !rId.isEmpty() )
+ {
+ BulletListItemInfo& aBulletListItemInfo = maBulletListItemMap[ rId ];
+ aBulletListItemInfo.nFontSize = rFont.GetHeight();
+ aBulletListItemInfo.aColor = aTextColor;
+ aBulletListItemInfo.aPos = maTextPos;
+ aBulletListItemInfo.cBulletChar = mcBulletChar;
+
+ // Make this text portion a bullet placeholder
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rId );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "BulletPlaceholder" ) );
+ SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
+ return;
+ }
+ }
+ }
+
+ Reference< XInterface > xRef( mrCurrentTextPortion, UNO_QUERY );
+ const OUString& rTextPortionId = implGetValidIDFromInterface( xRef );
+ if( !rTextPortionId.isEmpty() )
+ {
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rTextPortionId );
+ }
+
+ if( mbIsURLField && !msUrl.isEmpty() )
+ {
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, msUrl );
+ }
addFontAttributes( /* isTexTContainer: */ false );
@@ -1236,6 +1797,35 @@ PolyPolygon& SVGActionWriter::ImplMap( const PolyPolygon& rPolyPoly, PolyPolygon
// -----------------------------------------------------------------------------
+sal_uLong SVGActionWriter::GetChecksum( const MetaBmpExScaleAction* pAct )
+{
+ sal_uLong nCrc = 0;
+ SVBT16 aBT16;
+ SVBT32 aBT32;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ return nCrc;
+}
+
+// -----------------------------------------------------------------------------
+
void SVGActionWriter::ImplWriteLine( const Point& rPt1, const Point& rPt2,
const Color* pLineColor, sal_Bool bApplyMapping )
{
@@ -2043,14 +2633,23 @@ void SVGActionWriter::ImplWriteBmp( const BitmapEx& rBmpEx,
void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
sal_uInt32 nWriteFlags,
- const ::rtl::OUString* pElementId )
+ const ::rtl::OUString* pElementId,
+ const Reference< XShape >* pxShape,
+ const GDIMetaFile* pTextEmbeddedBitmapMtf )
{
if( mnInnerMtfCount )
nWriteFlags |= SVGWRITER_NO_SHAPE_COMMENTS;
+ if( !mrExport.IsUsePositionedCharacters() && pxShape
+ && Reference< XText >( *pxShape, UNO_QUERY ).is() )
+ {
+ Reference< XText > xText( *pxShape, UNO_QUERY );
+ maTextWriter.setTextShape( xText, pTextEmbeddedBitmapMtf );
+ }
+
mbIsPlacehlolderShape = false;
maTextWriter.setPlaceholderShapeFlag( false );
- if( pElementId != NULL && ( *pElementId == sPlaceholderTag ) )
+ if( ( pElementId != NULL ) && ( *pElementId == sPlaceholderTag ) )
{
mbIsPlacehlolderShape = true;
maTextWriter.setPlaceholderShapeFlag( true );
@@ -2063,7 +2662,7 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
const MetaAction* pAction = rMtf.GetAction( nCurAction );
const sal_uInt16 nType = pAction->GetType();
- if( bIsTextShape )
+ if( maTextWriter.getTextShape().is() )
{
try
{
@@ -2677,9 +3276,17 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
{
const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
- ImplWriteBmp( pA->GetBitmapEx(),
- pA->GetPoint(), pA->GetSize(),
- Point(), pA->GetBitmapEx().GetSizePixel() );
+ // Bitmaps embedded into text shapes are collected and exported elsewhere.
+ if( maTextWriter.getTextShape().is() )
+ {
+ maTextWriter.writeBitmapPlaceholder( pA );
+ }
+ else
+ {
+ ImplWriteBmp( pA->GetBitmapEx(),
+ pA->GetPoint(), pA->GetSize(),
+ Point(), pA->GetBitmapEx().GetSizePixel() );
+ }
}
}
break;
@@ -2874,7 +3481,9 @@ void SVGActionWriter::WriteMetaFile( const Point& rPos100thmm,
const Size& rSize100thmm,
const GDIMetaFile& rMtf,
sal_uInt32 nWriteFlags,
- const ::rtl::OUString* pElementId )
+ const ::rtl::OUString* pElementId,
+ const Reference< XShape >* pXShape,
+ const GDIMetaFile* pTextEmbeddedBitmapMtf )
{
MapMode aMapMode( rMtf.GetPrefMapMode() );
Size aPrefSize( rMtf.GetPrefSize() );
@@ -2895,7 +3504,7 @@ void SVGActionWriter::WriteMetaFile( const Point& rPos100thmm,
mapCurShape.reset();
- ImplWriteActions( rMtf, nWriteFlags, pElementId );
+ ImplWriteActions( rMtf, nWriteFlags, pElementId, pXShape, pTextEmbeddedBitmapMtf );
// draw open shape that doesn't have a border
if( mapCurShape.get() )
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index 8f74671903cc..3a23f5fa52ad 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -45,6 +45,12 @@
#include <xmloff/nmspmap.hxx>
#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XComponent.hpp>
@@ -55,6 +61,21 @@
#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+
+// -----------------------------------------------------------------------------
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::style;
// -----------------------------------------------------------------------------
@@ -141,29 +162,68 @@ struct SVGShapeDescriptor
}
};
-// -------------------
-// - SVGActionWriter -
-// -------------------
+
class SVGAttributeWriter;
class GDIMetaFile;
+
+// ---------------------------
+// - BulletListItemInfo -
+// ---------------------------
+struct BulletListItemInfo
+{
+ long nFontSize;
+ Color aColor;
+ Point aPos;
+ sal_Unicode cBulletChar;
+};
+
+// ---------------------------
+// - OUStringHasher -
+// ---------------------------
+
+struct OUStringHasher
+{
+ size_t operator()( const ::rtl::OUString& oustr ) const { return static_cast< size_t >( oustr.hashCode() ); }
+};
+
+
// -------------------
// - SVGTextWriter -
// -------------------
class SVGTextWriter
{
+ public:
+ typedef ::boost::unordered_map< ::rtl::OUString, BulletListItemInfo, OUStringHasher > BulletListItemInfoMap;
+
private:
SVGExport& mrExport;
SVGFontExport& mrFontExport;
SVGAttributeWriter* mpContext;
VirtualDevice* mpVDev;
+ Reference<XText> mrTextShape;
+ Reference<XEnumeration> mrParagraphEnumeration;
+ Reference<XEnumeration> mrTextPortionEnumeration;
+ Reference<XTextRange> mrCurrentTextPortion;
+ const GDIMetaFile* mpTextEmbeddedBitmapMtf;
MapMode* mpTargetMapMode;
SvXMLElementExport* mpTextShapeElem;
SvXMLElementExport* mpTextParagraphElem;
SvXMLElementExport* mpTextPositionElem;
+ sal_Int32 mnLeftTextPortionLength;
Point maTextPos;
long int mnTextWidth;
+ sal_Bool mbPositioningNeeded;
+ sal_Bool mbIsNumbering;
+ sal_Int16 meNumberingType;
+ sal_Unicode mcBulletChar;
+ BulletListItemInfoMap maBulletListItemMap;
+ sal_Bool mbIsListLevelStyleImage;
+ sal_Bool mbLineBreak;
+ sal_Bool mbIsURLField;
+ ::rtl::OUString msUrl;
+ ::rtl::OUString msHyperlinkIdList;
sal_Bool mbIsPlacehlolderShape;
sal_Bool mbIWS;
Font maCurrentFont;
@@ -177,12 +237,19 @@ class SVGTextWriter
void setTextProperties( const GDIMetaFile& rMtf, sal_uLong nCurAction );
void addFontAttributes( sal_Bool bIsTextContainer );
+ sal_Bool nextParagraph();
+ sal_Bool nextTextPortion();
+
void startTextShape();
void endTextShape();
void startTextParagraph();
void endTextParagraph();
void startTextPosition( sal_Bool bExportX = sal_True, sal_Bool bExportY = sal_True);
void endTextPosition();
+ void implExportHyperlinkIds();
+ void implWriteBulletChars();
+ void writeBitmapPlaceholder( const MetaBmpExScaleAction* pAction );
+ void implWriteEmbeddedBitmaps();
void writeTextPortion( const Point& rPos, const String& rText,
sal_Bool bApplyMapping = sal_True );
void implWriteTextPortion( const Point& rPos, const String& rText,
@@ -201,6 +268,19 @@ class SVGTextWriter
mpContext = pContext;
}
+ void setTextShape( const Reference<XText>& rxText,
+ const GDIMetaFile* pTextEmbeddedBitmapMtf )
+ {
+ mrTextShape.set( rxText );
+ mpTextEmbeddedBitmapMtf = pTextEmbeddedBitmapMtf;
+ }
+
+ const Reference<XText>& getTextShape() const
+ {
+ return mrTextShape;
+ }
+
+
void setPlaceholderShapeFlag( sal_Bool bState )
{
mbIsPlacehlolderShape = bState;
@@ -213,9 +293,15 @@ class SVGTextWriter
void implSetFontFamily();
template< typename SubType >
sal_Bool implGetTextPosition( const MetaAction* pAction, Point& raPos, sal_Bool& bEmpty );
+ void implRegisterInterface( const Reference< XInterface >& rxIf );
+ const ::rtl::OUString & implGetValidIDFromInterface( const Reference< XInterface >& rxIf );
+
};
+// -------------------
+// - SVGActionWriter -
+// -------------------
class SVGActionWriter
{
@@ -289,13 +375,18 @@ private:
void ImplCheckFontAttributes();
void ImplCheckPaintAttributes();
- void ImplWriteActions( const GDIMetaFile& rMtf, sal_uInt32 nWriteFlags, const ::rtl::OUString* pElementId );
+ void ImplWriteActions( const GDIMetaFile& rMtf,
+ sal_uInt32 nWriteFlags,
+ const ::rtl::OUString* pElementId,
+ const Reference< XShape >* pXShape = NULL,
+ const GDIMetaFile* pTextEmbeddedBitmapMtf = NULL );
Font ImplSetCorrectFontHeight() const;
public:
static ::rtl::OUString GetPathString( const PolyPolygon& rPolyPoly, sal_Bool bLine );
+ static sal_uLong GetChecksum( const MetaBmpExScaleAction* pAct );
public:
@@ -306,7 +397,9 @@ public:
const Size& rSize100thmm,
const GDIMetaFile& rMtf,
sal_uInt32 nWriteFlags,
- const ::rtl::OUString* pElementId = NULL );
+ const ::rtl::OUString* pElementId = NULL,
+ const Reference< XShape >* pXShape = NULL,
+ const GDIMetaFile* pTextEmbeddedBitmapMtf = NULL );
sal_Bool bIsTextShape;
};