Hi,
finally a patch is ready for handling of dashes. I've removed all
polygon emulation stuff. Svg has a more flexible way to define dashes.
1. ODF only permits one constant distance between dashes. Currently the
average of all distances is taken.
2. The svg dash array is parsed up to the point where is can't be
represented by ODF parameters. That should be better than rejecting the
whole array and drawing a solid line.
3. Dash offset can't be represented at all.
Comments and nitpicking welcome...
As far as I can see now the emulated style id in the internal-style-ref
attribute isn't used anywhere (id following after '$'). Keep it or
remove it?
Christina
From 8c71ee764f06327a265e1e8d230bea9a8a7fe058 Mon Sep 17 00:00:00 2001
From: "Chr. Rossmanith" <ChrRossmanith@gmx.de>
Date: Fri, 15 Jun 2012 23:27:49 +0200
Subject: [PATCH] SVG: use dash parameters from svg file
Change-Id: I86b31156e1a9221d9cfdc40d5670b324ce056a89
---
filter/source/svg/gfxtypes.hxx | 3 +-
filter/source/svg/svgreader.cxx | 182 ++++++++++++++++++++++++++++-----------
2 files changed, 132 insertions(+), 53 deletions(-)
diff --git a/filter/source/svg/gfxtypes.hxx b/filter/source/svg/gfxtypes.hxx
index 68463c8..7cebe1a 100644
--- a/filter/source/svg/gfxtypes.hxx
+++ b/filter/source/svg/gfxtypes.hxx
@@ -143,7 +143,8 @@ enum PaintType
{
NONE,
SOLID,
- GRADIENT
+ GRADIENT,
+ DASH
};
enum FillRule
diff --git a/filter/source/svg/svgreader.cxx b/filter/source/svg/svgreader.cxx
index 6db2eb0..52c2078 100644
--- a/filter/source/svg/svgreader.cxx
+++ b/filter/source/svg/svgreader.cxx
@@ -659,11 +659,17 @@ struct AnnotatingVisitor
else
xAttrs->AddAttribute( "draw:fill", "none");
- if( rState.meStrokeType != NONE )
+ if( rState.meStrokeType == SOLID )
{
xAttrs->AddAttribute( "draw:stroke", "solid");
xAttrs->AddAttribute( "svg:stroke-color", getOdfColor(rState.maStrokeColor));
}
+ else if( rState.meStrokeType == DASH )
+ {
+ xAttrs->AddAttribute( "draw:stroke", "dash");
+ xAttrs->AddAttribute( "draw:stroke-dash",
"dash"+rtl::OUString::valueOf(mnCurrStateId));
+ xAttrs->AddAttribute( "svg:stroke-color", getOdfColor(rState.maStrokeColor));
+ }
else
xAttrs->AddAttribute( "draw:stroke", "none");
@@ -694,28 +700,6 @@ struct AnnotatingVisitor
void writeStyle(const uno::Reference<xml::dom::XElement>& xElem, const sal_Int32 nTagId)
{
SAL_INFO ("svg", "writeStyle xElem " << xElem->getTagName());
- sal_Int32 nEmulatedStyleId=0;
- if( maCurrState.maDashArray.size() &&
- maCurrState.meStrokeType != NONE )
- {
- // ODF dashing is severly borked - generate filled shape
- // instead (further down the road - here, we simply
- // emulate a filled style with the next id)
-
- // move all stroke attribs to fill, Clear stroking
- State aEmulatedStrokeState( maCurrState );
- aEmulatedStrokeState.meFillType = maCurrState.meStrokeType;
- aEmulatedStrokeState.mnFillOpacity = maCurrState.mnStrokeOpacity;
- aEmulatedStrokeState.maFillColor = maCurrState.maStrokeColor;
- aEmulatedStrokeState.maFillGradient = maCurrState.maStrokeGradient;
- aEmulatedStrokeState.meFillRule = EVEN_ODD;
- aEmulatedStrokeState.meStrokeType = NONE;
-
- if( writeStyle(aEmulatedStrokeState, nTagId) )
- nEmulatedStyleId = mnCurrStateId;
- else
- nEmulatedStyleId = mrStates.find(aEmulatedStrokeState)->mnStyleId;
- }
sal_Int32 nStyleId=0;
if( writeStyle(maCurrState, nTagId) )
@@ -726,9 +710,7 @@ struct AnnotatingVisitor
xElem->setAttribute("internal-style-ref",
rtl::OUString::valueOf(
nStyleId)
- +"$"
- +rtl::OUString::valueOf(
- nEmulatedStyleId));
+ +"$0");
}
void push()
@@ -969,12 +951,18 @@ struct AnnotatingVisitor
case XML_STROKE_DASHARRAY:
{
if( aValueUtf8 == "none" )
+ {
maCurrState.maDashArray.clear();
+ maCurrState.meStrokeType = SOLID;
+ }
else if( aValueUtf8 == "inherit" )
maCurrState.maDashArray = maParentStates.back().maDashArray;
else
+ {
parseDashArray(aValueUtf8.getStr(),
maCurrState.maDashArray);
+ maCurrState.meStrokeType = DASH;
+ }
break;
}
case XML_STROKE_OPACITY:
@@ -1668,32 +1656,6 @@ struct ShapeWritingVisitor
maCurrState.maCTM.get(1,1),
maCurrState.maCTM.get(1,2));
- if( aState.meStrokeType != NONE && aState.maDashArray.size() )
- {
- // ODF dashing is severly borked - generate filled polygon instead
- aPolys.clear();
- for( sal_uInt32 i=0; i<rPoly.count(); ++i )
- {
- aPolys.push_back(
- basegfx::tools::stripNeutralPolygons(
- basegfx::tools::prepareForPolygonOperation(
- basegfx::tools::createAreaGeometry(
- rPoly.getB2DPolygon(i),
- aState.mnStrokeWidth/2.0,
- aState.meLineJoin))));
- // TODO(F2): line ends
- }
-
- sal_Int32 nDummyIndex(0);
- aStyleId = xElem->getAttribute(
- "internal-style-ref").getToken(1,'$',nDummyIndex);
- StateMap::iterator pAlternateState=mrStateMap.find(aStyleId.toInt32());
- OSL_ASSERT(pAlternateState != mrStateMap.end());
- aState = pAlternateState->second;
- OSL_ENSURE( pAlternateState == mrStateMap.end(),
- "Doh - where's my alternate style entry?!" );
- }
-
// TODO(F2): separate out shear, rotate etc.
// apply transformation to polygon, to keep draw
// import in 100th mm
@@ -1775,6 +1737,119 @@ static void writeShapes( StatePool&
rStat
} // namespace
+struct OfficeStylesWritingVisitor
+{
+ OfficeStylesWritingVisitor( StateMap& rStateMap,
+ const uno::Reference<xml::sax::XDocumentHandler>&
xDocumentHandler) :
+ mrStateMap(rStateMap),
+ mxDocumentHandler(xDocumentHandler)
+ {}
+ void operator()( const uno::Reference<xml::dom::XElement>& /*xElem*/ )
+ {
+ }
+ void operator()( const uno::Reference<xml::dom::XElement>& xElem,
+ const uno::Reference<xml::dom::XNamedNodeMap>& /*xAttributes*/ )
+ {
+ rtl::Reference<SvXMLAttributeList> xAttrs( new SvXMLAttributeList() );
+ uno::Reference<xml::sax::XAttributeList> xUnoAttrs( xAttrs.get() );
+
+ sal_Int32 nDummyIndex(0);
+ rtl::OUString sStyleId(
+ xElem->getAttribute("internal-style-ref").getToken(
+ 0,'$',nDummyIndex));
+ StateMap::iterator pOrigState=mrStateMap.find(
+ sStyleId.toInt32());
+
+ if( pOrigState == mrStateMap.end() )
+ return; // non-exportable element, e.g. linearGradient
+
+ maCurrState = pOrigState->second;
+
+ if( maCurrState.meStrokeType == DASH )
+ {
+ sal_Int32 dots1, dots2;
+ double dots1_length, dots2_length, dash_distance;
+ SvgDashArray2Odf( &dots1, &dots1_length, &dots2, &dots2_length, &dash_distance );
+
+ xAttrs->Clear();
+ xAttrs->AddAttribute( "draw:name", "dash"+sStyleId );
+ xAttrs->AddAttribute( "draw:display-name", "dash"+sStyleId );
+ xAttrs->AddAttribute( "draw:style", "rect" );
+ if ( dots1>0 ) {
+ xAttrs->AddAttribute( "draw:dots1", rtl::OUString::valueOf(dots1) );
+ xAttrs->AddAttribute( "draw:dots1-length",
rtl::OUString::valueOf(pt2mm(convLength( rtl::OUString::valueOf(dots1_length), maCurrState, 'h'
)))+"mm" );
+ }
+ xAttrs->AddAttribute( "draw:distance", rtl::OUString::valueOf(pt2mm(convLength(
rtl::OUString::valueOf(dash_distance), maCurrState, 'h' )))+"mm" );
+ if ( dots2>0 ) {
+ xAttrs->AddAttribute( "draw:dots2", rtl::OUString::valueOf(dots2) );
+ xAttrs->AddAttribute( "draw:dots2-length",
rtl::OUString::valueOf(pt2mm(convLength( rtl::OUString::valueOf(dots2_length), maCurrState, 'h'
)))+"mm" );
+ }
+
+ mxDocumentHandler->startElement( "draw:stroke-dash", xUnoAttrs);
+ mxDocumentHandler->endElement( "draw:stroke-dash" );
+ }
+ }
+
+ void SvgDashArray2Odf( sal_Int32 *dots1, double *dots1_length, sal_Int32 *dots2, double
*dots2_length, double *dash_distance )
+ {
+ *dots1 = 0;
+ *dots1_length = 0;
+ *dots2 = 0;
+ *dots2_length = 0;
+ *dash_distance = 0;
+
+ if( maCurrState.maDashArray.size() == 0 ) {
+ return;
+ }
+
+ double effective_dasharray_size = maCurrState.maDashArray.size();
+ if( maCurrState.maDashArray.size() % 2 == 1 )
+ effective_dasharray_size = maCurrState.maDashArray.size()*2;
+
+ *dash_distance = maCurrState.maDashArray[1%maCurrState.maDashArray.size()];
+ sal_Int32 dist_count = 1;
+ for( int i=3; i<effective_dasharray_size; i+=2 ) {
+ *dash_distance = ((dist_count * *dash_distance) +
maCurrState.maDashArray[i%maCurrState.maDashArray.size()])/(dist_count+1);
+ ++dist_count;
+ }
+
+ *dots1 = 1;
+ *dots1_length = maCurrState.maDashArray[0];
+ int i=2;
+ while( ( i<effective_dasharray_size ) && (
maCurrState.maDashArray[i%maCurrState.maDashArray.size()] == *dots1_length ) ) {
+ ++(*dots1);
+ i += 2;
+ }
+ if( i<effective_dasharray_size ) {
+ *dots2 = 1;
+ *dots2_length = maCurrState.maDashArray[i];
+ i+=2;
+ while( ( i<effective_dasharray_size ) && (
maCurrState.maDashArray[i%maCurrState.maDashArray.size()] == *dots2_length ) ) {
+ ++(*dots2);
+ i += 2;
+ }
+ }
+
+ SAL_INFO("svg", "SvgDashArray2Odf " << *dash_distance << " " << *dots1 << " " <<
*dots1_length << " " << *dots2 << " " << *dots2_length );
+
+ return;
+ }
+
+ void push() {}
+ void pop() {}
+
+ State maCurrState;
+ StateMap& mrStateMap;
+ uno::Reference<xml::sax::XDocumentHandler> mxDocumentHandler;
+};
+
+static void writeOfficeStyles( StateMap& rStateMap,
+ const uno::Reference<xml::dom::XElement> xElem,
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocHdl )
+{
+ OfficeStylesWritingVisitor aVisitor( rStateMap, xDocHdl );
+ visitElements( aVisitor, xElem );
+}
#if OSL_DEBUG_LEVEL > 2
struct DumpingVisitor
@@ -1994,6 +2069,9 @@ sal_Bool SVGReader::parseAndConvert()
xAttrs->Clear();
m_xDocumentHandler->startElement( "office:styles", xUnoAttrs);
+ writeOfficeStyles( aStateMap,
+ xDocElem,
+ m_xDocumentHandler);
m_xDocumentHandler->endElement( "office:styles" );
////////////////////////////////////////////////////////////////////
--
1.7.9.5
Context
- [PATCH][REVIEW] use dash parameters from svg file · Christina Roßmanith
Privacy Policy |
Impressum (Legal Info) |
Copyright information: Unless otherwise specified, all text and images
on this website are licensed under the
Creative Commons Attribution-Share Alike 3.0 License.
This does not include the source code of LibreOffice, which is
licensed under the Mozilla Public License (
MPLv2).
"LibreOffice" and "The Document Foundation" are
registered trademarks of their corresponding registered owners or are
in actual use as trademarks in one or more countries. Their respective
logos and icons are also subject to international copyright laws. Use
thereof is explained in our
trademark policy.