File indexing completed on 2024-05-12 16:29:14

0001 /*
0002  * This file is part of Office 2007 Filters for Calligra
0003  *
0004  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
0005  *
0006  * Contact: Suresh Chande suresh.chande@nokia.com
0007  *
0008  * This library is free software; you can redistribute it and/or
0009  * modify it under the terms of the GNU Lesser General Public License
0010  * version 2.1 as published by the Free Software Foundation.
0011  *
0012  * This library is distributed in the hope that it will be useful, but
0013  * WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library; if not, write to the Free Software
0019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020  * 02110-1301 USA
0021  *
0022  */
0023 
0024 #ifndef MSOOXMLVMLREADER_IMPL_H
0025 #define MSOOXMLVMLREADER_IMPL_H
0026 
0027 #include <math.h>
0028 
0029 #undef MSOOXML_CURRENT_NS
0030 #define MSOOXML_CURRENT_NS "v"
0031 
0032 //#define VMLREADER_DEBUG
0033 
0034 //! Used by read_rect() to parse CSS2.
0035 //! See ECMA-376 Part 4, 14.1.2.16, p.465.
0036 //! @todo reuse KHTML parser?
0037 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::parseCSS(const QString& style)
0038 {
0039     m_currentVMLProperties.vmlStyle.clear();
0040     foreach( const QString& pair, style.split(';', QString::SkipEmptyParts)) {
0041         const int splitIndex = pair.indexOf(':');
0042         if (splitIndex < 1) {
0043             continue;
0044         }
0045         const QByteArray name(pair.left(splitIndex).toLatin1().trimmed());
0046         QString value(pair.mid(splitIndex+1).trimmed());
0047         if (name.isEmpty()) {
0048             continue;
0049         }
0050         if (value.startsWith(QLatin1Char('\'')) && value.endsWith(QLatin1Char('\''))) {
0051             value.remove(0, 1).chop(1);
0052         }
0053 #ifdef VMLREADER_DEBUG
0054         debugMsooXml << "name:" << name << "value:" << value;
0055 #endif
0056         m_currentVMLProperties.vmlStyle.insert(name, value);
0057     }
0058     return KoFilter::OK;
0059 }
0060 
0061 static void doPrependCheck(QString& checkedString) {
0062     if (!checkedString.isEmpty()) {
0063         if (checkedString.at(0) == '.') {
0064             checkedString.prepend("0");
0065         }
0066     }
0067 }
0068 
0069 static void changeToPoints(QString &value) {
0070     QString unit = value.right(2);
0071     if (unit == "pt") {
0072         return;
0073     }
0074     if (value == "0") {
0075         value = "0pt";
0076     }
0077     qreal number = value.left(value.size() - 2).toDouble();
0078     if (unit == "in") {
0079         number = number * 71;
0080     }
0081     else if (unit == "mm") {
0082         number = number * 56.6929130287 / 20.0;
0083     }
0084     else if (unit == "cm") {
0085         number = number * 566.929098146 / 20.0;
0086     }
0087     value = QString("%1pt").arg(number);
0088 }
0089 
0090 void MSOOXML_CURRENT_CLASS::createFrameStart(FrameStartElement startType)
0091 {
0092     // Todo handle here all possible shape types
0093     if (startType == RectStart) {
0094         body->startElement("draw:rect");
0095     }
0096     else if (startType == EllipseStart) {
0097         body->startElement("draw:ellipse");
0098     }
0099     // Simplifying connector to be a line
0100     else if (startType == LineStart) {
0101         body->startElement("draw:line");
0102     }
0103     else if (startType == GroupStart) {
0104         body->startElement("draw:g");
0105     }
0106     else if (startType == CustomStart) {
0107         body->startElement("draw:custom-shape");
0108     }
0109     else {
0110         body->startElement("draw:frame");
0111     }
0112 
0113     QString width(m_currentVMLProperties.vmlStyle.value("width")); // already in "...cm" format
0114     doPrependCheck(width);
0115     QString height(m_currentVMLProperties.vmlStyle.value("height")); // already in "...cm" format
0116     doPrependCheck(height);
0117     QString x_mar(m_currentVMLProperties.vmlStyle.value("margin-left"));
0118     doPrependCheck(x_mar);
0119     QString y_mar(m_currentVMLProperties.vmlStyle.value("margin-top"));
0120     doPrependCheck(y_mar);
0121     QString leftPos(m_currentVMLProperties.vmlStyle.value("left"));
0122     doPrependCheck(leftPos);
0123     QString topPos(m_currentVMLProperties.vmlStyle.value("top"));
0124     doPrependCheck(topPos);
0125     QString position(m_currentVMLProperties.vmlStyle.value("position"));
0126     QString hor_pos(m_currentVMLProperties.vmlStyle.value("mso-position-horizontal"));
0127     QString ver_pos(m_currentVMLProperties.vmlStyle.value("mso-position-vertical"));
0128     QString hor_pos_rel(m_currentVMLProperties.vmlStyle.value("mso-position-horizontal-relative"));
0129     QString ver_pos_rel(m_currentVMLProperties.vmlStyle.value("mso-position-vertical-relative"));
0130     const QString ver_align(m_currentVMLProperties.vmlStyle.value("v-text-anchor"));
0131     QString rotation(m_currentVMLProperties.vmlStyle.value("rotation"));
0132     const QString z_index(m_currentVMLProperties.vmlStyle.value("z-index"));
0133     qreal rotationAngle = 0;
0134     if (!rotation.isEmpty()) {
0135         if (rotation.endsWith(QLatin1String("fd"))) {
0136             rotationAngle = rotation.left(rotation.length()-2).toDouble() / 65536.0;
0137         }
0138         else {
0139             rotationAngle = rotation.toDouble();
0140         }
0141         rotationAngle = rotationAngle / 180.0 * M_PI;
0142     }
0143 
0144     qreal x_position = 0;
0145     QString x_pos_string, y_pos_string, widthString, heightString;
0146     qreal y_position = 0;
0147     qreal widthValue = 0;
0148     qreal heightValue = 0;
0149 
0150     /* NOTE: The default value of props. in {height, left, margin-*,
0151      * mso-wrp-distance-*, rotation, top, width, z-index} is 0. */
0152     QString *p_str = 0;
0153 
0154     //horizontal position
0155     if (m_currentVMLProperties.insideGroup) {
0156         if (!x_mar.isEmpty()) {
0157             x_position = (x_mar.toDouble() - m_currentVMLProperties.groupX) * m_currentVMLProperties.real_groupWidth /
0158                          m_currentVMLProperties.groupWidth + m_currentVMLProperties.groupXOffset;
0159             x_pos_string = QString("%1pt").arg(x_position);
0160         }
0161         else if (!leftPos.isEmpty()) {
0162             x_position = (leftPos.toDouble() - m_currentVMLProperties.groupX) * m_currentVMLProperties.real_groupWidth /
0163                          m_currentVMLProperties.groupWidth + m_currentVMLProperties.groupXOffset;
0164             x_pos_string = QString("%1pt").arg(x_position);
0165         } else {
0166             x_pos_string = QString("%1pt").arg(m_currentVMLProperties.groupXOffset);
0167         }
0168 
0169     } else {
0170         if (!x_mar.isEmpty()) {
0171             p_str = &x_mar;
0172         }
0173         else if (!leftPos.isEmpty()) {
0174             p_str = &leftPos;
0175         }
0176         //TODO: Add support for auto and percentage values.
0177         if (p_str && !(*p_str == "auto" || p_str->endsWith("%"))) {
0178             if (*p_str == "0") {
0179                 p_str->append("in");
0180             }
0181             x_position = p_str->left(p_str->length() - 2).toDouble();
0182             x_pos_string = *p_str;
0183             p_str = 0;
0184         }
0185     }
0186 
0187     //vertical position
0188     if (m_currentVMLProperties.insideGroup) {
0189         if (!y_mar.isEmpty()) {
0190             y_position = (y_mar.toDouble() - m_currentVMLProperties.groupY) * m_currentVMLProperties.real_groupHeight /
0191                 m_currentVMLProperties.groupHeight + m_currentVMLProperties.groupYOffset;
0192             y_pos_string = QString("%1pt").arg(y_position);
0193         }
0194         else if (!topPos.isEmpty()) {
0195             y_position = (topPos.toDouble() - m_currentVMLProperties.groupY) * m_currentVMLProperties.real_groupHeight /
0196                 m_currentVMLProperties.groupHeight + m_currentVMLProperties.groupYOffset;
0197             y_pos_string = QString("%1pt").arg(y_position);
0198         } else {
0199             y_pos_string = QString("%1pt").arg(m_currentVMLProperties.groupYOffset);
0200         }
0201     } else {
0202         if (!y_mar.isEmpty()) {
0203             p_str = &y_mar;
0204         }
0205         else if (!topPos.isEmpty()) {
0206             p_str = &topPos;
0207         }
0208         //TODO: Add support for auto and percentage values.
0209         if (p_str && !(*p_str == "auto" || p_str->endsWith("%"))) {
0210             if (*p_str == "0") {
0211                 p_str->append("in");
0212             }
0213             y_position = p_str->left(p_str->length() - 2).toDouble();
0214             y_pos_string = *p_str;
0215             p_str = 0;
0216         }
0217     }
0218 
0219     //width
0220     if (m_currentVMLProperties.insideGroup) {
0221         if (!width.isEmpty()) {
0222             widthValue = width.toDouble() * m_currentVMLProperties.real_groupWidth /
0223                          m_currentVMLProperties.groupWidth;
0224             widthString = QString("%1pt").arg(widthValue);
0225         }
0226     } else {
0227         if (width.isEmpty() || width == "0") {
0228             width = "0in";
0229         }
0230         //TODO: Add support for auto and percentage values.
0231         if (!(width == "auto" || width.endsWith('%'))) {
0232             widthValue = width.left(width.length() - 2).toDouble();
0233             widthString = width;
0234         }
0235     }
0236 
0237     //height
0238     if (m_currentVMLProperties.insideGroup) {
0239         if (!height.isEmpty()) {
0240             heightValue = height.toDouble() * m_currentVMLProperties.real_groupHeight /
0241                           m_currentVMLProperties.groupHeight;
0242             heightString = QString("%1pt").arg(heightValue);
0243         }
0244     } else {
0245         if (height.isEmpty() || height == "0") {
0246             height = "0in";
0247         }
0248         //TODO: Add support for auto and percentage values.
0249         if (!(height == "auto" || height.endsWith('%'))) {
0250             heightValue = height.left(height.length() - 2).toDouble();
0251             heightString = height;
0252         }
0253     }
0254 
0255     if (startType == LineStart) {
0256         QString flip(m_currentVMLProperties.vmlStyle.value("flip"));
0257         QString y1 = y_pos_string;
0258         // right(2) takes the unit
0259         QString x2 = QString("%1%2").arg(x_position + widthValue).arg(widthString.right(2));
0260         QString x1 = x_pos_string;
0261         QString y2 = QString("%1%2").arg(y_position + heightValue).arg(heightString.right(2));
0262         if (flip.contains('x')) {
0263             QString temp = y2;
0264             y2 = y1;
0265             y1 = temp;
0266         }
0267         if (flip.contains('y')) {
0268             QString temp = x2;
0269             x2 = x1;
0270             x1 = temp;
0271         }
0272         body->addAttribute("svg:x1", x1);
0273         body->addAttribute("svg:y1", y1);
0274         body->addAttribute("svg:x2", x2);
0275         body->addAttribute("svg:y2", y2);
0276     }
0277     else {
0278         if (startType != GroupStart) {
0279             if (rotationAngle != 0) {
0280                 changeToPoints(widthString);
0281                 changeToPoints(heightString);
0282                 changeToPoints(x_pos_string);
0283                 changeToPoints(y_pos_string);
0284                 qreal width_rot = widthString.left(widthString.length()-2).toDouble();
0285                 qreal height_rot = heightString.left(heightString.length()-2).toDouble();
0286                 qreal left_rot = x_pos_string.left(x_pos_string.length()-2).toDouble();
0287                 qreal top_rot = y_pos_string.left(y_pos_string.length()-2).toDouble();
0288                 qreal xDiff = width_rot/2 - cos(rotationAngle)*width_rot/2 + sin(rotationAngle)*height_rot/2;
0289                 qreal yDiff = height_rot/2 - sin(rotationAngle)*width_rot/2 - cos(rotationAngle)*height_rot/2;
0290                 QString rotString = QString("rotate(%1) translate(%2pt %3pt)")
0291                                 .arg(-rotationAngle).arg(left_rot + xDiff).arg(top_rot + yDiff);
0292                 body->addAttribute("draw:transform", rotString);
0293             }
0294             else {
0295                 if (!x_pos_string.isEmpty()) {
0296                     body->addAttribute("svg:x", x_pos_string);
0297                 }
0298                 if (!y_pos_string.isEmpty()) {
0299                     body->addAttribute("svg:y", y_pos_string);
0300                 }
0301             }
0302             body->addAttribute("svg:width", widthString);
0303             body->addAttribute("svg:height", heightString);
0304         }
0305     }
0306 
0307     //TODO: VML allows negative numbers, ODF does NOT!  Using
0308     //automatic ordering in case of negative numbers temporary.
0309     if (!z_index.isEmpty() && z_index != "auto") {
0310         bool ok;
0311         const int n = z_index.toInt(&ok);
0312         if (!ok) {
0313             debugMsooXml << "error converting" << z_index << "to int (attribute z-index)";
0314         }
0315         else if (n >= 0) {
0316             body->addAttribute("draw:z-index", n);
0317         }
0318     }
0319 
0320     bool asChar = false;
0321     if (position.isEmpty() || position == "static") {
0322         asChar = true;
0323     }
0324 
0325     if (!hor_pos_rel.isEmpty()) {
0326         if (hor_pos_rel == "outer-margin-area" || hor_pos_rel == "left-margin-area") {
0327             hor_pos_rel = "page-start-margin";
0328             m_currentVMLProperties.anchorType = "paragraph"; //forced
0329         }
0330         else if (hor_pos_rel == "margin") {
0331             hor_pos_rel = "page-content";
0332             m_currentVMLProperties.anchorType = "paragraph"; //forced
0333         }
0334         else if (hor_pos_rel == "inner-margin-area" || hor_pos_rel == "right-margin-area") {
0335             hor_pos_rel = "page-end-margin";
0336             m_currentVMLProperties.anchorType = "paragraph"; //forced
0337         }
0338         else if (hor_pos_rel == "text") {
0339             hor_pos_rel = "paragraph";
0340         }
0341         if (!asChar) {
0342             m_currentDrawStyle->addProperty("style:horizontal-rel", hor_pos_rel);
0343         }
0344     }
0345 #ifdef DOCXXMLDOCUMENTREADER_H
0346     if (!ver_pos_rel.isEmpty()) {
0347         if (ver_pos_rel == "margin" || ver_pos_rel == "line") {
0348             if (m_headerActive || m_footerActive) {
0349                 m_currentDrawStyle->addProperty("style:vertical-rel", "frame-content");
0350             } else {
0351                 m_currentDrawStyle->addProperty("style:vertical-rel", "page-content");
0352             }
0353         }
0354         else if (ver_pos_rel == "top-margin-area" || ver_pos_rel == "inner-margin-area" ||
0355                  ver_pos_rel == "outer-margin-area") {
0356             if (m_headerActive || m_footerActive) {
0357                 m_currentDrawStyle->addProperty("style:vertical-rel", "frame");
0358             } else {
0359                 m_currentDrawStyle->addProperty("style:vertical-rel", "page");
0360             }
0361         }
0362         else if (ver_pos_rel == "bottom-margin-area") {
0363             if (m_headerActive || m_footerActive) {
0364                 m_currentDrawStyle->addProperty("style:vertical-rel", "frame");
0365             } else {
0366                 m_currentDrawStyle->addProperty("style:vertical-rel", "page");
0367             }
0368             // This effectively emulates the bottom-margin-area
0369             m_currentDrawStyle->addProperty("style:vertical-pos", "bottom");
0370         }
0371         else {
0372             m_currentDrawStyle->addProperty("style:vertical-rel", ver_pos_rel);
0373         }
0374     }
0375 
0376     if (!m_currentVMLProperties.wrapRead) {
0377         m_currentDrawStyle->addProperty("style:wrap", "none");
0378         if (asChar) { // Default
0379             body->addAttribute("text:anchor-type", "as-char");
0380             if (ver_pos_rel == "line") {
0381                 m_currentDrawStyle->addProperty("style:vertical-rel", "text");
0382             }
0383         }
0384         else {
0385             body->addAttribute("text:anchor-type", "char");
0386             if (m_currentDrawStyle->property("style:vertical-rel").isEmpty()) {
0387                 m_currentDrawStyle->addProperty("style:vertical-rel", "paragraph");
0388             }
0389             if (m_currentDrawStyle->property("style:horizontal-rel").isEmpty()) {
0390                 m_currentDrawStyle->addProperty("style:horizontal-rel", "paragraph");
0391             }
0392 
0393             if (m_currentVMLProperties.vmlStyle.contains("z-index")) {
0394                 m_currentDrawStyle->addProperty("style:wrap", "run-through");
0395                 if (m_currentVMLProperties.vmlStyle.value("z-index").toInt() > 0) {
0396                     m_currentDrawStyle->addProperty("style:run-through", "foreground");
0397                 }
0398                 else {
0399                     m_currentDrawStyle->addProperty("style:run-through", "background");
0400                 }
0401             }
0402             else {
0403                 m_currentDrawStyle->addProperty("style:wrap", "run-through");
0404                 m_currentDrawStyle->addProperty("style:run-through", "foreground");
0405             }
0406         }
0407     }
0408     else {
0409         body->addAttribute("text:anchor-type", m_currentVMLProperties.anchorType.isEmpty() ? "char": m_currentVMLProperties.anchorType);
0410     }
0411     if (!asChar) {
0412         if (hor_pos.isEmpty() || hor_pos == "absolute") {
0413             hor_pos = "from-left";
0414         }
0415         m_currentDrawStyle->addProperty("style:horizontal-pos", hor_pos);
0416     }
0417     if (ver_pos.isEmpty() || ver_pos == "absolute") {
0418         if (asChar) {
0419             m_currentDrawStyle->addProperty("style:vertical-pos", "bottom");
0420         }
0421         else {
0422             m_currentDrawStyle->addProperty("style:vertical-pos", "from-top");
0423         }
0424     }
0425     else {
0426         if (ver_pos == "center") {
0427             ver_pos = "middle";
0428         }
0429         m_currentDrawStyle->addProperty("style:vertical-pos", ver_pos);
0430     }
0431 #endif
0432 
0433     m_currentDrawStyle->addProperty("svg:stroke-width", m_currentVMLProperties.strokeWidth);
0434     m_currentDrawStyle->addProperty("svg:stroke-color", m_currentVMLProperties.strokeColor);
0435     m_currentDrawStyle->addProperty("svg:stroke-linecap", m_currentVMLProperties.lineCapStyle);
0436     m_currentDrawStyle->addProperty("draw:stroke-linejoin", m_currentVMLProperties.joinStyle);
0437     if (m_currentVMLProperties.stroked) {
0438         if (m_currentVMLProperties.strokeStyleName.isEmpty()) {
0439             m_currentDrawStyle->addProperty("draw:stroke", "solid");
0440         }
0441         else {
0442             m_currentDrawStyle->addProperty("draw:stroke", "dash");
0443             m_currentDrawStyle->addProperty("draw:stroke-dash", m_currentVMLProperties.strokeStyleName);
0444         }
0445     }
0446     else {
0447         m_currentDrawStyle->addProperty("draw:stroke", "none");
0448     }
0449 
0450     if (m_currentVMLProperties.filled) {
0451         if (m_currentVMLProperties.fillType == "solid") {
0452             m_currentDrawStyle->addProperty("draw:fill", "solid");
0453             m_currentDrawStyle->addProperty("draw:fill-color", m_currentVMLProperties.shapeColor);
0454         }
0455         else if (m_currentVMLProperties.fillType == "gradient" || m_currentVMLProperties.fillType == "gradientRadial") {
0456             m_currentDrawStyle->addProperty("draw:fill", "gradient");
0457             m_currentDrawStyle->addProperty("draw:fill-gradient-name", m_currentVMLProperties.gradientStyle);
0458         }
0459         else if (m_currentVMLProperties.fillType == "picture" || m_currentVMLProperties.fillType == "pattern") {
0460             KoGenStyle fillStyle = KoGenStyle(KoGenStyle::FillImageStyle);
0461             fillStyle.addProperty("xlink:href", m_currentVMLProperties.imagedataPath);
0462             fillStyle.addProperty("xlink:type", "simple");
0463             fillStyle.addProperty("xlink:actuate", "onLoad");
0464             const QString imageName = mainStyles->insert(fillStyle);
0465             m_currentDrawStyle->addProperty("draw:fill", "bitmap");
0466             m_currentDrawStyle->addProperty("draw:fill-image-name", imageName);
0467             if (m_currentVMLProperties.fillType == "picture") {
0468                 m_currentDrawStyle->addProperty("style:repeat", "stretch");
0469             }
0470             else {
0471                 m_currentDrawStyle->addProperty("style:repeat", "repeat");
0472             }
0473         }
0474     }
0475     else {
0476         m_currentDrawStyle->addProperty("draw:fill", "none");
0477     }
0478 
0479     if (!ver_align.isEmpty()) {
0480         m_currentDrawStyle->addProperty("draw:textarea-vertical-align", ver_align);
0481     }
0482 
0483     if (m_currentVMLProperties.shadowed == true) {
0484         m_currentDrawStyle->addProperty("draw:shadow", "visible");
0485     }
0486     else {
0487         m_currentDrawStyle->addProperty("draw:shadow", "hidden");
0488     }
0489     m_currentDrawStyle->addProperty("draw:shadow-color", m_currentVMLProperties.shadowColor);
0490 
0491     // ------------------------------
0492     // shadow offset
0493     // ------------------------------
0494     QString offset = m_currentVMLProperties.shadowXOffset;
0495     if (offset.endsWith(QLatin1Char('%'))) {
0496         offset.chop(1);
0497         bool ok;
0498         int p = offset.toInt(&ok);
0499         if (!ok) {
0500             debugMsooXml << "error converting" << offset << "to int (shadow x-offset)";
0501         } else {
0502             offset = QString::number(p * widthValue / 100.0,'f').append(widthString.right(2));
0503         }
0504     }
0505     m_currentDrawStyle->addProperty("draw:shadow-offset-x", offset);
0506 
0507     offset = m_currentVMLProperties.shadowYOffset;
0508     if (offset.endsWith(QLatin1Char('%'))) {
0509         offset.chop(1);
0510         bool ok;
0511         int p = offset.toInt(&ok);
0512         if (!ok) {
0513             debugMsooXml << "error converting" << offset << "to int (shadow y-offset)";
0514         } else {
0515             offset = QString::number(p * heightValue / 100.0,'f').append(heightString.right(2));
0516         }
0517     }
0518     m_currentDrawStyle->addProperty("draw:shadow-offset-y", offset);
0519     // ------------------------------
0520 
0521     if (m_currentVMLProperties.shadowOpacity > 0) {
0522         m_currentDrawStyle->addProperty("draw:shadow-opacity", QString("%1%").
0523             arg(m_currentVMLProperties.shadowOpacity));
0524     }
0525 
0526     if (m_currentVMLProperties.opacity > 0) {
0527         m_currentDrawStyle->addProperty("draw:opacity", QString("%1%").arg(m_currentVMLProperties.opacity));
0528     }
0529 
0530     // FIXME: The draw:fit-to-size attribute specifies whether to stretch the
0531     // text content of a drawing object to fill an entire object.  The
0532     // style:shrink-to-fit attribute specifies whether content is reduced in
0533     // size to fit within a cell or drawing object.  Shrinking means that the
0534     // font size of the content is decreased to fit the content into a cell or
0535     // drawing object.  That's needed to be compatible with MS PowerPoint.  Any
0536     // margin, padding or indent MUST be retained.
0537     if (m_currentVMLProperties.fitTextToShape) {
0538         m_currentDrawStyle->addProperty("draw:fit-to-size", "true");
0539     }
0540 
0541     if (m_currentVMLProperties.fitShapeToText) {
0542         m_currentDrawStyle->addProperty("draw:auto-grow-height", "true");
0543         m_currentDrawStyle->addProperty("draw:auto-grow-width", "true");
0544     }
0545 
0546     // --------------------
0547     // padding
0548     // --------------------
0549 #ifdef VMLREADER_DEBUG
0550     debugMsooXml << this << "padding-left:" << m_currentVMLProperties.internalMarginLeft;
0551     debugMsooXml << this << "padding-top:" << m_currentVMLProperties.internalMarginTop;
0552     debugMsooXml << this << "padding-right:" << m_currentVMLProperties.internalMarginRight;
0553     debugMsooXml << this << "padding-bottom:" << m_currentVMLProperties.internalMarginBottom;
0554 #endif
0555     m_currentDrawStyle->addProperty("fo:padding-left", m_currentVMLProperties.internalMarginLeft);
0556     m_currentDrawStyle->addProperty("fo:padding-right", m_currentVMLProperties.internalMarginRight);
0557     m_currentDrawStyle->addProperty("fo:padding-top", m_currentVMLProperties.internalMarginTop);
0558     m_currentDrawStyle->addProperty("fo:padding-bottom", m_currentVMLProperties.internalMarginBottom);
0559 
0560     // --------------------
0561     // margins
0562     // --------------------
0563     QString *p_margin = &m_currentVMLProperties.marginLeft;
0564     if (m_currentVMLProperties.vmlStyle.contains("mso-wrap-distance-left")) {
0565         *p_margin = m_currentVMLProperties.vmlStyle.value("mso-wrap-distance-left");
0566         doPrependCheck(*p_margin);
0567         changeToPoints(*p_margin);
0568     }
0569     p_margin = &m_currentVMLProperties.marginTop;
0570     if (m_currentVMLProperties.vmlStyle.contains("mso-wrap-distance-top")) {
0571         *p_margin = m_currentVMLProperties.vmlStyle.value("mso-wrap-distance-top");
0572         doPrependCheck(*p_margin);
0573         changeToPoints(*p_margin);
0574     }
0575     p_margin = &m_currentVMLProperties.marginRight;
0576     if (m_currentVMLProperties.vmlStyle.contains("mso-wrap-distance-right")) {
0577         *p_margin = m_currentVMLProperties.vmlStyle.value("mso-wrap-distance-right");
0578         doPrependCheck(*p_margin);
0579         changeToPoints(*p_margin);
0580     }
0581     p_margin = &m_currentVMLProperties.marginBottom;
0582     if (m_currentVMLProperties.vmlStyle.contains("mso-wrap-distance-bottom")) {
0583         *p_margin = m_currentVMLProperties.vmlStyle.value("mso-wrap-distance-bottom");
0584         doPrependCheck(*p_margin);
0585         changeToPoints(*p_margin);
0586     }
0587     m_currentDrawStyle->addProperty("fo:margin-left", m_currentVMLProperties.marginLeft);
0588     m_currentDrawStyle->addProperty("fo:margin-top", m_currentVMLProperties.marginTop);
0589     m_currentDrawStyle->addProperty("fo:margin-right", m_currentVMLProperties.marginRight);
0590     m_currentDrawStyle->addProperty("fo:margin-bottom", m_currentVMLProperties.marginBottom);
0591 
0592     if (!m_currentDrawStyle->isEmpty()) {
0593         const QString drawStyleName(mainStyles->insert(*m_currentDrawStyle, "gr"));
0594         body->addAttribute("draw:style-name", drawStyleName);
0595     }
0596 }
0597 
0598 void MSOOXML_CURRENT_CLASS::takeDefaultValues()
0599 {
0600     m_currentVMLProperties.modifiers.clear();
0601     m_currentVMLProperties.viewBox.clear();
0602     m_currentVMLProperties.shapePath.clear();
0603     m_currentVMLProperties.strokeColor = "#000000"; // default
0604     m_currentVMLProperties.strokeWidth = "1pt" ; // default
0605     m_currentVMLProperties.shapeColor = "#ffffff"; //default
0606     m_currentVMLProperties.fillType = "solid"; //default
0607     m_currentVMLProperties.shapeSecondaryColor = "#ffffff"; //default
0608     m_currentVMLProperties.lineCapStyle = "square";
0609     m_currentVMLProperties.joinStyle = "middle";
0610     m_currentVMLProperties.strokeStyleName.clear();
0611     m_currentVMLProperties.filled = true; // default
0612     m_currentVMLProperties.stroked = true; // default
0613     m_currentVMLProperties.opacity = 0; // default
0614     m_currentVMLProperties.shadowed = false;
0615     m_currentVMLProperties.shadowOpacity = 0; // default
0616     m_currentVMLProperties.shadowColor = "#101010"; // default
0617     m_currentVMLProperties.shadowXOffset = "2pt"; // default
0618     m_currentVMLProperties.shadowYOffset = "2pt"; //default
0619     m_currentVMLProperties.imagedataPath.clear();
0620     // default internal margins
0621     m_currentVMLProperties.internalMarginLeft = "0.1in";
0622     m_currentVMLProperties.internalMarginRight = "0.1in";
0623     m_currentVMLProperties.internalMarginTop = "0.05in";
0624     m_currentVMLProperties.internalMarginBottom = "0.05in";
0625     // default margins (according to MS Word UI NOT MS-ODRAW defaults)
0626     m_currentVMLProperties.marginLeft = "0.13in";
0627     m_currentVMLProperties.marginRight = "0.13in";
0628     m_currentVMLProperties.marginTop = "0in";
0629     m_currentVMLProperties.marginBottom = "0in";
0630     m_currentVMLProperties.fitTextToShape = false;
0631     m_currentVMLProperties.fitShapeToText = false;
0632 }
0633 
0634 QString MSOOXML_CURRENT_CLASS::rgbColor(QString color)
0635 {
0636     QString extraArgument, argumentValue;
0637     int colorSeparator = color.indexOf(' ');
0638     if (colorSeparator > 0) {
0639         extraArgument = color.mid(colorSeparator + 1);
0640         color = color.left(colorSeparator);
0641         int startIndex = extraArgument.indexOf('(');
0642         if (startIndex > 0) {
0643             argumentValue = extraArgument.mid(startIndex + 1);
0644             argumentValue = argumentValue.left(argumentValue.length() - 1);
0645             extraArgument = extraArgument.left(startIndex);
0646         }
0647     }
0648 
0649     QString newColor;
0650     if (color.startsWith('#')) {
0651         QColor c(color); // use QColor parser to validate and/or correct color
0652         newColor = c.name();
0653     }
0654     else if (color == "red") {
0655         newColor = "#ff0000";
0656     }
0657     else if (color == "green") {
0658         newColor = "#008000";
0659     }
0660     else if (color == "blue") {
0661         newColor = "#0000ff";
0662     }
0663     else if (color == "yellow") {
0664         newColor = "#ffff00";
0665     }
0666     else if (color == "window") {
0667         newColor = "#ffffff"; // should ask from system
0668     }
0669     else if (color == "white") {
0670         newColor = "#ffffff";
0671     }
0672     else if (color == "black") {
0673         newColor = "#000000";
0674     }
0675     else if (color == "silver") {
0676         newColor = "#c0c0c0";
0677     }
0678     else if (color == "gray") {
0679         newColor = "#808080";
0680     }
0681     else if (color == "maroon") {
0682         newColor = "#800000";
0683     }
0684     else if (color == "purple") {
0685         newColor = "#800080";
0686     }
0687     else if (color == "fuchsia") {
0688         newColor = "#ff00ff";
0689     }
0690     else if (color == "lime") {
0691         newColor = "#00ff00";
0692     }
0693     else if (color == "olive") {
0694         newColor = "#808000";
0695     }
0696     else if (color == "navy") {
0697         newColor = "#000080";
0698     }
0699     else if (color == "teal") {
0700         newColor = "#008080";
0701     }
0702     else if (color == "aqua") {
0703         newColor = "#00ffff";
0704     }
0705     else if (color == "windowText") {
0706         newColor = "#000000"; // should ask from system
0707     }
0708     else if (color == "buttonFace") {
0709         newColor = "#808080"; // should ask from system
0710     }
0711     else if (color == "fill") { // referencing the other color
0712         newColor = m_currentVMLProperties.shapeColor;
0713     }
0714     else if (color == "line") {
0715         newColor = m_currentVMLProperties.strokeColor;
0716     }
0717     else if (color == "shadow") {
0718         newColor = m_currentVMLProperties.shadowColor;
0719     }
0720     else {
0721         // unhandled situation, means missing implementation
0722         newColor = color;
0723     }
0724 
0725     if (!argumentValue.isEmpty()) {
0726         int argument = argumentValue.toInt();
0727         QColor temp = newColor;
0728         int red = temp.red();
0729         int green = temp.green();
0730         int blue = temp.blue();
0731         if (extraArgument == "darken") {
0732             red = red * argument / 255;
0733             green = green * argument / 255;
0734             blue = blue * argument / 255;
0735         }
0736         else if (extraArgument == "lighten") {
0737             red = 255 - (255 - red) * argument / 255;
0738             green = 255 - (255 - green) * argument / 255;
0739             blue = 255 - (255 - blue) * argument / 255;
0740         }
0741         if (red > 255) {
0742             red = 255;
0743         }
0744         else if (red < 0) {
0745             red = 0;
0746         }
0747         if (green > 255) {
0748             green = 255;
0749         }
0750         else if (green < 0) {
0751             green = 0;
0752         }
0753         if (blue > 255) {
0754             blue = 255;
0755         }
0756         else if (blue < 0) {
0757             blue = 0;
0758         }
0759         newColor = QColor(red, green, blue).name();
0760     }
0761 
0762     return newColor;
0763 }
0764 
0765 void MSOOXML_CURRENT_CLASS::handleStrokeAndFill(const QXmlStreamAttributes& attrs)
0766 {
0767     TRY_READ_ATTR_WITHOUT_NS(strokeweight)
0768     doPrependCheck(strokeweight);
0769     if (!strokeweight.isEmpty()) {
0770         m_currentVMLProperties.strokeWidth = strokeweight;
0771     }
0772 
0773     TRY_READ_ATTR_WITHOUT_NS(type)
0774     if (!type.isEmpty()) {
0775         type = type.mid(1); // removes extra # from the start
0776     }
0777     TRY_READ_ATTR_WITHOUT_NS(filled)
0778     if (!filled.isEmpty()) {
0779         if (filled == "f" || filled == "false") {
0780             m_currentVMLProperties.filled = false;
0781         }
0782         else {
0783             m_currentVMLProperties.filled = true;
0784         }
0785     }
0786 
0787     TRY_READ_ATTR_WITHOUT_NS(fillcolor)
0788     if (!fillcolor.isEmpty()) {
0789         m_currentVMLProperties.shapeColor = rgbColor(fillcolor);
0790     }
0791 
0792     TRY_READ_ATTR_WITHOUT_NS(stroked)
0793     if (!stroked.isEmpty()) {
0794         if (stroked == "f" || stroked == "false") {
0795             m_currentVMLProperties.stroked = false;
0796         }
0797         else {
0798             m_currentVMLProperties.stroked = true;
0799         }
0800     }
0801 
0802     TRY_READ_ATTR_WITHOUT_NS(strokecolor)
0803     if (!strokecolor.isEmpty()) {
0804         m_currentVMLProperties.strokeColor = rgbColor(strokecolor);
0805     }
0806 
0807     TRY_READ_ATTR_WITHOUT_NS(opacity)
0808     if (!opacity.isEmpty()) {
0809         if (opacity.right(1) == "f") {
0810             opacity = opacity.left(opacity.length() - 1);
0811             m_currentVMLProperties.opacity = 100.0 * opacity.toDouble() / 65536.0;
0812         }
0813         else {
0814             doPrependCheck(opacity);
0815             m_currentVMLProperties.opacity = 100.0 * opacity.toDouble();
0816         }
0817     }
0818 }
0819 
0820 #undef CURRENT_EL
0821 #define CURRENT_EL line
0822 //! line handler (Line)
0823 /*
0824  Parent elements:
0825  - background (Part 1, §17.2.1)
0826  - [done] group (§14.1.2.7)
0827  - object (Part 1, §17.3.3.19)
0828  - [done] pict (§9.2.2.2)
0829  - [done] pict (§9.5.1)
0830 
0831  Child elements:
0832  - anchorlock (Anchor Location Is Locked) §14.3.2.1
0833  - borderbottom (Bottom Border) §14.3.2.2
0834  - borderleft (Left Border) §14.3.2.3
0835  - borderright (Right Border) §14.3.2.4
0836  - bordertop (Top Border) §14.3.2.5
0837  - callout (Callout) §14.2.2.2
0838  - ClientData (Attached Object Data) §14.4.2.12
0839  - clippath (Shape Clipping Path) §14.2.2.3
0840  - extrusion (3D Extrusion) §14.2.2.11
0841  - [done] fill (Shape Fill Properties) §14.1.2.5
0842  - formulas (Set of Formulas) §14.1.2.6
0843  - handles (Set of Handles) §14.1.2.9
0844  - imagedata (Image Data) §14.1.2.11
0845  - lock (Shape Protections) §14.2.2.18
0846  - path (Shape Path) §14.1.2.14
0847  - [done] shadow (Shadow Effect) §14.1.2.18
0848  - signatureline (Digital Signature Line) §14.2.2.30
0849  - skew (Skew Transform) §14.2.2.31
0850  - [done] stroke (Line Stroke Settings) §14.1.2.21
0851  - [done] textbox (Text Box) §14.1.2.22
0852  - textdata (VML Diagram Text) §14.5.2.2
0853  - textpath (Text Layout Path) §14.1.2.23
0854  - [done] wrap (Text Wrapping) §14.3.2.6
0855 */
0856 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_line()
0857 {
0858     READ_PROLOGUE
0859     const QXmlStreamAttributes attrs(attributes());
0860 
0861     TRY_READ_ATTR_WITHOUT_NS(style)
0862     RETURN_IF_ERROR(parseCSS(style))
0863 
0864     takeDefaultValues();
0865     handleStrokeAndFill(attrs);
0866 
0867     MSOOXML::Utils::XmlWriteBuffer frameBuf;
0868     body = frameBuf.setWriter(body);
0869 
0870     pushCurrentDrawStyle(new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic"));
0871     if (m_moveToStylesXml) {
0872         m_currentDrawStyle->setAutoStyleInStylesDotXml(true);
0873     }
0874 
0875     m_currentVMLProperties.wrapRead = false;
0876 
0877     READ_ATTR_WITHOUT_NS(from)
0878     READ_ATTR_WITHOUT_NS(to)
0879 
0880     // The transformations below are done in order to utilize group transformations
0881     // in createFrameStart function
0882     int index = from.indexOf(',');
0883     QString temp = from.left(index);
0884     doPrependCheck(temp);
0885     if (temp == "0") {
0886         temp = "0pt";
0887     }
0888     qreal fromX = temp.left(temp.size() - 2).toDouble();
0889     m_currentVMLProperties.vmlStyle["left"] = temp;
0890     temp = from.mid(index + 1);
0891     doPrependCheck(temp);
0892     if (temp == "0") {
0893         temp = "0pt";
0894     }
0895     qreal fromY = temp.left(temp.size() - 2).toDouble();
0896     m_currentVMLProperties.vmlStyle["top"] = temp;
0897     index = to.indexOf(',');
0898     temp = to.left(index);
0899     doPrependCheck(temp);
0900     if (temp == "0") {
0901         temp = "0pt";
0902     }
0903     QString unit = temp.right(2);
0904     qreal toX = temp.left(temp.size() - 2).toDouble() - fromX;
0905     m_currentVMLProperties.vmlStyle["width"] = QString("%1%2").arg(toX).arg(unit);
0906     temp = to.mid(index + 1);
0907     doPrependCheck(temp);
0908     if (temp == "0") {
0909         temp = "0pt";
0910     }
0911     unit = temp.right(2);
0912     qreal toY = temp.left(temp.size() - 2).toDouble() - fromY;
0913     m_currentVMLProperties.vmlStyle["height"] = QString("%1%2").arg(toY).arg(unit);
0914 
0915     while (!atEnd()) {
0916         readNext();
0917         BREAK_IF_END_OF(CURRENT_EL)
0918         if (isStartElement()) {
0919             TRY_READ_IF(fill)
0920             ELSE_TRY_READ_IF(textbox)
0921             ELSE_TRY_READ_IF(stroke)
0922             ELSE_TRY_READ_IF(shadow)
0923             else if (qualifiedName() == "w10:wrap") {
0924                 m_currentVMLProperties.wrapRead = true;
0925                 TRY_READ(wrap)
0926             }
0927             SKIP_UNKNOWN
0928 //! @todo add ELSE_WRONG_FORMAT
0929         }
0930     }
0931 
0932     body = frameBuf.originalWriter();
0933 
0934     createFrameStart(LineStart);
0935 
0936     (void)frameBuf.releaseWriter();
0937 
0938     body->endElement(); //draw:frame or draw:rect
0939 
0940     popCurrentDrawStyle();
0941 
0942     READ_EPILOGUE
0943 }
0944 
0945 #undef CURRENT_EL
0946 #define CURRENT_EL rect
0947 //! rect handler (Rectangle)
0948 /*! ECMA-376 Part 4, 14.1.2.16, p.449.
0949  This element is used to draw a simple rectangle.
0950  The CSS2 style content width and height define the width and height of the rectangle.
0951 
0952  Parent elements:
0953  - background (Part 1, §17.2.1)
0954  - [done] group (§14.1.2.7)
0955  - object (Part 1, §17.3.3.19)
0956  - [done] pict (§9.2.2.2)
0957  - [done] pict (§9.5.1)
0958 
0959  Child elements:
0960  - anchorlock (Anchor Location Is Locked) §14.3.2.1
0961  - borderbottom (Bottom Border) §14.3.2.2
0962  - borderleft (Left Border) §14.3.2.3
0963  - borderright (Right Border) §14.3.2.4
0964  - bordertop (Top Border) §14.3.2.5
0965  - callout (Callout) §14.2.2.2
0966  - ClientData (Attached Object Data) §14.4.2.12
0967  - clippath (Shape Clipping Path) §14.2.2.3
0968  - extrusion (3D Extrusion) §14.2.2.11
0969  - [done] fill (Shape Fill Properties) §14.1.2.5
0970  - formulas (Set of Formulas) §14.1.2.6
0971  - handles (Set of Handles) §14.1.2.9
0972  - [done] imagedata (Image Data) §14.1.2.11
0973  - lock (Shape Protections) §14.2.2.18
0974  - path (Shape Path) §14.1.2.14
0975  - [done] shadow (Shadow Effect) §14.1.2.18
0976  - signatureline (Digital Signature Line) §14.2.2.30
0977  - skew (Skew Transform) §14.2.2.31
0978  - [done] stroke (Line Stroke Settings) §14.1.2.21
0979  - [done] textbox (Text Box) §14.1.2.22
0980  - textdata (VML Diagram Text) §14.5.2.2
0981  - textpath (Text Layout Path) §14.1.2.23
0982  - [done] wrap (Text Wrapping) §14.3.2.6
0983 */
0984 //! @todo support all elements
0985 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_rect()
0986 {
0987     READ_PROLOGUE
0988     const QXmlStreamAttributes attrs(attributes());
0989 
0990     TRY_READ_ATTR_WITHOUT_NS(style)
0991     RETURN_IF_ERROR(parseCSS(style))
0992 
0993     takeDefaultValues();
0994     handleStrokeAndFill(attrs);
0995 
0996     MSOOXML::Utils::XmlWriteBuffer frameBuf;
0997     body = frameBuf.setWriter(body);
0998 
0999     pushCurrentDrawStyle(new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic"));
1000     if (m_moveToStylesXml) {
1001         m_currentDrawStyle->setAutoStyleInStylesDotXml(true);
1002     }
1003 
1004     m_currentVMLProperties.wrapRead = false;
1005 
1006     while (!atEnd()) {
1007         readNext();
1008         BREAK_IF_END_OF(CURRENT_EL)
1009         if (isStartElement()) {
1010             TRY_READ_IF(fill)
1011             ELSE_TRY_READ_IF(textbox)
1012             ELSE_TRY_READ_IF(stroke)
1013             ELSE_TRY_READ_IF(shadow)
1014             ELSE_TRY_READ_IF(imagedata)
1015             else if (qualifiedName() == "w10:wrap") {
1016                 m_currentVMLProperties.wrapRead = true;
1017                 TRY_READ(wrap)
1018             }
1019             SKIP_UNKNOWN
1020 //! @todo add ELSE_WRONG_FORMAT
1021         }
1022     }
1023 
1024     body = frameBuf.originalWriter();
1025 
1026     createFrameStart(RectStart);
1027 
1028     (void)frameBuf.releaseWriter();
1029 
1030     body->endElement(); //draw:frame or draw:rect
1031 
1032     popCurrentDrawStyle();
1033 
1034     READ_EPILOGUE
1035 }
1036 
1037 #undef CURRENT_EL
1038 #define CURRENT_EL shadow
1039 //! Shadow handler
1040 /*! ECMA-376 Part 4, 19.1.2.18, p.587.
1041 
1042  Parent elements:
1043  - arc (§14.1.2.1);
1044  - background (Part 1, §17.2.1);
1045  - curve (§14.1.2.3);
1046  - [done] group (§14.1.2.7);
1047  - image (§14.1.2.10);
1048  - [done] line (§14.1.2.12);
1049  - object (Part 1, §17.3.3.19);
1050  - [done] oval (§14.1.2.13);
1051  - pict (§9.2.2.2);
1052  - pict (§9.5.1);
1053  - polyline (§14.1.2.15);
1054  - [done] rect (§14.1.2.16);
1055  - [done] roundrect (§14.1.2.17);
1056  - [done] shape (§14.1.2.19);
1057  - shapedefaults (§14.2.2.28);
1058  - [done] shapetype (§14.1.2.20)
1059 
1060  Child elements:
1061  - none
1062 */
1063 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_shadow()
1064 {
1065     READ_PROLOGUE
1066     const QXmlStreamAttributes attrs(attributes());
1067 
1068     m_currentVMLProperties.shadowed = true; // default in this function
1069 
1070     TRY_READ_ATTR_WITHOUT_NS(on)
1071     if (on == "f" || on == "false") {
1072         m_currentVMLProperties.shadowed = false;
1073     }
1074 
1075     TRY_READ_ATTR_WITHOUT_NS(color)
1076     if (!color.isEmpty()) {
1077         m_currentVMLProperties.shadowColor = rgbColor(color);
1078     }
1079 
1080     TRY_READ_ATTR_WITHOUT_NS(offset)
1081     int index = offset.indexOf(',');
1082     if (index > 0) {
1083         if (offset.left(index) != "0") {
1084             m_currentVMLProperties.shadowXOffset = offset.left(index);
1085         }
1086         if (offset.mid(index + 1) != "0") {
1087             m_currentVMLProperties.shadowYOffset = offset.mid(index + 1);
1088         }
1089     }
1090     else if (offset == "0") {
1091         m_currentVMLProperties.shadowed = false;
1092     }
1093 
1094     TRY_READ_ATTR_WITHOUT_NS(opacity)
1095     if (!opacity.isEmpty()) {
1096         if (opacity.right(1) == "f") {
1097             opacity = opacity.left(opacity.length() - 1);
1098             m_currentVMLProperties.shadowOpacity = 100.0 * opacity.toDouble() / 65536.0;
1099         }
1100         else {
1101             doPrependCheck(opacity);
1102             m_currentVMLProperties.shadowOpacity = 100.0 * opacity.toDouble();
1103         }
1104     }
1105 
1106     readNext();
1107     READ_EPILOGUE
1108 }
1109 
1110 #undef CURRENT_EL
1111 #define CURRENT_EL stroke
1112 //! Stroke style handler
1113 /*
1114  Parent elements:
1115  - arc (§14.1.2.1);
1116  - background (Part 1, §17.2.1);
1117  - curve (§14.1.2.3);
1118  - [done] group (§14.1.2.7);
1119  - image (§14.1.2.10);
1120  - [done] line (§14.1.2.12);
1121  - object (Part 1, §17.3.3.19);
1122  - [done] oval (§14.1.2.13);
1123  - pict (§9.2.2.2);
1124  - pict (§9.5.1);
1125  - polyline (§14.1.2.15);
1126  - [done] rect (§14.1.2.16);
1127  - [done] roundrect (§14.1.2.17);
1128  - [done] shape (§14.1.2.19);
1129  - shapedefaults (§14.2.2.28);
1130  - [done] shapetype (§14.1.2.20)
1131 
1132  Child elements:
1133  - bottom (Text Box Bottom Stroke) §14.2.2.1
1134  - column (Text Box Interior Stroke) §14.2.2.6
1135  - left (Text Box Left Stroke) §14.2.2.16
1136  - right (Text Box Right Stroke) §14.2.2.26
1137  - top (Text Box Top Stroke) §14.2.2.32
1138 */
1139 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_stroke()
1140 {
1141     READ_PROLOGUE
1142     const QXmlStreamAttributes attrs(attributes());
1143 
1144     // Spec says that this should overwrite the shape's value, but apparently
1145     // a non specified value does not overwrite it
1146     //m_currentVMLProperties.stroked = true; // default in this function
1147 
1148     TRY_READ_ATTR_WITHOUT_NS(weight)
1149     doPrependCheck(weight);
1150     if (!weight.isEmpty()) {
1151         m_currentVMLProperties.strokeWidth = weight;
1152     }
1153 
1154     TRY_READ_ATTR_WITHOUT_NS(on)
1155     if (on == "f" || on == "false") {
1156         m_currentVMLProperties.stroked = false;
1157     }
1158 
1159     TRY_READ_ATTR_WITHOUT_NS(color)
1160     if (!color.isEmpty()) {
1161         m_currentVMLProperties.strokeColor = rgbColor(color);
1162     }
1163 
1164     TRY_READ_ATTR_WITHOUT_NS(endcap)
1165     if (endcap.isEmpty() || endcap == "sq") {
1166        m_currentVMLProperties.lineCapStyle = "square";
1167     }
1168     else if (endcap == "round") {
1169          m_currentVMLProperties.lineCapStyle = "round";
1170     }
1171     else if (endcap == "flat") {
1172         m_currentVMLProperties.lineCapStyle = "flat";
1173     }
1174 
1175     TRY_READ_ATTR_WITHOUT_NS(joinstyle)
1176     if (!joinstyle.isEmpty()) {
1177         m_currentVMLProperties.joinStyle = joinstyle;
1178     }
1179 
1180     TRY_READ_ATTR_WITHOUT_NS(dashstyle)
1181     if (!dashstyle.isEmpty()) {
1182         // This is over simplification
1183         QPen pen;
1184         pen.setWidthF(2);
1185         pen.setStyle(Qt::DashLine);
1186         m_currentDrawStyle->addProperty("draw:stroke", "dash");
1187         KoGenStyle dashStyle(KoGenStyle::StrokeDashStyle);
1188         dashStyle.addAttribute("draw:style", "rect");
1189         QVector<qreal> dashes = pen.dashPattern();
1190         dashStyle.addAttribute("draw:dots1", static_cast<int>(1));
1191         dashStyle.addAttributePt("draw:dots1-length", dashes[0]*pen.widthF());
1192         dashStyle.addAttributePt("draw:distance", dashes[1]*pen.widthF());
1193         if (dashes.size() > 2) {
1194             dashStyle.addAttribute("draw:dots2", static_cast<int>(1));
1195             dashStyle.addAttributePt("draw:dots2-length", dashes[2]*pen.widthF());
1196         }
1197         m_currentVMLProperties.strokeStyleName = mainStyles->insert(dashStyle, "dash");
1198         /* TODO : implement in reality
1199         if (dashStyle == "dashDot") {
1200 
1201         }
1202         else if (dashStyle == "longDash") {
1203 
1204         }
1205         else if (dashStyle == "1 1") {
1206 
1207         }
1208         else if (dashStyle == "3 1") {
1209 
1210         }
1211         else if (dashStyle == "dash") {
1212 
1213         }*/
1214     // TODO
1215     }
1216 
1217     while (!atEnd()) {
1218         BREAK_IF_END_OF(CURRENT_EL)
1219         readNext();
1220     }
1221 
1222     READ_EPILOGUE
1223 }
1224 
1225 #undef CURRENT_EL
1226 #define CURRENT_EL group
1227 //! Vml group handler
1228 /*
1229  Parent elements:
1230  - background (Part 1, §17.2.1);
1231  - group (§14.1.2.7);
1232  - object (Part 1, §17.3.3.19);
1233  - [done] pict (§9.2.2.2);
1234  - [done] pict (§9.5.1)
1235 
1236  Child elements:
1237  - anchorlock (Anchor Location Is Locked) §14.3.2.1
1238  - arc (Arc Segment) §14.1.2.1
1239  - borderbottom (Bottom Border) §14.3.2.2
1240  - borderleft (Left Border) §14.3.2.3
1241  - borderright (Right Border) §14.3.2.4
1242  - bordertop (Top Border) §14.3.2.5
1243  - callout (Callout) §14.2.2.2
1244  - ClientData (Attached Object Data) §14.4.2.12
1245  - clippath (Shape Clipping Path) §14.2.2.3
1246  - curve (Bezier Curve) §14.1.2.3
1247  - diagram (VML Diagram) §14.2.2.8
1248  - extrusion (3D Extrusion) §14.2.2.11
1249  - [done] fill (Shape Fill Properties) §14.1.2.5
1250  - formulas (Set of Formulas) §14.1.2.6
1251  - [done] group (Shape Group) §14.1.2.7
1252  - handles (Set of Handles) §14.1.2.9
1253  - image (Image File) §14.1.2.10
1254  - [done] imagedata (Image Data) §14.1.2.11
1255  - [done] line (Line) §14.1.2.12
1256  - lock (Shape Protections) §14.2.2.18
1257  - [done] oval (Oval) §14.1.2.13
1258  - path (Shape Path) §14.1.2.14
1259  - polyline (Multiple Path Line) §14.1.2.15
1260  - [done] rect (Rectangle) §14.1.2.16
1261  - [done] roundrect (Rounded Rectangle) §14.1.2.17
1262  - [done] shadow (Shadow Effect) §14.1.2.18
1263  - [done] shape (Shape Definition) §14.1.2.19
1264  - [done] shapetype (Shape Template) §14.1.2.20
1265  - signatureline (Digital Signature Line) §14.2.2.30
1266  - skew (Skew Transform) §14.2.2.31
1267  - [done] stroke (Line Stroke Settings) §14.1.2.21
1268  - textbox (Text Box) §14.1.2.22
1269  - textdata (VML Diagram Text) §14.5.2.2
1270  - textpath (Text Layout Path) §14.1.2.23
1271  - [done] wrap (Text Wrapping) §14.3.2.6
1272 */
1273 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_group()
1274 {
1275     READ_PROLOGUE
1276     const QXmlStreamAttributes attrs(attributes());
1277     TRY_READ_ATTR_WITHOUT_NS(style)
1278     RETURN_IF_ERROR(parseCSS(style))
1279 
1280     pushCurrentDrawStyle(new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic"));
1281     if (m_moveToStylesXml) {
1282         m_currentDrawStyle->setAutoStyleInStylesDotXml(true);
1283     }
1284 
1285     if (!m_currentVMLProperties.insideGroup) {
1286         QString width(m_currentVMLProperties.vmlStyle.value("width"));
1287         doPrependCheck(width);
1288         changeToPoints(width);
1289         QString height(m_currentVMLProperties.vmlStyle.value("height"));
1290         doPrependCheck(height);
1291         changeToPoints(height);
1292 
1293         // These potentially cause an offset to all shapes in the group
1294         // Unhandled case: theoretically x_mar could be in different units
1295         // than width, in this case they should be added somehow intelligently
1296         QString x_mar(m_currentVMLProperties.vmlStyle.value("margin-left"));
1297         doPrependCheck(x_mar);
1298         changeToPoints(x_mar);
1299         QString y_mar(m_currentVMLProperties.vmlStyle.value("margin-top"));
1300         doPrependCheck(y_mar);
1301         changeToPoints(y_mar);
1302 
1303         m_currentVMLProperties.real_groupWidth = width.left(width.length() - 2).toDouble();
1304         m_currentVMLProperties.real_groupHeight = height.left(height.length() - 2).toDouble();
1305         m_currentVMLProperties.groupXOffset = x_mar.left(x_mar.length() - 2).toDouble();
1306         m_currentVMLProperties.groupYOffset = y_mar.left(y_mar.length() - 2).toDouble();
1307     }
1308     else { // We are already in a group, this is a sub group, we're calculating new relative values for its children to use
1309         QString width(m_currentVMLProperties.vmlStyle.value("width"));
1310         QString height(m_currentVMLProperties.vmlStyle.value("height"));
1311         QString x_mar(m_currentVMLProperties.vmlStyle.value("left"));
1312         QString y_mar(m_currentVMLProperties.vmlStyle.value("top"));
1313 
1314         m_currentVMLProperties.groupXOffset = (x_mar.toDouble() - m_currentVMLProperties.groupX) * m_currentVMLProperties.real_groupWidth /
1315             m_currentVMLProperties.groupWidth + m_currentVMLProperties.groupXOffset;
1316         m_currentVMLProperties.groupYOffset = (y_mar.toDouble() - m_currentVMLProperties.groupY) * m_currentVMLProperties.real_groupHeight /
1317             m_currentVMLProperties.groupHeight + m_currentVMLProperties.groupYOffset;
1318         m_currentVMLProperties.real_groupWidth = width.toDouble() * m_currentVMLProperties.real_groupWidth / m_currentVMLProperties.groupWidth;
1319         m_currentVMLProperties.real_groupHeight = height.toDouble() * m_currentVMLProperties.real_groupHeight / m_currentVMLProperties.groupHeight;
1320     }
1321 
1322     m_currentVMLProperties.groupX = 0;
1323     m_currentVMLProperties.groupY = 0;
1324     m_currentVMLProperties.groupWidth = 1000; // default
1325     m_currentVMLProperties.groupHeight = 1000; //default
1326 
1327     TRY_READ_ATTR_WITHOUT_NS(coordsize)
1328     if (!coordsize.isEmpty()) {
1329         m_currentVMLProperties.groupWidth = coordsize.mid(0, coordsize.indexOf(',')).toInt();
1330         m_currentVMLProperties.groupHeight = coordsize.mid(coordsize.indexOf(',') + 1).toInt();
1331     }
1332 
1333     TRY_READ_ATTR_WITHOUT_NS(coordorigin)
1334     if (!coordorigin.isEmpty()) {
1335         m_currentVMLProperties.groupX = coordorigin.mid(0, coordorigin.indexOf(',')).toInt();
1336         m_currentVMLProperties.groupY = coordorigin.mid(coordorigin.indexOf(',') + 1).toInt();
1337     }
1338 
1339     MSOOXML::Utils::XmlWriteBuffer frameBuf;
1340     body = frameBuf.setWriter(body);
1341 
1342     m_currentVMLProperties.wrapRead = false;
1343 
1344     takeDefaultValues();
1345     handleStrokeAndFill(attrs);
1346 
1347     while (!atEnd()) {
1348         readNext();
1349         BREAK_IF_END_OF(CURRENT_EL)
1350         if (isStartElement()) {
1351             if (name() == "shapetype") {
1352                 m_VMLShapeStack.push(m_currentVMLProperties);
1353                 // Template by default should not have any group info
1354                 TRY_READ(shapetype)
1355                 m_currentVMLProperties = m_VMLShapeStack.pop();
1356             }
1357             else if (name() == "rect") {
1358                 m_VMLShapeStack.push(m_currentVMLProperties);
1359                 m_currentVMLProperties.insideGroup = true;
1360                 TRY_READ(rect)
1361                 m_currentVMLProperties = m_VMLShapeStack.pop();
1362             }
1363             else if (name() == "roundrect") {
1364                 m_VMLShapeStack.push(m_currentVMLProperties);
1365                 m_currentVMLProperties.insideGroup = true;
1366                 TRY_READ(roundrect)
1367                 m_currentVMLProperties = m_VMLShapeStack.pop();
1368             }
1369             else if (name() == "oval") {
1370                 m_VMLShapeStack.push(m_currentVMLProperties);
1371                 m_currentVMLProperties.insideGroup = true;
1372                 TRY_READ(oval)
1373                 m_currentVMLProperties = m_VMLShapeStack.pop();
1374             }
1375             else if (name() == "shape") {
1376                 m_VMLShapeStack.push(m_currentVMLProperties);
1377                 m_currentVMLProperties.insideGroup = true;
1378                 TRY_READ(shape)
1379                 m_currentVMLProperties = m_VMLShapeStack.pop();
1380             }
1381             else if (name() == "group") {
1382                 m_VMLShapeStack.push(m_currentVMLProperties);
1383                 m_currentVMLProperties.insideGroup = true;
1384                 TRY_READ(group)
1385                 m_currentVMLProperties = m_VMLShapeStack.pop();
1386             }
1387             else if (name() == "line") {
1388                 m_VMLShapeStack.push(m_currentVMLProperties);
1389                 m_currentVMLProperties.insideGroup = true;
1390                 TRY_READ(line)
1391                 m_currentVMLProperties = m_VMLShapeStack.pop();
1392             }
1393             ELSE_TRY_READ_IF(fill)
1394             ELSE_TRY_READ_IF(stroke)
1395             ELSE_TRY_READ_IF(shadow)
1396             ELSE_TRY_READ_IF(imagedata)
1397             else if (qualifiedName() == "w10:wrap") {
1398                 m_currentVMLProperties.wrapRead = true;
1399                 TRY_READ(wrap)
1400             }
1401             SKIP_UNKNOWN
1402 //! @todo add ELSE_WRONG_FORMAT
1403         }
1404     }
1405 
1406     body = frameBuf.originalWriter();
1407 
1408     createFrameStart(GroupStart);
1409 
1410     (void)frameBuf.releaseWriter();
1411 
1412     body->endElement(); // draw:g
1413 
1414     popCurrentDrawStyle();
1415 
1416     READ_EPILOGUE
1417 }
1418 
1419 // Generic helper to help with draw:xxx shapes
1420 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::genericReader(FrameStartElement startType)
1421 {
1422     const QXmlStreamAttributes attrs(attributes());
1423 //! @todo support more attrs
1424     TRY_READ_ATTR_WITHOUT_NS(style)
1425     RETURN_IF_ERROR(parseCSS(style))
1426 
1427     pushCurrentDrawStyle(new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic"));
1428     if (m_moveToStylesXml) {
1429         m_currentDrawStyle->setAutoStyleInStylesDotXml(true);
1430     }
1431 
1432     takeDefaultValues();
1433     handleStrokeAndFill(attrs);
1434 
1435     MSOOXML::Utils::XmlWriteBuffer frameBuf;
1436     body = frameBuf.setWriter(body);
1437 
1438     m_currentVMLProperties.wrapRead = false;
1439 
1440     while (!atEnd()) {
1441         readNext();
1442         if (isEndElement() && qualifiedName() == m_currentVMLProperties.currentEl) {
1443             break;
1444         }
1445         else if (isStartElement()) {
1446             TRY_READ_IF(fill)
1447             ELSE_TRY_READ_IF(textbox)
1448             ELSE_TRY_READ_IF(stroke)
1449             ELSE_TRY_READ_IF(shadow)
1450             ELSE_TRY_READ_IF(imagedata)
1451             else if (qualifiedName() == "w10:wrap") {
1452                 m_currentVMLProperties.wrapRead = true;
1453                 TRY_READ(wrap)
1454             }
1455             SKIP_UNKNOWN
1456 //! @todo add ELSE_WRONG_FORMAT
1457         }
1458     }
1459 
1460     body = frameBuf.originalWriter();
1461 
1462     createFrameStart(startType);
1463 
1464     (void)frameBuf.releaseWriter();
1465 
1466     body->endElement(); //draw:frame or draw:rect
1467 
1468     popCurrentDrawStyle();
1469 
1470     return KoFilter::OK;
1471 }
1472 
1473 #undef CURRENT_EL
1474 #define CURRENT_EL oval
1475 //! oval handler (Oval)
1476 // For parents, children, look from rect
1477 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_oval()
1478 {
1479     READ_PROLOGUE
1480 
1481     m_currentVMLProperties.currentEl = "v:oval";
1482     KoFilter::ConversionStatus status = genericReader(EllipseStart);
1483     if (status != KoFilter::OK) {
1484         return status;
1485     }
1486 
1487     READ_EPILOGUE
1488 }
1489 
1490 #undef CURRENT_EL
1491 #define CURRENT_EL roundrect
1492 //! roundrect handler (Rounded rectangle)
1493 // For parents, children, look from rect
1494 // Note: this is atm. simplified, should in reality make a round rectangle
1495 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_roundrect()
1496 {
1497     READ_PROLOGUE
1498 
1499     m_currentVMLProperties.currentEl = "v:roundrect";
1500     KoFilter::ConversionStatus status = genericReader(RectStart);
1501     if (status != KoFilter::OK) {
1502         return status;
1503     }
1504 
1505     READ_EPILOGUE
1506 }
1507 
1508 #undef CURRENT_EL
1509 #define CURRENT_EL fill
1510 //! fill handler (Shape Fill Properties)
1511 /*! ECMA-376 Part 4, 14.1.2.16, p.280.
1512  This element specifies how the path should be filled if something beyond
1513  a solid color fill is desired.
1514 
1515  Parent elements:
1516  - arc (§14.1.2.1)
1517  - background (Part 1, §17.2.1)
1518  - background (§14.1.2.2)
1519  - curve (§14.1.2.3)
1520  - [done] group (§14.1.2.7)
1521  - image (§14.1.2.10)
1522  - [done] line (§14.1.2.12)
1523  - object (Part 1, §17.3.3.19)
1524  - [done] oval (§14.1.2.13)
1525  - pict (§9.2.2.2)
1526  - pict (§9.5.1)
1527  - polyline (§14.1.2.15)
1528  - [done] rect (§14.1.2.16)
1529  - [done] roundrect (§14.1.2.17)
1530  - [done] shape (§14.1.2.19)
1531  - shapedefaults (§14.2.2.28)
1532  - [done] shapetype (§14.1.2.20)
1533 
1534  Child elements:
1535  - fill (Shape Fill Extended Properties) §14.2.2.13
1536 */
1537 //! @todo support all elements
1538 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_fill()
1539 {
1540     READ_PROLOGUE
1541     const QXmlStreamAttributes attrs(attributes());
1542 
1543     // Spec says that this should overwrite the shape's value, but apparently
1544     // a non specified value does not overwrite it
1545     //m_currentVMLProperties.filled = true; // default in this function
1546 
1547     TRY_READ_ATTR_WITHOUT_NS(on)
1548     if (on == "f" || on == "false") {
1549         m_currentVMLProperties.filled = false;
1550     }
1551 
1552     // Note this is only like this for solidfill, for others do something...
1553     TRY_READ_ATTR_WITHOUT_NS(color)
1554     if (!color.isEmpty()) {
1555         m_currentVMLProperties.shapeColor = rgbColor(color);
1556     }
1557 
1558     TRY_READ_ATTR_WITHOUT_NS(color2)
1559     if (!color2.isEmpty()) {
1560         m_currentVMLProperties.shapeSecondaryColor = rgbColor(color2);
1561     }
1562     TRY_READ_ATTR_WITHOUT_NS(angle)
1563     TRY_READ_ATTR_WITHOUT_NS(colors)
1564 
1565     TRY_READ_ATTR_WITHOUT_NS(opacity)
1566     if (!opacity.isEmpty()) {
1567         if (opacity.right(1) == "f") {
1568             opacity = opacity.left(opacity.length() - 1);
1569             m_currentVMLProperties.opacity = 100.0 * opacity.toDouble() / 65536.0;
1570         }
1571         else {
1572             doPrependCheck(opacity);
1573             m_currentVMLProperties.opacity = 100.0 * opacity.toDouble();
1574         }
1575     }
1576 
1577     while (!atEnd()) {
1578         readNext();
1579         BREAK_IF_END_OF(CURRENT_EL)
1580         if (isStartElement()) {
1581 //            TRY_READ_IF(fill)
1582 //! @todo add ELSE_WRONG_FORMAT
1583         }
1584     }
1585 
1586     TRY_READ_ATTR_WITHOUT_NS(focusposition)
1587 
1588     TRY_READ_ATTR_WITHOUT_NS(type)
1589     if (!type.isEmpty()) {
1590         m_currentVMLProperties.fillType = type;
1591         if (type == "gradient") {
1592             m_currentGradientStyle = KoGenStyle(KoGenStyle::LinearGradientStyle);
1593             if (angle.isEmpty()) { // default
1594                 m_currentGradientStyle.addAttribute("svg:x1", "50%");
1595                 m_currentGradientStyle.addAttribute("svg:y1", "0%");
1596                 m_currentGradientStyle.addAttribute("svg:x2", "50%");
1597                 m_currentGradientStyle.addAttribute("svg:y2", "100%");
1598             }
1599             else {
1600                 qreal angleReal = (90.0 + angle.toDouble()) * M_PI / 180.0;
1601                 m_currentGradientStyle.addAttribute("svg:x1", QString("%1%").arg(50 - 50 * cos(angleReal)));
1602                 m_currentGradientStyle.addAttribute("svg:y1", QString("%1%").arg(50 + 50 * sin(angleReal)));
1603                 m_currentGradientStyle.addAttribute("svg:x2", QString("%1%").arg(50 + 50 * cos(angleReal)));
1604                 m_currentGradientStyle.addAttribute("svg:y2", QString("%1%").arg(50 - 50 * sin(angleReal)));
1605             }
1606         }
1607         else if (type == "gradientRadial") {
1608             m_currentGradientStyle = KoGenStyle(KoGenStyle::RadialGradientStyle);
1609             if (focusposition.isEmpty()) {
1610                 m_currentGradientStyle.addAttribute("svg:fx", QString("%1%").arg(0)); // default
1611                 m_currentGradientStyle.addAttribute("svg:fy", QString("%1%").arg(0)); // default
1612             }
1613             else {
1614                 int index = focusposition.indexOf(',');
1615                 if (index > 0) {
1616                     QString first = focusposition.left(index);
1617                     doPrependCheck(first);
1618                     focusposition.remove(0, index + 1);
1619                     doPrependCheck(focusposition);
1620                     qreal fx = first.toDouble() * 100;
1621                     qreal fy = focusposition.toDouble() * 100;
1622                     m_currentGradientStyle.addAttribute("svg:fx", QString("%1%").arg(fx));
1623                     m_currentGradientStyle.addAttribute("svg:fy", QString("%1%").arg(fy));
1624                 }
1625             }
1626             // defaulting so that gradient is always towards the center
1627             m_currentGradientStyle.addAttribute("svg:cx", QString("%1%").arg(50));
1628             m_currentGradientStyle.addAttribute("svg:cy", QString("%1%").arg(50));
1629             m_currentGradientStyle.addAttribute("svg:r", "80%"); ; // fix me if possible
1630         }
1631         else if (type == "frame") {
1632             m_currentVMLProperties.fillType = "picture";
1633         }
1634         else if (type == "tile" || type == "pattern") {
1635             m_currentVMLProperties.fillType = "pattern";
1636         }
1637         else {
1638             m_currentVMLProperties.fillType = "solid"; // defaulting
1639         }
1640         if (type == "gradientRadial" || type == "gradient") {
1641             if (colors.isEmpty()) {
1642                 QString contents = QString("<svg:stop svg:offset=\"%1\" svg:stop-color=\"%2\" svg:stop-opacity=\"1\"/>").
1643                     arg(0).arg(m_currentVMLProperties.shapeColor);
1644                 QString name = QString("%1").arg(1);
1645                 m_currentGradientStyle.addChildElement(name, contents);
1646                 contents = QString("<svg:stop svg:offset=\"%1\" svg:stop-color=\"%2\" svg:stop-opacity=\"1\"/>").
1647                     arg(1.0).arg(m_currentVMLProperties.shapeSecondaryColor);
1648                 name = QString("%1").arg(2);
1649                 m_currentGradientStyle.addChildElement(name, contents);
1650             }
1651             else {
1652                 QList<QString> gradientColors;
1653                 QList<qreal> gradientPositions;
1654                 int index = colors.indexOf(';');
1655                 bool lastRound = false;
1656                 while (index > 0 || lastRound) {
1657                     QString gradientString = colors.left(index);
1658                     colors.remove(0, index + 1);
1659                     int spaceLocation = gradientString.indexOf(' ');
1660                     QString pos = gradientString.left(spaceLocation);
1661                     if (pos.right(1) == "f") {
1662                         pos = pos.left(pos.length() - 1);
1663                         gradientPositions.push_back(pos.toDouble() / 65536.0);
1664                     }
1665                     else {
1666                         doPrependCheck(pos);
1667                         gradientPositions.push_back(pos.toDouble());
1668                     }
1669                     gradientColors.push_back(rgbColor(gradientString.mid(spaceLocation + 1)));
1670                     if (lastRound) {
1671                         break;
1672                     }
1673                     index = colors.indexOf(';');
1674                     if (index < 0 ) {
1675                         lastRound = true;
1676                     }
1677                 }
1678                 index = 0;
1679                 while (index < gradientPositions.size()) {
1680                     QString contents = QString("<svg:stop svg:offset=\"%1\" svg:stop-color=\"%2\" svg:stop-opacity=\"1\"/>").
1681                          arg(gradientPositions.at(index)).arg(gradientColors.at(index));
1682                     QString name = QString("%1").arg(index);
1683                     m_currentGradientStyle.addChildElement(name, contents);
1684                     ++index;
1685                 }
1686             }
1687             m_currentVMLProperties.gradientStyle = mainStyles->insert(m_currentGradientStyle);
1688         }
1689     }
1690 
1691     TRY_READ_ATTR_WITH_NS(r, id)
1692     if (!r_id.isEmpty()) {
1693         const QString sourceName(m_context->relationships->target(m_context->path, m_context->file, r_id));
1694         m_currentVMLProperties.imagedataPath = QLatin1String("Pictures/") + sourceName.mid(sourceName.lastIndexOf('/') + 1);
1695         KoFilter::ConversionStatus status = m_context->import->copyFile(sourceName, m_currentVMLProperties.imagedataPath, false);
1696         if (status == KoFilter::OK) {
1697             addManifestEntryForFile(m_currentVMLProperties.imagedataPath);
1698             addManifestEntryForPicturesDir();
1699         }
1700         else {
1701             m_currentVMLProperties.fillType = "solid"; // defaulting
1702         }
1703     }
1704 
1705     // frame (Stretch Image to Fit) - The image is stretched to fill the shape.
1706     // gradient (Linear Gradient) - The fill colors blend together in a linear gradient from bottom to top.
1707     // gradientRadial (Radial Gradient) - The fill colors blend together in a radial gradient.
1708     // pattern (Image Pattern) - The image is used to create a pattern using the fill colors.
1709     // tile (Tiled Image) - The fill image is tiled.
1710     // solid (Solid Fill) - The fill pattern is a solid color.
1711 
1712     READ_EPILOGUE
1713 }
1714 
1715 #undef CURRENT_EL
1716 #define CURRENT_EL background
1717 
1718 //! fill handler (Document Background)
1719 /*! ECMA-376 Part 4, 14.1.2.2, p.235.
1720  This element describes the fill of the background of a page using vector graphics fills.
1721 
1722  Parent elements:
1723  - background (Part 1, §17.2.1)
1724  - object (Part 1, §17.3.3.19)
1725  - pict (§9.2.2.2)
1726  - pict (§9.5.1)
1727 
1728  Child elements:
1729  - [Done] fill (Shape Fill Properties) §14.1.2.5
1730 
1731  Attributes:
1732  - bwmode (Blackand- White Mode)
1733  - bwnormal (Normal Black-and-White Mode)
1734  - bwpure (Pure Black-and-White Mode)
1735  - fillcolor (Fill Color)
1736  - filled (Shape Fill Toggle)
1737  - id (Unique Identifier)
1738  - targetscreensize (Target Screen Size)
1739 */
1740 //! @todo support all elements
1741 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_VML_background()
1742 {
1743     READ_PROLOGUE2(VML_background)
1744     //const QXmlStreamAttributes attrs(attributes());
1745     while (!atEnd()) {
1746         readNext();
1747         BREAK_IF_END_OF(CURRENT_EL)
1748         if (isStartElement()) {
1749             TRY_READ_IF(fill)
1750             ELSE_WRONG_FORMAT
1751         }
1752     }
1753     const QString rId(m_currentVMLProperties.vmlStyle.value("v:fill@r:id"));
1754     if (!rId.isEmpty()) {
1755         const QString sourceName(m_context->relationships->target(m_context->path, m_context->file, rId));
1756         debugMsooXml << "sourceName:" << sourceName;
1757         if (sourceName.isEmpty()) {
1758             return KoFilter::FileNotFound;
1759         }
1760         QString destinationName = QLatin1String("Pictures/") + sourceName.mid(sourceName.lastIndexOf('/') + 1);
1761         RETURN_IF_ERROR( m_context->import->copyFile(sourceName, destinationName, false ) )
1762         addManifestEntryForFile(destinationName);
1763         addManifestEntryForPicturesDir();
1764         if (m_pDocBkgImageWriter) {
1765             delete m_pDocBkgImageWriter->device();
1766             delete m_pDocBkgImageWriter;
1767             m_pDocBkgImageWriter = nullptr;
1768         }
1769         QBuffer* buffer = new QBuffer();
1770         m_pDocBkgImageWriter = new KoXmlWriter(buffer);
1771 
1772         m_pDocBkgImageWriter->startElement("style:background-image");
1773         m_pDocBkgImageWriter->addAttribute("xlink:href", destinationName);
1774         m_pDocBkgImageWriter->addAttribute("xlink:type", "simple");
1775         m_pDocBkgImageWriter->addAttribute("xlink:actuate", "onLoad");
1776         m_pDocBkgImageWriter->endElement(); //style:background-image
1777     }
1778     READ_EPILOGUE
1779 }
1780 
1781 static QString getNumber(QString& source)
1782 {
1783     QString number;
1784     int index = 0;
1785     bool numberOk = true;
1786     while (true) {
1787         QString(source.at(index)).toInt(&numberOk);
1788         if (numberOk) {
1789             number = number + source.at(index);
1790             ++index;
1791         }
1792         else {
1793             break;
1794         }
1795     }
1796     source.remove(0, index);
1797     return number;
1798 }
1799 
1800 static QString getArgument(QString& source, bool commaMeansZero, bool& wasCommand)
1801 {
1802     wasCommand = false;
1803     if (source.at(0) == ',') {
1804         source.remove(0, 1);
1805         if (commaMeansZero) {
1806             return "0";
1807         }
1808     }
1809     bool isNumber;
1810     QString(source.at(0)).toInt(&isNumber);
1811     if (isNumber) {
1812         return getNumber(source);
1813     }
1814     if (source.at(0) == '-') { //negative number
1815         source.remove(0, 1);
1816         return QString("-%1").arg(getNumber(source));
1817     }
1818     if (source.at(0) == ',') { // case of 1,,2
1819         return "0";
1820     }
1821     if (source.at(0) == '#') {
1822         source.remove(0, 1);
1823         return QString("$%1").arg(getNumber(source));
1824     }
1825     if (source.at(0) == '@') {
1826         source.remove(0, 1);
1827         return QString("?f%1").arg(getNumber(source));
1828     }
1829 
1830     wasCommand = true;
1831     return "0"; // this means case 1,e
1832 }
1833 
1834 static QString convertToEnhancedPath(const QString& source, QString& extraShapeFormulas)
1835 {
1836     enum ConversionState {CommandExpected, ArgumentExpected};
1837     int extraFormulaIndex = 1;
1838     QString parsedString = source;
1839     QString returnedString;
1840     ConversionState state = CommandExpected;
1841     enum CommandType {MoveCommand, LineCommand, RelativeLineCommand, QuadEllipXCommand, QuadEllipYCommand,
1842                       CurveCommand, RelativeCurveCommand, ArcCommand, ArcToCommand, ArcCommandClock, ArcToCommandClock,
1843                       AngleEllipseToCommand, AngleEllipseCommand};
1844     CommandType lastCommand = MoveCommand;
1845     QString firstMoveX, firstMoveY, currentX, currentY;
1846     bool argumentMove;
1847     QChar command;
1848     QString first, second, third, fourth, fifth, sixth, seventh, eighth;
1849 
1850     while (true) {
1851         if (parsedString.length() == 0) {
1852             break;
1853         }
1854         while (parsedString.at(0) == ' ') {
1855             parsedString = parsedString.trimmed();
1856         }
1857         switch (state) {
1858         case CommandExpected:
1859             command = parsedString.at(0);
1860             parsedString.remove(0, 1);
1861             state = ArgumentExpected;
1862             if (command == 'm') {
1863                 lastCommand = MoveCommand;
1864             }
1865             else if (command == 'l') {
1866                 lastCommand = LineCommand;
1867             }
1868             else if (command == 'r') {
1869                 lastCommand = RelativeLineCommand;
1870             }
1871             else if (command == 'x') {
1872                 state = CommandExpected;
1873                 returnedString += " Z";
1874             }
1875             else if (command == 'e') {
1876                 returnedString += " N";
1877                 state = CommandExpected;
1878             }
1879             else if (command == 'c') {
1880                 lastCommand = CurveCommand;
1881             }
1882             else if (command == 'v') {
1883                 lastCommand = RelativeCurveCommand;
1884             }
1885             else if (command == 'q') {
1886                 QChar subcommand = parsedString.at(0);
1887                 parsedString.remove(0, 1);
1888                 if (subcommand == 'x') {
1889                     lastCommand = QuadEllipXCommand;
1890                     returnedString += " X";
1891                 }
1892                 else {
1893                     lastCommand = QuadEllipYCommand;
1894                     returnedString += " Y";
1895                 }
1896             }
1897             else if (command == 'a') {
1898                 QChar subcommand = parsedString.at(0);
1899                 parsedString.remove(0, 1);
1900                 if (subcommand == 'r') {
1901                     lastCommand = ArcCommand;
1902                     returnedString += " B";
1903                 }
1904                 else if (subcommand == 'e') {
1905                     lastCommand = AngleEllipseToCommand;
1906                     returnedString += " T";
1907                 }
1908                 else if (subcommand == 'l') {
1909                     lastCommand = AngleEllipseCommand;
1910                     returnedString += " U";
1911                 }
1912                 else {
1913                     lastCommand = ArcToCommand;
1914                     returnedString += " A";
1915                 }
1916             }
1917             else if (command == 'w') {
1918                 QChar subcommand = parsedString.at(0);
1919                 parsedString.remove(0, 1);
1920                 if (subcommand == 'r') {
1921                     lastCommand = ArcCommandClock;
1922                     returnedString += " V";
1923                 }
1924                 else {
1925                     lastCommand = ArcToCommandClock;
1926                     returnedString += " W";
1927                 }
1928             }
1929             else if (command == 'n') {
1930                 QChar subcommand = parsedString.at(0);
1931                 parsedString.remove(0, 1);
1932                 if (subcommand == 'f') {
1933                     returnedString += " F";
1934                 }
1935                 else {
1936                     returnedString += " S";
1937                 }
1938                 state = CommandExpected;
1939             }
1940             break;
1941         case ArgumentExpected:
1942             switch (lastCommand) {
1943             case MoveCommand:
1944                 first = getArgument(parsedString, true, argumentMove);
1945                 second = getArgument(parsedString, false, argumentMove);
1946                 firstMoveX = first;
1947                 firstMoveY = second;
1948                 currentX = first;
1949                 currentY = second;
1950                 returnedString += QString(" M %1 %2").arg(first).arg(second);
1951                 state = CommandExpected;
1952                 break;
1953             case RelativeCurveCommand:
1954                 first = getArgument(parsedString, true, argumentMove);
1955                 second = getArgument(parsedString, false, argumentMove);
1956                 third = getArgument(parsedString, false, argumentMove);
1957                 fourth = getArgument(parsedString, false, argumentMove);
1958                 fifth = getArgument(parsedString, false, argumentMove);
1959                 sixth = getArgument(parsedString, false, argumentMove);
1960                 first = QString("%1").arg(first.toInt() + currentX.toInt());
1961                 second = QString("%1").arg(second.toInt() + currentY.toInt());
1962                 third = QString("%1").arg(third.toInt() + currentX.toInt());
1963                 fourth = QString("%1").arg(fourth.toInt() + currentY.toInt());
1964                 currentX = QString("%1").arg(fifth.toInt() + currentX.toInt());
1965                 currentY = QString("%1").arg(sixth.toInt() + currentY.toInt());
1966                 returnedString += QString(" C %1 %2 %3 %4 %5 %6").arg(first).arg(second).arg(third).
1967                                   arg(fourth).arg(currentX).arg(currentY);
1968                 while (true) {
1969                     first = getArgument(parsedString, false, argumentMove);
1970                     if (argumentMove) {
1971                         state = CommandExpected;
1972                         break;
1973                     }
1974                     second = getArgument(parsedString, false, argumentMove);
1975                     third = getArgument(parsedString, false, argumentMove);
1976                     fourth = getArgument(parsedString, false, argumentMove);
1977                     fifth = getArgument(parsedString, false, argumentMove);
1978                     sixth = getArgument(parsedString, false, argumentMove);
1979                     first = QString("%1").arg(first.toInt() + currentX.toInt());
1980                     second = QString("%1").arg(second.toInt() + currentY.toInt());
1981                     third = QString("%1").arg(third.toInt() + currentX.toInt());
1982                     fourth = QString("%1").arg(fourth.toInt() + currentY.toInt());
1983                     currentX = QString("%1").arg(fifth.toInt() + currentX.toInt());
1984                     currentY = QString("%1").arg(sixth.toInt() + currentY.toInt());
1985                     returnedString += QString(" %1 %2 %3 %4 %5 %6").arg(first).arg(second).arg(third).
1986                                       arg(fourth).arg(currentX).arg(currentY);
1987                 }
1988                 break;
1989             case CurveCommand:
1990                 first = getArgument(parsedString, true, argumentMove);
1991                 second = getArgument(parsedString, false, argumentMove);
1992                 third = getArgument(parsedString, false, argumentMove);
1993                 fourth = getArgument(parsedString, false, argumentMove);
1994                 fifth = getArgument(parsedString, false, argumentMove);
1995                 sixth = getArgument(parsedString, false, argumentMove);
1996                 returnedString += QString(" C %1 %2 %3 %4 %5 %6").arg(first).arg(second).arg(third).
1997                                   arg(fourth).arg(fifth).arg(sixth);
1998                 currentX = fifth;
1999                 currentY = sixth;
2000                 while (true) {
2001                     first = getArgument(parsedString, false, argumentMove);
2002                     if (argumentMove) {
2003                         state = CommandExpected;
2004                         break;
2005                     }
2006                     second = getArgument(parsedString, false, argumentMove);
2007                     third = getArgument(parsedString, false, argumentMove);
2008                     fourth = getArgument(parsedString, false, argumentMove);
2009                     fifth = getArgument(parsedString, false, argumentMove);
2010                     sixth = getArgument(parsedString, false, argumentMove);
2011                     returnedString += QString(" %1 %2 %3 %4 %5 %6").arg(first).arg(second).arg(third).
2012                                       arg(fourth).arg(fifth).arg(sixth);
2013                     currentX = fifth;
2014                     currentY = sixth;
2015                 }
2016                 break;
2017             case LineCommand:
2018                 first = getArgument(parsedString, true, argumentMove);
2019                 second = getArgument(parsedString, false, argumentMove);
2020                 returnedString += QString(" L %1 %2").arg(first).arg(second);
2021                 currentX = first;
2022                 currentY = second;
2023                 while (true) {
2024                     first = getArgument(parsedString, false, argumentMove);
2025                     if (argumentMove) {
2026                         state = CommandExpected;
2027                         break;
2028                     }
2029                     second = getArgument(parsedString, false, argumentMove);
2030                     currentX = first;
2031                     currentY = second;
2032                     returnedString += QString(" %1 %2").arg(first).arg(second);
2033                 }
2034                 break;
2035             case RelativeLineCommand:
2036                 first = getArgument(parsedString, true, argumentMove);
2037                 second = getArgument(parsedString, false, argumentMove);
2038                 currentX = QString("%1").arg(first.toInt() + currentX.toInt());
2039                 currentY = QString("%1").arg(second.toInt() + currentY.toInt());
2040                 returnedString += QString(" L %1 %2").arg(currentX).arg(currentY);
2041                 while (true) {
2042                     first = getArgument(parsedString, false, argumentMove);
2043                     if (argumentMove) {
2044                         state = CommandExpected;
2045                         break;
2046                     }
2047                     second = getArgument(parsedString, false, argumentMove);
2048                     currentX = QString("%1").arg(first.toInt() + currentX.toInt());
2049                     currentY = QString("%1").arg(second.toInt() + currentY.toInt());
2050                     returnedString += QString(" %1 %2").arg(currentX).arg(currentY);
2051                 }
2052                 break;
2053             case QuadEllipXCommand:
2054             case QuadEllipYCommand:
2055                 first = getArgument(parsedString, true, argumentMove);
2056                 second = getArgument(parsedString, false, argumentMove);
2057                 returnedString += QString(" %1 %2").arg(first).arg(second);
2058                 currentX = first;
2059                 currentY = second;
2060                 while (true) {
2061                     first = getArgument(parsedString, false, argumentMove);
2062                     if (argumentMove) {
2063                         state = CommandExpected;
2064                         break;
2065                     }
2066                     second = getArgument(parsedString, false, argumentMove);
2067                     currentX = first;
2068                     currentY = second;
2069                     returnedString += QString(" %1 %2").arg(first).arg(second);
2070                 }
2071                 break;
2072             case ArcCommand:
2073             case ArcToCommand:
2074             case ArcCommandClock:
2075             case ArcToCommandClock:
2076                 first = getArgument(parsedString, true, argumentMove);
2077                 second = getArgument(parsedString, false, argumentMove);
2078                 third = getArgument(parsedString, false, argumentMove);
2079                 fourth = getArgument(parsedString, false, argumentMove);
2080                 fifth = getArgument(parsedString, false, argumentMove);
2081                 sixth = getArgument(parsedString, false, argumentMove);
2082                 seventh = getArgument(parsedString, false, argumentMove);
2083                 eighth = getArgument(parsedString, false, argumentMove);
2084                 currentX = seventh;
2085                 currentY = eighth;
2086                 returnedString += QString(" %1 %2 %3 %4 %5 %6 %7 %8").arg(first).arg(second).arg(third).arg(fourth).
2087                     arg(fifth).arg(sixth).arg(seventh).arg(eighth);
2088                 while (true) {
2089                     first = getArgument(parsedString, false, argumentMove);
2090                     if (argumentMove) {
2091                         state = CommandExpected;
2092                         break;
2093                     }
2094                     second = getArgument(parsedString, false, argumentMove);
2095                     third = getArgument(parsedString, false, argumentMove);
2096                     fourth = getArgument(parsedString, false, argumentMove);
2097                     fifth = getArgument(parsedString, false, argumentMove);
2098                     sixth = getArgument(parsedString, false, argumentMove);
2099                     seventh = getArgument(parsedString, false, argumentMove);
2100                     eighth = getArgument(parsedString, false, argumentMove);
2101                     currentX = seventh;
2102                     currentY = eighth;
2103                     returnedString += QString(" %1 %2 %3 %4 %5 %6 %7 %8").arg(first).arg(second).arg(third).arg(fourth).
2104                         arg(fifth).arg(sixth).arg(seventh).arg(eighth);
2105                 }
2106                 break;
2107             case AngleEllipseToCommand:
2108             case AngleEllipseCommand:
2109                 first = getArgument(parsedString, true, argumentMove);
2110                 second = getArgument(parsedString, false, argumentMove);
2111                 third = getArgument(parsedString, false, argumentMove);
2112                 fourth = getArgument(parsedString, false, argumentMove);
2113                 fifth = getArgument(parsedString, false, argumentMove);
2114                 sixth = getArgument(parsedString, false, argumentMove);
2115                 seventh = QString("?extraFormula%1").arg(extraFormulaIndex);
2116                 extraShapeFormulas += "\n<draw:equation " +
2117                                       QString("draw:name=\"extraFormula%1\" draw:formula=\"").arg(extraFormulaIndex) +
2118                                       QString("%1 / 65536").arg(fifth) +
2119                                       "\" "
2120                                       "/>";
2121                 ++extraFormulaIndex;
2122                 eighth = QString("?extraFormula%1").arg(extraFormulaIndex);
2123                 extraShapeFormulas += "\n<draw:equation " +
2124                                       QString("draw:name=\"extraFormula%1\" draw:formula=\"").arg(extraFormulaIndex) +
2125                                       QString("%1 / 65536").arg(sixth) +
2126                                       "\" "
2127                                       "/>";
2128                 ++extraFormulaIndex;
2129                 currentX = QString("%1").arg(first.toInt() + cos(sixth.toDouble()));
2130                 currentY = QString("%1").arg(first.toInt() + sin(sixth.toDouble()));
2131                 returnedString += QString(" %1 %2 %3 %4 %5 %6").arg(first).arg(second).arg(third).arg(fourth).
2132                     arg(seventh).arg(eighth);
2133                 while (true) {
2134                     first = getArgument(parsedString, false, argumentMove);
2135                     if (argumentMove) {
2136                         state = CommandExpected;
2137                         break;
2138                     }
2139                     second = getArgument(parsedString, false, argumentMove);
2140                     third = getArgument(parsedString, false, argumentMove);
2141                     fourth = getArgument(parsedString, false, argumentMove);
2142                     fifth = getArgument(parsedString, false, argumentMove);
2143                     sixth = getArgument(parsedString, false, argumentMove);
2144                     seventh = QString("?extraFormula%1").arg(extraFormulaIndex);
2145                     extraShapeFormulas += "\n<draw:equation " +
2146                                           QString("draw:name=\"extraFormula%1\" draw:formula=\"").arg(extraFormulaIndex) +
2147                                           QString("%1 / 65536").arg(fifth) +
2148                                           "\" "
2149                                           "/>";
2150                     ++extraFormulaIndex;
2151                     eighth = QString("?extraFormula%1").arg(extraFormulaIndex);
2152                     extraShapeFormulas += "\n<draw:equation " +
2153                                           QString("draw:name=\"extraFormula%1\" draw:formula=\"").arg(extraFormulaIndex) +
2154                                           QString("%1 / 65536").arg(sixth) +
2155                                           "\" "
2156                                           "/>";
2157                     ++extraFormulaIndex;
2158                     currentX = QString("%1").arg(first.toInt() + cos(sixth.toDouble()));
2159                     currentY = QString("%1").arg(first.toInt() + sin(sixth.toDouble()));
2160                     returnedString += QString(" %1 %2 %3 %4 %5 %6").arg(first).arg(second).arg(third).arg(fourth).
2161                     arg(seventh).arg(eighth);
2162                 }
2163                 break;
2164             }
2165         }
2166     }
2167 
2168     return returnedString;
2169 }
2170 
2171 #undef CURRENT_EL
2172 #define CURRENT_EL shapetype
2173 //! shapetype handler (Shape Template)
2174 /*! ECMA-376 Part 4, 14.1.2.20, p.539.
2175  This element defines a shape template that can be used to create other shapes.
2176  Shapetype is identical to the shape element (§14.1.2.19) except it cannot reference another
2177  shapetype element.
2178 
2179  Parent elements:
2180  - background (Part 1, §17.2.1)
2181  - [done] group (§14.1.2.7)
2182  - [done] object (Part 1, §17.3.3.19)
2183  - pict (§9.2.2.2)
2184  - pict (§9.5.1)
2185 
2186  Child elements:
2187  - bordertop (Top Border) §14.3.2.5
2188  - callout (Callout) §14.2.2.2
2189  - ClientData (Attached Object Data) §14.4.2.12
2190  - clippath (Shape Clipping Path) §14.2.2.3
2191  - complex (Complex) §14.2.2.7
2192  - extrusion (3D Extrusion) §14.2.2.11
2193  - [done] fill (Shape Fill Properties) §14.1.2.5
2194  - [done] formulas (Set of Formulas) §14.1.2.6
2195  - handles (Set of Handles) §14.1.2.9
2196  - [done] imagedata (Image Data) §14.1.2.11
2197  - lock (Shape Protections) §14.2.2.18
2198  - [done] path (Shape Path) §14.1.2.14
2199  - [done shadow (Shadow Effect) §14.1.2.18
2200  - signatureline (Digital Signature Line) §14.2.2.30
2201  - skew (Skew Transform) §14.2.2.31
2202  - [done] stroke (Line Stroke Settings) §14.1.2.21
2203  - textbox (Text Box) §14.1.2.22
2204  - textdata (VML Diagram Text) §14.5.2.2
2205  - textpath (Text Layout Path) §14.1.2.23
2206  - wrap (Text Wrapping) §14.3.2.6
2207 */
2208 //! @todo support all elements
2209 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_shapetype()
2210 {
2211     READ_PROLOGUE
2212     const QXmlStreamAttributes attrs(attributes());
2213 
2214     TRY_READ_ATTR_WITHOUT_NS(id)
2215 
2216     takeDefaultValues();
2217     handleStrokeAndFill(attrs);
2218     handlePathValues(attrs);
2219 
2220     while (!atEnd()) {
2221         readNext();
2222         BREAK_IF_END_OF(CURRENT_EL)
2223         if (isStartElement()) {
2224             TRY_READ_IF(formulas)
2225             ELSE_TRY_READ_IF(path)
2226             ELSE_TRY_READ_IF(shadow)
2227             ELSE_TRY_READ_IF(fill)
2228             ELSE_TRY_READ_IF(stroke)
2229             ELSE_TRY_READ_IF(imagedata)
2230             SKIP_UNKNOWN
2231         }
2232     }
2233 
2234     m_definedShapeTypes[id] = m_currentVMLProperties;
2235 
2236     READ_EPILOGUE
2237 }
2238 
2239 #undef CURRENT_EL
2240 #define CURRENT_EL formulas
2241 /* formulas handlers (Set of Formulas)
2242 
2243  Parent elements:
2244  - arc (§14.1.2.1);
2245  - background (Part 1, §17.2.1);
2246  - curve (§14.1.2.3);
2247  - group (§14.1.2.7);
2248  - image (§14.1.2.10);
2249  - line (§14.1.2.12);
2250  - object (Part 1, §17.3.3.19);
2251  - oval (§14.1.2.13);
2252  - pict (§9.2.2.2);
2253  - pict (§9.5.1);
2254  - polyline (§14.1.2.15);
2255  - rect (§14.1.2.16);
2256  - roundrect (§14.1.2.17);
2257  - shape (§14.1.2.19);
2258  - [done] shapetype (§14.1.2.20)
2259 
2260  Child elements:
2261  -  [done] f (Single Formula) §14.1.2.4
2262 */
2263 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_formulas()
2264 {
2265     READ_PROLOGUE
2266 
2267     m_currentVMLProperties.formulaIndex = 0;
2268     m_currentVMLProperties.normalFormulas.clear();
2269 
2270     while (!atEnd()) {
2271         readNext();
2272         BREAK_IF_END_OF(CURRENT_EL)
2273         if (isStartElement()) {
2274             TRY_READ_IF(f)
2275             ELSE_WRONG_FORMAT
2276         }
2277     }
2278 
2279     READ_EPILOGUE
2280 }
2281 
2282 #undef CURRENT_EL
2283 #define CURRENT_EL f
2284 /*! f handler (Shape Definition)
2285  Parent elements:
2286  - [done] formulas (§14.1.2.6)
2287 
2288  Child elements:
2289  - none
2290 */
2291 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_f()
2292 {
2293     READ_PROLOGUE
2294     const QXmlStreamAttributes attrs(attributes());
2295     TRY_READ_ATTR_WITHOUT_NS(eqn)
2296     m_currentVMLProperties.normalFormulas += "\n<draw:equation " +
2297                                              QString("draw:name=\"f%1\" draw:formula=\"").arg(m_currentVMLProperties.formulaIndex);
2298 
2299     if (!eqn.isEmpty()) {
2300         eqn = eqn.trimmed();
2301         eqn.replace('#', '$'); // value reference
2302         eqn.replace('@', "?f"); // function reference
2303         eqn.replace("pixelWidth", "width");
2304         eqn.replace("pixelHeight", "height");
2305         eqn.replace("emuWidth", "width");
2306         eqn.replace("emuHeight", "height");
2307         eqn.replace("emuWidth2", "(width/2)");
2308         eqn.replace("emuHeight2", "(height/2)");
2309         eqn.replace("lineDrawn", "hasstroke");
2310         eqn.replace("pixelLineWidth", "1");
2311         eqn.replace("xcenter", "(width/2)");
2312         eqn.replace("ycenter", "(height/2)");
2313         int commandIndex = eqn.indexOf(' ');
2314         QString command = eqn.left(commandIndex);
2315         eqn.remove(0, commandIndex + 1);
2316         QList<QString> parameters;
2317         while (true) {
2318             commandIndex = eqn.indexOf(' ');
2319             if (commandIndex < 0) {
2320                 parameters.append(eqn);
2321                 break;
2322             }
2323             parameters.append(eqn.left(commandIndex));
2324             eqn.remove(0, commandIndex + 1);
2325         }
2326         if (command == "val") {
2327             m_currentVMLProperties.normalFormulas += parameters.at(0);
2328         }
2329         else if (command == "sum") {
2330             m_currentVMLProperties.normalFormulas += parameters.at(0) + "+" + parameters.at(1) + "-" + parameters.at(2);
2331         }
2332         else if (command == "prod") {
2333             m_currentVMLProperties.normalFormulas += parameters.at(0) + "*" + parameters.at(1) + "/" + parameters.at(2);
2334         }
2335         else if (command == "abs") {
2336             m_currentVMLProperties.normalFormulas += QString("abs(%1)").arg(parameters.at(0));
2337         }
2338         else if (command == "min") {
2339             m_currentVMLProperties.normalFormulas += QString("min(%1,%2)").arg(parameters.at(0)).arg(parameters.at(1));
2340         }
2341         else if (command == "max") {
2342             m_currentVMLProperties.normalFormulas += QString("max(%1,%2)").arg(parameters.at(0)).arg(parameters.at(1));
2343         }
2344         else if (command == "if") {
2345             m_currentVMLProperties.normalFormulas += QString("if(%1,%2,%3)").arg(parameters.at(0)).arg(parameters.at(1)).arg(parameters.at(2));
2346         }
2347         else if (command == "sqrt") {
2348             m_currentVMLProperties.normalFormulas += QString("sqrt(%1)").arg(parameters.at(0));
2349         }
2350         else if (command == "mid") {
2351             m_currentVMLProperties.normalFormulas += QString("(%1+%2)/2").arg(parameters.at(0)).arg(parameters.at(1));
2352         }
2353         else if (command == "mod") {
2354             m_currentVMLProperties.normalFormulas += QString("sqrt(%1*%1+%2*%2+%3*%3)").arg(parameters.at(0)).arg(parameters.at(1)).arg(parameters.at(2));
2355         }
2356         else if (command == "ellipse") {
2357             m_currentVMLProperties.normalFormulas += QString("%3-sqrt(1-(%1/%2)*(%1/%2))").arg(parameters.at(0)).arg(parameters.at(1)).arg(parameters.at(2));
2358         }
2359         else if (command == "atan2") { // converting to fd unit (degrees * 65536)
2360             m_currentVMLProperties.normalFormulas += QString("3754936*atan2(%2,%1)").arg(parameters.at(0)).arg(parameters.at(1));
2361         }
2362         else if (command == "cosatan2") {
2363             m_currentVMLProperties.normalFormulas += QString("%1*cos(atan2(%3,%2))").arg(parameters.at(0)).arg(parameters.at(1)).arg(parameters.at(2));
2364         }
2365         else if (command == "sinatan2") {
2366             m_currentVMLProperties.normalFormulas += QString("%1*sin(atan2(%3,%2))").arg(parameters.at(0)).arg(parameters.at(1)).arg(parameters.at(2));
2367         }
2368         else if (command == "sumangle") {
2369             m_currentVMLProperties.normalFormulas += QString("%1+%2*65536-%3*65536").arg(parameters.at(0)).arg(parameters.at(1)).arg(parameters.at(2));
2370         }
2371         else if (command == "sin") { // converting fd unit to radians
2372             m_currentVMLProperties.normalFormulas += QString("%1*sin(%2 * 0.000000266)").arg(parameters.at(0)).arg(parameters.at(1));
2373         }
2374         else if (command == "cos") {
2375             m_currentVMLProperties.normalFormulas += QString("%1*cos(%2 * 0.000000266)").arg(parameters.at(0)).arg(parameters.at(1));
2376         }
2377         else if (command == "tan") {
2378             m_currentVMLProperties.normalFormulas += QString("%1*tan(%2 * 0.000000266)").arg(parameters.at(0)).arg(parameters.at(1));
2379         }
2380     }
2381 
2382     m_currentVMLProperties.normalFormulas += "\" "
2383                                              "/>";
2384 
2385     ++m_currentVMLProperties.formulaIndex;
2386     readNext();
2387     READ_EPILOGUE
2388 }
2389 
2390 #undef CURRENT_EL
2391 #define CURRENT_EL shape
2392 /*! shape handler (Shape Definition)
2393  ECMA-376 Part 4, 14.1.2.19, p.509.
2394 
2395  Parent elements:
2396  - background (Part 1, §17.2.1)
2397  - group (§14.1.2.7)
2398  - [done] object (Part 1, §17.3.3.19)
2399  - [done] pict (§9.2.2.2); pict (§9.5.1)
2400 
2401  Child elements:
2402  - anchorlock (Anchor Location Is Locked) §14.3.2.1
2403  - borderbottom (Bottom Border) §14.3.2.2
2404  - borderleft (Left Border) §14.3.2.3
2405  - borderright (Right Border) §14.3.2.4
2406  - bordertop (Top Border) §14.3.2.5
2407  - callout (Callout) §14.2.2.2
2408  - ClientData (Attached Object Data) §14.4.2.12
2409  - clippath (Shape Clipping Path) §14.2.2.3
2410  - equationxml (Storage for Alternate Math Content) §14.2.2.10
2411  - extrusion (3D Extrusion) §14.2.2.11
2412  - [done] fill (Shape Fill Properties) §14.1.2.5
2413  - [done] formulas (Set of Formulas) §14.1.2.6
2414  - handles (Set of Handles) §14.1.2.9
2415  - [done] imagedata (Image Data) §14.1.2.11
2416  - ink (Ink) §14.2.2.15
2417  - iscomment (Ink Annotation Flag) §14.5.2.1
2418  - lock (Shape Protections) §14.2.2.18
2419  - [done] path (Shape Path) §14.1.2.14
2420  - [done] shadow (Shadow Effect) §14.1.2.18
2421  - signatureline (Digital Signature Line) §14.2.2.30
2422  - skew (Skew Transform) §14.2.2.31
2423  - [done] stroke (Line Stroke Settings) §14.1.2.21
2424  - [done] textbox (Text Box) §14.1.2.22
2425  - textdata (VML Diagram Text) §14.5.2.2
2426  - textpath (Text Layout Path) §14.1.2.23
2427  - [done] wrap (Text Wrapping) §14.3.2.6
2428 */
2429 //! @todo support all elements
2430 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_shape()
2431 {
2432     READ_PROLOGUE
2433 /*    e.g. <v:shape id="_x0000_i1025" type="#_x0000_t75" style="width:166.5pt;height:124.5pt" o:ole="">
2434              <v:imagedata r:id="rId7" o:title=""/>
2435            </v:shape>*/
2436     const QXmlStreamAttributes attrs(attributes());
2437 
2438     TRY_READ_ATTR_WITHOUT_NS(type)
2439     if (!type.isEmpty()) {
2440         type.remove(0, 1); // removes extra # from the start
2441         // Inheriting all values from the template shape, except for group values
2442         // since it is possible that the template was declared outside the group
2443         bool _insideGroup = m_currentVMLProperties.insideGroup;
2444         int _groupWidth = m_currentVMLProperties.groupWidth;
2445         int _groupHeight = m_currentVMLProperties.groupHeight;
2446         int _groupX = m_currentVMLProperties.groupX;
2447         int _groupY = m_currentVMLProperties.groupY;
2448         qreal _groupXOffset = m_currentVMLProperties.groupXOffset;
2449         qreal _groupYOffset = m_currentVMLProperties.groupYOffset;
2450         qreal _real_groupWidth = m_currentVMLProperties.real_groupWidth;
2451         qreal _real_groupHeight = m_currentVMLProperties.real_groupHeight;
2452 
2453         m_currentVMLProperties = m_definedShapeTypes.value(type);
2454 
2455         if (_insideGroup) {
2456             m_currentVMLProperties.insideGroup = _insideGroup;
2457             m_currentVMLProperties.groupWidth = _groupWidth;
2458             m_currentVMLProperties.groupHeight = _groupHeight;
2459             m_currentVMLProperties.groupX = _groupX;
2460             m_currentVMLProperties.groupY = _groupY;
2461             m_currentVMLProperties.groupXOffset = _groupXOffset;
2462             m_currentVMLProperties.groupYOffset = _groupYOffset;
2463             m_currentVMLProperties.real_groupWidth = _real_groupWidth;
2464             m_currentVMLProperties.real_groupHeight = _real_groupHeight;
2465         }
2466     } else {
2467         takeDefaultValues();
2468     }
2469 
2470     handleStrokeAndFill(attrs);
2471 
2472     TRY_READ_ATTR_WITHOUT_NS(id)
2473     m_currentVMLProperties.currentShapeId = id;
2474 
2475     // For some shapes, it seems that this is the correct id.
2476     TRY_READ_ATTR_WITH_NS(o, spid)
2477     if (!o_spid.isEmpty()) {
2478         m_currentVMLProperties.currentShapeId = o_spid;
2479     }
2480 
2481     TRY_READ_ATTR_WITH_NS(o, connectortype)
2482 
2483     // CSS2 styling properties of the shape, http://www.w3.org/TR/REC-CSS2
2484     TRY_READ_ATTR_WITHOUT_NS(style)
2485     RETURN_IF_ERROR(parseCSS(style))
2486     debugMsooXml << "m_vmlStyle:" << m_currentVMLProperties.vmlStyle;
2487 
2488     TRY_READ_ATTR_WITHOUT_NS_INTO(alt, m_currentVMLProperties.shapeAltText)
2489     TRY_READ_ATTR_WITHOUT_NS_INTO(title, m_currentVMLProperties.shapeTitle)
2490 
2491     handlePathValues(attrs);
2492 
2493     MSOOXML::Utils::XmlWriteBuffer frameBuf;
2494     body = frameBuf.setWriter(body);
2495 
2496     pushCurrentDrawStyle(new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic"));
2497     if (m_moveToStylesXml) {
2498         m_currentDrawStyle->setAutoStyleInStylesDotXml(true);
2499     }
2500 
2501     m_currentVMLProperties.wrapRead = false;
2502 
2503     while (!atEnd()) {
2504         readNext();
2505         BREAK_IF_END_OF(CURRENT_EL)
2506         if (isStartElement()) {
2507             TRY_READ_IF(imagedata)
2508             //TODO: represent as draw:frame/draw:text-box
2509             ELSE_TRY_READ_IF(textbox)
2510             ELSE_TRY_READ_IF(stroke)
2511             ELSE_TRY_READ_IF(fill)
2512             ELSE_TRY_READ_IF(shadow)
2513             else if (qualifiedName() == "w10:wrap") {
2514                 m_currentVMLProperties.wrapRead = true;
2515                 TRY_READ(wrap)
2516             }
2517             ELSE_TRY_READ_IF(formulas)
2518             ELSE_TRY_READ_IF(path)
2519             SKIP_UNKNOWN
2520         }
2521     }
2522 
2523     body = frameBuf.originalWriter();
2524     bool makeFrameInstead = false;
2525 
2526     // Checking for a special case where there is a picture and the shape is a rectangle
2527     // In this case we draw a simple frame, this because calligra atm. does not support
2528     // wmf/emf pictures are the background fill of an element
2529     if (!m_currentVMLProperties.imagedataPath.isEmpty() &&
2530         m_currentVMLProperties.shapePath == " M ?f4 ?f5 L ?f4 ?f11 ?f9 ?f11 ?f9 ?f5 Z N") {
2531         m_currentVMLProperties.filled = false;
2532         makeFrameInstead = true;
2533     }
2534 
2535     if (m_outputFrames) {
2536         if (makeFrameInstead) {
2537             createFrameStart();
2538         }
2539         else {
2540             createFrameStart(CustomStart);
2541         }
2542     }
2543 
2544     (void)frameBuf.releaseWriter();
2545 
2546     if (m_outputFrames) {
2547         if (makeFrameInstead) {
2548             body->startElement("draw:image");
2549             body->addAttribute("xlink:type", "simple");
2550             body->addAttribute("xlink:show", "embed");
2551             body->addAttribute("xlink:actuate", "onLoad");
2552             body->addAttribute("xlink:href", m_currentVMLProperties.imagedataPath);
2553             body->endElement(); // draw:image
2554         }
2555         else {
2556             m_currentVMLProperties.shapeTypeString = "<draw:enhanced-geometry ";
2557 
2558             QString flip(m_currentVMLProperties.vmlStyle.value("flip"));
2559             if (flip.contains('x')) {
2560                 m_currentVMLProperties.shapeTypeString += "draw:mirror-vertical=\"true\" ";
2561             }
2562             if (flip.contains('y')) {
2563                 m_currentVMLProperties.shapeTypeString += "draw:mirror-horizontal=\"true\" ";
2564             }
2565             m_currentVMLProperties.shapeTypeString +=
2566                 QString("draw:modifiers=\"%1\" ").arg(m_currentVMLProperties.modifiers) +
2567                 QString("svg:viewBox=\"%1\" ").arg(m_currentVMLProperties.viewBox) +
2568                 QString("draw:enhanced-path=\"%1\" ").arg(m_currentVMLProperties.shapePath) +
2569                 QLatin1Char('>') +
2570                 m_currentVMLProperties.extraShapeFormulas +
2571                 m_currentVMLProperties.normalFormulas +
2572                 "</draw:enhanced-geometry>";
2573 
2574             body->addCompleteElement(m_currentVMLProperties.shapeTypeString.toUtf8());
2575         }
2576         body->endElement(); //draw:frame or draw:custom-shape
2577     }
2578 
2579     popCurrentDrawStyle();
2580 
2581     READ_EPILOGUE
2582 }
2583 
2584 #undef CURRENT_EL
2585 #define CURRENT_EL imagedata
2586 /*! imagedata handler (Image Data)
2587  ECMA-376 Part 4, 14.1.2.11, p.351.
2588 
2589  Parent elements:
2590  - arc (§14.1.2.1)
2591  - background (Part 1, §17.2.1)
2592  - curve (§14.1.2.3)
2593  - [done] group (§14.1.2.7)
2594  - image (§14.1.2.10)
2595  - line (§14.1.2.12)
2596  - object (Part 1, §17.3.3.19)
2597  - oval (§14.1.2.13)
2598  - pict (§9.2.2.2)
2599  - pict (§9.5.1)
2600  - polyline (§14.1.2.15)
2601  - [done] rect (§14.1.2.16)
2602  - [done] roundrect (§14.1.2.17)
2603  - [done] shape (§14.1.2.19)
2604  - [done] shapetype (§14.1.2.20)
2605 
2606  Child elements:
2607  - none
2608 
2609 */
2610 //! @todo support all elements
2611 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_imagedata()
2612 {
2613     READ_PROLOGUE
2614 
2615     m_currentVMLProperties.filled = true;
2616 
2617 /*    e.g. <v:imagedata r:id="rId7" o:title="..."/> */
2618     const QXmlStreamAttributes attrs(attributes());
2619     QString imagedata;
2620     TRY_READ_ATTR_WITH_NS(r, id)
2621     if (!r_id.isEmpty()) {
2622         imagedata = m_context->relationships->target(m_context->path, m_context->file, r_id);
2623     }
2624     else {
2625         TRY_READ_ATTR_WITH_NS(o, relid)
2626         if (!o_relid.isEmpty()) {
2627             imagedata = m_context->relationships->target(m_context->path, m_context->file, o_relid);
2628         }
2629     }
2630 
2631     debugMsooXml << "imagedata:" << imagedata;
2632     if (!imagedata.isEmpty()) {
2633         m_currentVMLProperties.imagedataPath = QLatin1String("Pictures/") + imagedata.mid(imagedata.lastIndexOf('/') + 1);
2634         KoFilter::ConversionStatus status = m_context->import->copyFile(imagedata, m_currentVMLProperties.imagedataPath, false);
2635         if (status == KoFilter::OK) {
2636             addManifestEntryForFile(m_currentVMLProperties.imagedataPath);
2637             addManifestEntryForPicturesDir();
2638             m_currentVMLProperties.fillType = "picture";
2639         }
2640         else {
2641             m_currentVMLProperties.fillType = "solid"; // defaulting
2642         }
2643     }
2644 
2645     readNext();
2646     READ_EPILOGUE
2647 }
2648 
2649 #undef CURRENT_EL
2650 #define CURRENT_EL textbox
2651 /*! text box handler (Text Box)
2652 
2653  Parent elements:
2654  - [done] shape (§14.1.2.19)
2655  - more...
2656 
2657 */
2658 //! @todo support all elements
2659 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_textbox()
2660 {
2661     READ_PROLOGUE
2662 
2663     const QXmlStreamAttributes attrs(attributes());
2664     VMLShapeProperties oldProperties = m_currentVMLProperties;
2665     TRY_READ_ATTR_WITHOUT_NS(style)
2666     RETURN_IF_ERROR(parseCSS(style))
2667 
2668     if (m_currentVMLProperties.vmlStyle.value("mso-fit-shape-to-text") == "t") {
2669         oldProperties.fitShapeToText = true;
2670     }
2671     if (m_currentVMLProperties.vmlStyle.value("mso-fit-text-to-shape") == "t") {
2672         oldProperties.fitTextToShape = true;
2673     }
2674 
2675     // In below code, the else clauses are needed for cases that not
2676     // all insets are defined
2677     TRY_READ_ATTR_WITHOUT_NS(inset)
2678     if (!inset.isEmpty()) {
2679         doPrependCheck(inset);
2680         inset.replace(",,", ",d,"); //Default
2681         int index = inset.indexOf(',');
2682         if (index > 0) {
2683             QString str = inset.left(index);
2684             if (str != "d") {
2685                 if (str == "0") {
2686                     str.append("in");
2687                 }
2688                 oldProperties.internalMarginLeft = str;
2689             }
2690             inset.remove(0, index + 1);
2691             doPrependCheck(inset);
2692             index = inset.indexOf(',');
2693             if (index > 0) {
2694                 str = inset.left(index);
2695                 if (str != "d") {
2696                     if (str == "0") {
2697                         str.append("in");
2698                     }
2699                     oldProperties.internalMarginTop = str;
2700                 }
2701                 inset.remove(0, index + 1);
2702                 doPrependCheck(inset);
2703                 index = inset.indexOf(',');
2704                 if (index > 0) {
2705                     str = inset.left(index);
2706                     if (str != "d") {
2707                         if (str == "0") {
2708                             str.append("in");
2709                         }
2710                         oldProperties.internalMarginRight = str;
2711                     }
2712                     str = inset.mid(index + 1);
2713                     if (str != "d") {
2714                         if (str == "0") {
2715                             str.append("in");
2716                         }
2717                         oldProperties.internalMarginBottom = str;
2718                         doPrependCheck(oldProperties.internalMarginBottom);
2719                     }
2720                 } else {
2721                     str = inset.left(index);
2722                     if (str != "d") {
2723                         if (str == "0") {
2724                             str.append("in");
2725                         }
2726                         oldProperties.internalMarginRight = str;
2727                     }
2728                 }
2729             } else {
2730                 str = inset.left(index);
2731                 if (str != "d") {
2732                     if (str == "0") {
2733                         str.append("in");
2734                     }
2735                     oldProperties.internalMarginTop = str;
2736                 }
2737             }
2738         }
2739     }
2740 
2741     while (!atEnd()) {
2742         readNext();
2743         BREAK_IF_END_OF(CURRENT_EL)
2744         if (isStartElement()) {
2745 #ifdef DOCXXMLDOCREADER_CPP
2746             TRY_READ_IF_NS(w, txbxContent)
2747 #endif
2748         }
2749     }
2750 
2751     m_currentVMLProperties = oldProperties;
2752 
2753     READ_EPILOGUE
2754 }
2755 
2756 #undef CURRENT_EL
2757 #define CURRENT_EL path
2758 /*! path handler (Shape path)
2759 
2760  Parent elements:
2761  - arc (§14.1.2.1);
2762  - background (Part 1, §17.2.1);
2763  - curve (§14.1.2.3);
2764  - group (§14.1.2.7);
2765  - image (§14.1.2.10);
2766  - line (§14.1.2.12);
2767  - object (Part 1, §17.3.3.19);
2768  - oval (§14.1.2.13);
2769  - pict (§9.2.2.2);
2770  - pict (§9.5.1);
2771  - polyline (§14.1.2.15);
2772  - rect (§14.1.2.16);
2773  - roundrect (§14.1.2.17);
2774  - [done] shape (§14.1.2.19);
2775  - [done] shapetype (§14.1.2.20)
2776 
2777  Child elements:
2778  - none
2779 */
2780 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_path()
2781 {
2782     READ_PROLOGUE
2783 
2784     const QXmlStreamAttributes attrs(attributes());
2785 
2786     TRY_READ_ATTR_WITHOUT_NS(shadowok)
2787     if (shadowok == "f" || shadowok == "false") {
2788         m_currentVMLProperties.shadowed = false;
2789     }
2790 
2791     TRY_READ_ATTR_WITHOUT_NS(fillok)
2792     if (fillok == "f" || fillok == "false") {
2793         m_currentVMLProperties.filled = false;
2794     }
2795 
2796     TRY_READ_ATTR_WITHOUT_NS(strokeok)
2797     if (strokeok == "f" || strokeok == "false") {
2798         m_currentVMLProperties.stroked = false;
2799     }
2800 
2801     TRY_READ_ATTR_WITHOUT_NS(v)
2802     if (!v.isEmpty()) {
2803         m_currentVMLProperties.extraShapeFormulas.clear();
2804         m_currentVMLProperties.shapePath = convertToEnhancedPath(v, m_currentVMLProperties.extraShapeFormulas);
2805     }
2806 
2807     readNext();
2808 
2809     READ_EPILOGUE
2810 }
2811 
2812 void MSOOXML_CURRENT_CLASS::handlePathValues(const QXmlStreamAttributes& attrs)
2813 {
2814     TRY_READ_ATTR_WITHOUT_NS(adj)
2815     if (!adj.isEmpty()) {
2816         QString tempModifiers = adj;
2817         doPrependCheck(tempModifiers);
2818         tempModifiers.replace(",,", ",0,");
2819         tempModifiers.replace(',', ' ');
2820         m_currentVMLProperties.modifiers = tempModifiers;
2821     }
2822 
2823     TRY_READ_ATTR_WITHOUT_NS(coordsize)
2824     if (!coordsize.isEmpty()) {
2825         QString tempViewBox = "0 0 " + coordsize;
2826         tempViewBox.replace(',', ' ');
2827         m_currentVMLProperties.viewBox = tempViewBox;
2828     }
2829 
2830     TRY_READ_ATTR_WITHOUT_NS(path)
2831     if (!path.isEmpty()) {
2832         m_currentVMLProperties.extraShapeFormulas.clear();
2833         m_currentVMLProperties.shapePath = convertToEnhancedPath(path, m_currentVMLProperties.extraShapeFormulas);
2834     }
2835 }
2836 
2837 #undef MSOOXML_CURRENT_NS
2838 #define MSOOXML_CURRENT_NS "w10"
2839 
2840 #undef CURRENT_EL
2841 #define CURRENT_EL wrap
2842 // Wrap handler, todo fully..
2843 KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_wrap()
2844 {
2845     READ_PROLOGUE
2846 
2847     const QXmlStreamAttributes attrs(attributes());
2848 
2849     TRY_READ_ATTR_WITHOUT_NS(type)
2850     TRY_READ_ATTR_WITHOUT_NS(side)
2851 
2852     if (type.isEmpty()) {
2853         if (m_currentVMLProperties.vmlStyle.contains("z-index")) {
2854             m_currentDrawStyle->addProperty("style:wrap", "run-through");
2855             if (m_currentVMLProperties.vmlStyle.value("z-index").toInt() > 0) {
2856                 m_currentDrawStyle->addProperty("style:run-through", "foreground");
2857             }
2858             else {
2859                 m_currentDrawStyle->addProperty("style:run-through", "background");
2860             }
2861         }
2862         else {
2863             m_currentDrawStyle->addProperty("style:wrap", "run-through");
2864             m_currentDrawStyle->addProperty("style:run-through", "foreground");
2865         }
2866     }
2867     else if (type == "through" || type == "square" || type == "tight") {
2868         if (type == "square" || type == "tight") {
2869             m_currentDrawStyle->addProperty("style:wrap-contour-mode", "outside");
2870             m_currentDrawStyle->addProperty("style:wrap-contour", "false");
2871         }
2872         else {
2873             m_currentDrawStyle->addProperty("style:wrap-contour-mode", "full");
2874             m_currentDrawStyle->addProperty("style:wrap-contour", "true");
2875         }
2876         if (side.isEmpty()) {
2877             m_currentDrawStyle->addProperty("style:wrap", "parallel");
2878         }
2879         else if (side == "left") {
2880             m_currentDrawStyle->addProperty("style:wrap", "left");
2881         }
2882         else if (side == "largest") {
2883             m_currentDrawStyle->addProperty("style:wrap", "biggest");
2884         }
2885         else if (side == "right") {
2886             m_currentDrawStyle->addProperty("style:wrap", "right");
2887         }
2888         else if (side == "both") {
2889             m_currentDrawStyle->addProperty("style:wrap", "parallel");
2890         }
2891     }
2892     else if (type == "topAndBottom") {
2893         m_currentDrawStyle->addProperty("style:wrap", "none");
2894     }
2895     else {
2896         if (side.isEmpty()) { // Note doc doesn't say which one is default
2897             m_currentDrawStyle->addProperty("style:wrap", "biggest");
2898         }
2899         else if (side == "left") {
2900             m_currentDrawStyle->addProperty("style:wrap", "left");
2901         }
2902         else if (side == "largest") {
2903             m_currentDrawStyle->addProperty("style:wrap", "biggest");
2904         }
2905         else if (side == "right") {
2906             m_currentDrawStyle->addProperty("style:wrap", "right");
2907         }
2908         else if (side == "both") {
2909             m_currentDrawStyle->addProperty("style:wrap", "parallel");
2910         }
2911     }
2912 
2913     TRY_READ_ATTR_WITHOUT_NS(anchorx)
2914     TRY_READ_ATTR_WITHOUT_NS(anchory)
2915 
2916     // Documentation says default to be 'page', however because these are always in a paragraph
2917     // in a text run, a better default for odf purposes seems to be 'paragraph'
2918 
2919 #ifdef DOCXMLDOCREADER_H
2920     if (anchory == "page") {
2921         if (m_headerActive || m_footerActive) {
2922             m_currentDrawStyle->addProperty("style:vertical-rel", "frame");
2923             m_currentVMLProperties.anchorType = "frame";
2924         } else {
2925             m_currentDrawStyle->addProperty("style:vertical-rel", "page");
2926             m_currentVMLProperties.anchorType = "page";
2927         }
2928     }
2929     else if (anchory == "text") {
2930         m_currentVMLProperties.anchorType = "as-char";
2931         m_currentDrawStyle->addProperty("style:vertical-rel", "text");
2932     }
2933     else if (anchory == "line") {
2934         m_currentVMLProperties.anchorType = "as-char";
2935         m_currentDrawStyle->addProperty("style:vertical-rel", "line");
2936     }
2937     else { // margin
2938         m_currentVMLProperties.anchorType = "paragraph";
2939         m_currentDrawStyle->addProperty("style:vertical-rel", "paragraph");
2940     }
2941 
2942     if (anchorx == "page") {
2943         m_currentDrawStyle->addProperty("style:horizontal-rel", "page");
2944     }
2945     else if (anchorx == "margin") {
2946         m_currentDrawStyle->addProperty("style:horizontal-rel", "page-start-margin");
2947     }
2948     else if (anchorx == "text") {
2949         // Empty, horizontal-rel cannot be anything
2950     }
2951     else {
2952         m_currentDrawStyle->addProperty("style:horizontal-rel", "paragraph");
2953     }
2954 #endif
2955 
2956     readNext();
2957     READ_EPILOGUE
2958 }
2959 
2960 #endif // MSOOXMLVMLREADER_IMPL_H