summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartosz Kosiorek <gang65@poczta.onet.pl>2019-07-13 07:32:03 +0200
committerBartosz Kosiorek <gang65@poczta.onet.pl>2019-07-24 02:17:08 +0200
commitd6205a23ff36b1ab1f876cebfd41ad1acf19aac5 (patch)
tree51ac1fd869bd9eb978849a3a73022115ddf0b454
parent2ae597695c8ad41dcbdba8405157053a44564abb (diff)
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@poczta.onet.pl> Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
-rw-r--r--src/lib/VSDContentCollector.cpp126
-rw-r--r--src/test/data/Visio11FormatLine.vsdbin0 -> 73728 bytes
-rw-r--r--src/test/importtest.cpp80
3 files changed, 164 insertions, 42 deletions
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
--- /dev/null
+++ b/src/test/data/Visio11FormatLine.vsd
Binary files 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()
{