Warning, file /office/calligra/filters/libmsooxml/MsooXmlVmlReaderImpl.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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