[Libreoffice-commits] libvisio.git: src/lib src/test

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Wed Jul 24 00:17:27 UTC 2019


 src/lib/VSDContentCollector.cpp     |  126 +++++++++++++++++++++++++++---------
 src/test/data/Visio11FormatLine.vsd |binary
 src/test/importtest.cpp             |   80 +++++++++++++++++++---
 3 files changed, 164 insertions(+), 42 deletions(-)

New commits:
commit d6205a23ff36b1ab1f876cebfd41ad1acf19aac5
Author:     Bartosz Kosiorek <gang65 at poczta.onet.pl>
AuthorDate: Sat Jul 13 07:32:03 2019 +0200
Commit:     Bartosz Kosiorek <gang65 at poczta.onet.pl>
CommitDate: Wed Jul 24 02:17:08 2019 +0200

    tdf#126402 Fix line formating issue
    
    With this commit, I have implemented more Visio arrow styles
    and I have added support importing Center Line Ending.
    
    As a result many import issues of Visio diagrams was resolved.
    
    Change-Id: I5284e3e53b9d5174ab49e841c66be58e06060760
    Reviewed-on: https://gerrit.libreoffice.org/75635
    Tested-by: Bartosz Kosiorek <gang65 at poczta.onet.pl>
    Reviewed-by: Bartosz Kosiorek <gang65 at poczta.onet.pl>

diff --git a/src/lib/VSDContentCollector.cpp b/src/lib/VSDContentCollector.cpp
index 37881bb..dab4782 100644
--- a/src/lib/VSDContentCollector.cpp
+++ b/src/lib/VSDContentCollector.cpp
@@ -157,15 +157,17 @@ const char *libvisio::VSDContentCollector::_linePropertiesMarkerViewbox(unsigned
     return "0 0 20 10";
   case 8:
     return "0 0 20 18";
-  case 3:
+  case 3: // Short line Arrow
+    return "0 0 3000 3000";
   case 4:
   case 5:
   case 6:
-  case 11:
   case 16:
   case 17:
   case 18:
     return "0 0 20 20";
+  case 11: // Centered square filled
+    return "0 0 10 10";
   case 12:
   case 13:
   case 14:
@@ -173,8 +175,8 @@ const char *libvisio::VSDContentCollector::_linePropertiesMarkerViewbox(unsigned
   case 22:
   case 39:
     return "0 0 20 40";
-  case 21:
-    return "0 0 30 30";
+  case 21: // Centered square unfilled
+    return "0 0 300 300";
   case 10:
     return "0 0 1131 1131";
   default:
@@ -184,50 +186,108 @@ const char *libvisio::VSDContentCollector::_linePropertiesMarkerViewbox(unsigned
 
 const char *libvisio::VSDContentCollector::_linePropertiesMarkerPath(unsigned marker)
 {
+  // Information how to draw path
+  // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d
+
+  /*
+  SVG defines 6 types of path commands, for a total of 20 commands:
+
+  MoveTo: M, m
+  LineTo: L, l, H, h, V, v
+  Cubic Bézier Curve: C, c, S, s
+  Quadratic Bézier Curve: Q, q, T, t
+  Elliptical Arc Curve: A, a
+  ClosePath: Z, z
+  */
   switch (marker)
   {
-  case 1:
-    return "m10 -4l-14 14l4 4l10 -10l10 10l4 -4z";
-  case 2:
+  case 1: // TODO
+    return "M1500 0l1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z";
+  case 2: //
     return "m10 0-10 10h20z";
-  case 3:
-    return "m10 -8l-14 28l6 3l8 -16l8 16l6 -3z";
-  case 4:
+  case 3: // Short line arrow, Copied from LO
+    return "M1500 0l1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z";
+  case 4: // Filled equilateral triangle
     return "m10 0-10 20h20z";
-  case 5:
+  case 5: // Arrow concave
     return "m10 0-10 20q10,-5 20,0z";
-  case 6:
+  case 6: //
     return "m10 0-10 20q10,5 20,0z";
-  case 8:
+  case 7: // TODO
     return "m10 0q-2.6,13.4 -10,18q10,-5 20,0q-7.4,-4.6 -10,-18";
-  case 9:
-    return "m-2 -8l4 -4l20 20l-4 4z";
-  case 10: // Copied from what LO exports when using the "circle" marker
-    return "m462 1118-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z";
-  case 11:
-    return "m0 0v10h10v-10z";
-  case 12:
-    return "m10 -12l-14 42l9 3l5 -15l5 15l9 -3z";
+  case 8: // filled arrow
+    return "m10 0q-2.6,13.4 -10,18q10,-5 20,0q-7.4,-4.6 -10,-18";
+  case 9:  // Centered line
+    return "M1 2l1 -1l20 20l-1 1zM11 11v12h1v-10z";//
+  case 10: // Centered Filled circle
+  case 42: // Filled circle, Copied from LO
+    return "m462 1118-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z";//
+  case 11: // Centered square filled, Copied from LO
+    return "M0 0h10v10h-10z";
+  case 12: // TODO
+    return "M1500 0l1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z";
   case 13:
     return "m10 0-10 30h20z";
   case 14:
     return "m10 0-10 30h20z m0 12l-5 15h10z";
   case 15:
-    return "m10 0-10 10h20z m0 3l-5 5h10z";
+    return "m10 0-10 10h20z m0 1l-8 8h16z";
   case 16:
     return "m10 0-10 20h20z m0 7l-5 10h10z";
   case 17:
     return "m10 0-10 20q10,-5 20,0z m0 7l-4 8q4,-2 8,0z";
   case 18:
     return "m10 0-10 20q10,5 20,0z m0 7l-5 10q5,2 10,0z";
-  case 21:
-    return "m0 0v30h30v-30z m10 10v10h10v-10z";
-  case 22:
-    return "m10 0-10 20l10 20l10 -20z m0 8l-6 12l6 12l6 -12z";
-  case 39:
-    return "m10 0-10 20h20z m0 20-10 20h20z";
-  default:
-    return "m10 0-10 30h20z";
+  case 19: // TODO
+    return "m10 0q-2.6,13.4 -10,18q10,-5 20,0q-7.4,-4.6 -10,-18";
+  case 20: // Centered unfilled circle,
+  case 41: // unfilled circle, Copied from LO
+    return "M1500 3000c-276 0-511-63-750-201s-411-310-549-549-201-474-201-750 63-511 201-750 310-411 549-549 474-201 750-201 511 63 750 201 411 310 549 549 201 474 201 750-63 511-201 750-310 411-549 549-474 201-750 201zM1500 2800c-239 0-443-55-650-174s-356-269-476-476-174-411-174-650 55-443 174-650 269-356 476-476c207-119 411-174 650-174s443 55 650 174c207 120 356 269 476 476s174 411 174 650-55 443-174 650-269 356-476 476c-207 119-411 174-650 174z";
+  case 21: // Centered unfilled square, Copied from LO
+    return "M0 0h300v300h-300zM20 20h260v260h-260z";
+  case 22: // Unfilled diamond, Copied from LO
+    return "M1500 0l1500 3000-1500 3000-1500-3000zM1500 447l-1276 2553 1276 2553 1276-2553z";
+  case 23:
+    return "M1 32l1 1l19 -19l-1 -1zM11 0v33h1v-33z";
+  case 24: // CF One, Copied from LO
+    return "M0 0h1v-40h-2v40zM1 0h-20v-2h20zM-1 0h20v-2h-20z";
+  case 25: // CF Only One, Copied from LO
+    return "M0 0h1v-40h-2v40zM1 0h-20v-2h20zM-1 0h20v-2h-20zM1-18h-20v-2h20zM-1-18h20v-2h-20z";
+  case 26: // TODO CF Only One with three lines
+    return "M0 0h1v-40h-2v40zM1 0h-20v-2h20zM-1 0h20v-2h-20zM1-18h-20v-2h20zM-1-18h20v-2h-20z";
+  case 27: // CF Many, Copied from LO
+    return "M1500 0l1500-2789v-211h-114l-1286 2392v-2392h-200v2392l-1286-2392h-114v211z";
+  case 28: // CF Many One, Copied from LO
+    return "M1500 3200h1500v-200h-3000v200zM1500 3000l1500-2789v-211h-114l-1286 2392v-2392h-200v2392l-1286-2392h-114v211z";
+  case 29: // CF Zero Many, Copied from LO
+    return "M-1500 0c0-276 63-511 201-749 138-240 310-411 549-550 239-138 474-201 750-201s511 63 750 201c239 139 411 310 549 549 138 240 201 474 201 750 0 277-63 511-201 750-138 240-310 411-549 550-239 138-474 201-750 201s-511-63-750-201c-239-139-411-310-549-549s-201-474-201-750zM-1350 0c0-248 57-459 181-674 124-216 279-370 494-495 215-124 426-181 675-181s460 57 675 181c215 125 370 279 494 494 124 216 181 427 181 675 0 249-57 460-181 675-124 216-279 370-494 495-215 124-426 181-675 181s-460-57-675-181c-215-125-370-279-494-494-124-216-181-427-181-675zM0-1500l1500-2789v-211h-114l-1286 2392v-2392h-200v2392l-1286-2392h-114v211z";
+  case 30: // CF Zero One, Copied from LO
+    return "M100 4300c0-276 63-511 201-749 138-240 310-411 549-550 239-138 474-201 750-201s511 63 750 201c239 139 411 310 549 549 138 240 201 474 201 750 0 277-63 511-201 750-138 240-310 411-549 550-239 138-474 201-750 201s-511-63-750-201c-239-139-411-310-549-549s-201-474-201-750zM250 4300c0-248 57-459 181-674 124-216 279-370 494-495 215-124 426-181 675-181s460 57 675 181c215 125 370 279 494 494 124 216 181 427 181 675 0 249-57 460-181 675-124 216-279 370-494 495-215 124-426 181-675 181s-460-57-675-181c-215-125-370-279-494-494-124-216-181-427-181-675zM1600 2800h100v-2800h-200v2800zM1700 1400v100h1500v-200h-1500zM1500 1400v100h-1500v-200h1500z";
+  case 31: // TODO unfilled circle and line
+  case 32: // TODO unfilled circle and two lines
+  case 33: // TODO unfilled circle and three lines
+    return "M1500 3000c-276 0-511-63-750-201s-411-310-549-549-201-474-201-750 63-511 201-750 310-411 549-549 474-201 750-201 511 63 750 201 411 310 549 549 201 474 201 750-63 511-201 750-310 411-549 549-474 201-750 201zM1500 2800c-239 0-443-55-650-174s-356-269-476-476-174-411-174-650 55-443 174-650 269-356 476-476c207-119 411-174 650-174s443 55 650 174c207 120 356 269 476 476s174 411 174 650-55 443-174 650-269 356-476 476c-207 119-411 174-650 174z";
+  case 34: // TODO unfilled circle and diamond
+    return "M1500 3000c-276 0-511-63-750-201s-411-310-549-549-201-474-201-750 63-511 201-750 310-411 549-549 474-201 750-201 511 63 750 201 411 310 549 549 201 474 201 750-63 511-201 750-310 411-549 549-474 201-750 201zM1500 2800c-239 0-443-55-650-174s-356-269-476-476-174-411-174-650 55-443 174-650 269-356 476-476c207-119 411-174 650-174s443 55 650 174c207 120 356 269 476 476s174 411 174 650-55 443-174 650-269 356-476 476c-207 119-411 174-650 174z";
+  case 35: // TODO Filled circle with line,
+  case 36: // TODO Filled circle with two lines,
+  case 37: // TODO Filled circle with three lines,
+    return "m462 1118-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z";//
+  case 38: // TODO Filled circle with diamond,
+    return "m462 1118-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z";//
+  case 39: // double filled equilateral triangle arrow, Copied from LO
+    return "M737 1131h394l-564-1131-567 1131h398l-398 787h1131z";
+  case 40: // TODO double unfilled equilateral triangle arrow
+    return "M737 1131h394l-564-1131-567 1131h398l-398 787h1131z";
+  case 43: // TODO double Short line arrow
+    return "M1500 0l1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z";
+  case 44: // TODO Short line arrow with line
+    return "M1500 0l1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z";
+  case 45: // TODO double Short line arrow with line
+    return "M1500 0l1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z";
+
+  default: // default arrow
+    return "m10 0-10 30h20z";//
   }
 }
 
@@ -2902,7 +2962,9 @@ void libvisio::VSDContentCollector::_lineProperties(const VSDLineStyle &style, l
   switch (style.cap)
   {
   case 0:
+    // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap
     styleProps.insert("svg:stroke-linecap", "round");
+    // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linejoin
     styleProps.insert("svg:stroke-linejoin", "round");
     break;
   case 2:
@@ -2919,6 +2981,8 @@ void libvisio::VSDContentCollector::_lineProperties(const VSDLineStyle &style, l
   if (style.startMarker > 0)
   {
     styleProps.insert("draw:marker-start-viewbox", _linePropertiesMarkerViewbox(style.startMarker));
+    if ((style.startMarker == 9) || (style.startMarker == 10) || (style.startMarker == 11) || (style.startMarker == 20) || (style.startMarker == 21))
+      styleProps.insert("draw:marker-start-center", "true");
     styleProps.insert("draw:marker-start-path", _linePropertiesMarkerPath(style.startMarker));
     double w =  m_scale*_linePropertiesMarkerScale(style.startMarker)*(0.1/(style.width*style.width+1)+2.54*style.width);
     styleProps.insert("draw:marker-start-width", (std::max)(w, 0.05));
@@ -2926,6 +2990,8 @@ void libvisio::VSDContentCollector::_lineProperties(const VSDLineStyle &style, l
   if (style.endMarker > 0)
   {
     styleProps.insert("draw:marker-end-viewbox", _linePropertiesMarkerViewbox(style.endMarker));
+    if ((style.endMarker == 9) || (style.endMarker == 10) || (style.endMarker == 11) || (style.endMarker == 20) || (style.endMarker == 21))
+      styleProps.insert("draw:marker-end-center", "true");
     styleProps.insert("draw:marker-end-path", _linePropertiesMarkerPath(style.endMarker));
     double w =  m_scale*_linePropertiesMarkerScale(style.endMarker)*(0.1/(style.width*style.width+1)+2.54*style.width);
     styleProps.insert("draw:marker-end-width", (std::max)(w, 0.05));
diff --git a/src/test/data/Visio11FormatLine.vsd b/src/test/data/Visio11FormatLine.vsd
new file mode 100644
index 0000000..c06587d
Binary files /dev/null and b/src/test/data/Visio11FormatLine.vsd differ
diff --git a/src/test/importtest.cpp b/src/test/importtest.cpp
index 2b3a0b2..468f362 100644
--- a/src/test/importtest.cpp
+++ b/src/test/importtest.cpp
@@ -39,6 +39,7 @@ xmlXPathObjectPtr getXPathNode(xmlDocPtr doc, const librevenge::RVNGString &xpat
 /// Same as the assertXPath(), but don't assert: return the string instead.
 librevenge::RVNGString getXPath(xmlDocPtr doc, const librevenge::RVNGString &xpath, const librevenge::RVNGString &attribute)
 {
+  CPPUNIT_ASSERT(doc);
   xmlXPathObjectPtr xpathobject = getXPathNode(doc, xpath);
   xmlNodeSetPtr nodeset = xpathobject->nodesetval;
 
@@ -113,18 +114,45 @@ void assertBmpDataOffset(xmlDocPtr doc, const librevenge::RVNGString &xpath, con
 /// Same as the assertXPathContent(), but don't assert: return the string instead.
 librevenge::RVNGString getXPathContent(xmlDocPtr doc, const librevenge::RVNGString &xpath)
 {
-  xmlXPathObjectPtr xpathObject = getXPathNode(doc, xpath);
-  xmlNodeSetPtr nodeset = xpathObject->nodesetval;
-
-  librevenge::RVNGString message("XPath '");
-  message.append(xpath);
-  message.append("': not found.");
-  CPPUNIT_ASSERT_MESSAGE(message.cstr(), xmlXPathNodeSetGetLength(nodeset) > 0);
+  xmlXPathObjectPtr xpathobject = getXPathNode(doc, xpath);
+  switch (xpathobject->type)
+  {
+      case XPATH_UNDEFINED:
+          CPPUNIT_FAIL("Undefined XPath type");
+      case XPATH_NODESET:
+      {
+          xmlNodeSetPtr nodeset = xpathobject->nodesetval;
+
+          librevenge::RVNGString message("XPath '");
+          message.append(xpath);
+          message.append("': not found.");
+          CPPUNIT_ASSERT_MESSAGE(message.cstr(), xmlXPathNodeSetGetLength(nodeset) > 0);
+
+          xmlNodePtr xmlnode = nodeset->nodeTab[0];
+          xmlNodePtr xmlchild = xmlnode->children;
+          librevenge::RVNGString s;
+          while (xmlchild && xmlchild->type != XML_TEXT_NODE)
+              xmlchild = xmlchild->next;
+          if (xmlchild && xmlchild->type == XML_TEXT_NODE)
+              s = (reinterpret_cast<char *>((xmlnode->children[0]).content));
+          xmlXPathFreeObject(xpathobject);
+          return s;
+      }
+      case XPATH_BOOLEAN:
+          return xpathobject->boolval ? librevenge::RVNGString("true") : librevenge::RVNGString("false");
+      case XPATH_STRING:
+          return librevenge::RVNGString(reinterpret_cast<char *>(xpathobject->stringval));
+      case XPATH_NUMBER:
+      case XPATH_POINT:
+      case XPATH_RANGE:
+      case XPATH_LOCATIONSET:
+      case XPATH_USERS:
+      case XPATH_XSLT_TREE:
+          CPPUNIT_FAIL("Unsupported XPath type");
+  }
+
+  CPPUNIT_FAIL("Invalid XPath type");
 
-  xmlNodePtr node = nodeset->nodeTab[0];
-  librevenge::RVNGString s(reinterpret_cast<char *>((node->children[0]).content));
-  xmlXPathFreeObject(xpathObject);
-  return s;
 }
 /// Assert that xpath exists, and its content equals to content.
 void assertXPathContent(xmlDocPtr doc, const librevenge::RVNGString &xpath, const librevenge::RVNGString &content)
@@ -153,7 +181,7 @@ xmlDocPtr parse(const char *filename, xmlBufferPtr buffer)
   xmlTextWriterEndDocument(writer);
   xmlFreeTextWriter(writer);
 
-  // std::cerr << "XML is '" << (const char *)xmlBufferContent(buffer) << "'" << std::endl;
+  //std::cerr << "XML is '" << (const char *)xmlBufferContent(buffer) << "'" << std::endl;
   return xmlParseMemory((const char *)xmlBufferContent(buffer), xmlBufferLength(buffer));
 }
 
@@ -178,6 +206,7 @@ class ImportTest : public CPPUNIT_NS::TestFixture
   CPPUNIT_TEST(testVsdTextBlockWithoutBgColor);
   CPPUNIT_TEST(testVsdNumericFormat);
   CPPUNIT_TEST(testVsdDateTimeFormatting);
+  CPPUNIT_TEST(testVsd11FormatLine);
   CPPUNIT_TEST(testVsd6TextfieldsWithUnits);
   CPPUNIT_TEST(testVsd11TextfieldsWithUnits);
   CPPUNIT_TEST(testBmpFileHeader);
@@ -193,6 +222,7 @@ class ImportTest : public CPPUNIT_NS::TestFixture
   void testVsdxCharBgColor();
   void testVsdTextBlockWithoutBgColor();
   void testVsdNumericFormat();
+  void testVsd11FormatLine();
   void testVsdDateTimeFormatting();
   void testVsd6TextfieldsWithUnits();
   void testVsd11TextfieldsWithUnits();
@@ -337,6 +367,32 @@ void ImportTest::testVsdDateTimeFormatting()
   assertXPathContent(m_doc, "/document/page/textObject/paragraph/span/insertText", "11/30/2005");
 }
 
+
+// tdf#126402
+void ImportTest::testVsd11FormatLine()
+{
+  m_doc = parse("Visio11FormatLine.vsd", m_buffer);
+  assertXPathNoAttribute(m_doc, "/document/page/setStyle[4]", "marker-end-center");
+
+  // Centered filled circle, copied from LO to be able to edit
+  assertXPath(m_doc, "/document/page/setStyle[5]", "marker-end-path",
+              "m462 1118-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z");
+  assertXPath(m_doc, "/document/page/setStyle[5]", "marker-end-center", "true");
+  // Centered line
+  assertXPath(m_doc, "/document/page/setStyle[5]", "marker-start-path", "M1 2l1 -1l20 20l-1 1zM11 11v12h1v-10z");
+  assertXPath(m_doc, "/document/page/setStyle[5]", "marker-start-center", "true");
+
+  assertXPath(m_doc, "/document/page/setStyle[6]", "marker-end-path",
+              "M1500 0l1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z");
+  assertXPathNoAttribute(m_doc, "/document/page/setStyle[6]", "marker-end-center");
+  assertXPath(m_doc, "/document/page/setStyle[6]", "marker-start-center", "true");
+  assertXPathNoAttribute(m_doc, "/document/page/setStyle[11]", "marker-start-center");
+  assertXPath(m_doc, "/document/page/setStyle[11]", "marker-end-center", "true");
+  assertXPathNoAttribute(m_doc, "/document/page/setStyle[12]", "marker-end-center");
+  assertXPath(m_doc, "/document/page/setStyle[12]", "marker-start-center", "true");
+}
+
+
 // tdf#126292
 void ImportTest::testVsd6TextfieldsWithUnits()
 {


More information about the Libreoffice-commits mailing list