Date: prev next · Thread: first prev next last
2012 Archives by date, by thread · List index


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


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.