File indexing completed on 2024-12-08 12:55:57
0001 /* This file is part of the KDE project 0002 Copyright (C) 2010 KO GmbH <jos.van.den.oever@kogmbh.com> 0003 Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 /** 0022 * Note that the implementations here are supposed to be defined by DrawingML. 0023 * This details the geometry etc. in Appendix D, in the file 0024 * presetShapeDefinitions.xml. 0025 * 0026 * @note Of the {Bent,Curved}Connector[2345] shapes, the MS Office only seems to 0027 * support the [23] variants. The remainder have been coded in a manner 0028 * consistent with the [23] variants, but have not been tested. 0029 */ 0030 0031 #include "ODrawToOdf.h" 0032 #include "drawstyle.h" 0033 #include "msodraw.h" 0034 #include "generated/leinputstream.h" 0035 #include "writeodf/writeodfdraw.h" 0036 0037 #include <QDebug> 0038 #include <QPainterPath> 0039 #include <QTransform> 0040 #include <QBuffer> 0041 #include <QUrl> 0042 0043 #include <cmath> 0044 0045 0046 using namespace MSO; 0047 using namespace writeodf; 0048 0049 qint16 0050 ODrawToOdf::normalizeRotation(qreal rotation) 0051 { 0052 qint16 angle = ((qint16)rotation) % 360; 0053 if (angle < 0) { 0054 angle = angle + 360; 0055 } 0056 return angle; 0057 } 0058 0059 /** 0060 * Return the bounding rectangle for this object. 0061 **/ 0062 QRectF 0063 ODrawToOdf::getRect(const OfficeArtSpContainer &o) 0064 { 0065 if (o.childAnchor) { 0066 const OfficeArtChildAnchor& r = *o.childAnchor; 0067 return QRect(r.xLeft, r.yTop, r.xRight - r.xLeft, r.yBottom - r.yTop); 0068 } else if (o.clientAnchor && client) { 0069 return client->getRect(*o.clientAnchor); 0070 } else if (o.shapeProp.fHaveAnchor && client) { 0071 return client->getReserveRect(); 0072 } else { 0073 return QRectF(); 0074 } 0075 } 0076 0077 QRectF 0078 ODrawToOdf::processRect(const quint16 shapeType, const qreal rotation, QRectF &rect) 0079 { 0080 bool transform_anchor = false; 0081 qint16 nrotation = normalizeRotation(rotation); 0082 0083 //TODO: Add other shapes here! 0084 0085 switch (shapeType) { 0086 case msosptNotPrimitive: 0087 if ( ((nrotation >= 45) && (nrotation < 135)) || 0088 ((nrotation >= 225) && (nrotation < 315))) 0089 { 0090 transform_anchor = true; 0091 } 0092 break; 0093 default: 0094 break; 0095 } 0096 if (transform_anchor) { 0097 QPointF center = rect.center(); 0098 QTransform transform; 0099 transform.rotate(90); 0100 rect = transform.mapRect(rect.translated(-center)).translated(center); 0101 } 0102 return rect; 0103 } 0104 0105 void ODrawToOdf::processRectangle(const OfficeArtSpContainer& o, Writer& out) 0106 { 0107 // TODO: Use client->isPlaceholder - might require an update of the 0108 // placeholderAllowed function in the PPT filter. Trying to save as many 0109 // shapes into draw:text-box at the moment, because vertical alignment in 0110 // draw:custom-shape does not work properly (bug 288047). 0111 if (o.clientData && client->processRectangleAsTextBox(*o.clientData)) { 0112 processTextBox(o, out); 0113 } else { 0114 const DrawStyle ds(0, 0, &o); 0115 if (ds.pib()) { 0116 // see bug https://bugs.kde.org/show_bug.cgi?id=285577 0117 processPictureFrame(o, out); 0118 } else { 0119 draw_custom_shape rect(&out.xml); 0120 processStyleAndText(o, out); 0121 draw_enhanced_geometry eg(rect.add_draw_enhanced_geometry()); 0122 eg.set_svg_viewBox("0 0 21600 21600"); 0123 eg.set_draw_enhanced_path("M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N"); 0124 eg.set_draw_type("rectangle"); 0125 setShapeMirroring(o, out); 0126 } 0127 } 0128 } 0129 0130 void ODrawToOdf::processTextBox(const OfficeArtSpContainer& o, Writer& out) 0131 { 0132 draw_frame frame(&out.xml); 0133 processStyle(o, out); 0134 draw_text_box text(frame.add_draw_text_box()); 0135 processText(o, out); 0136 } 0137 0138 void ODrawToOdf::processLine(const OfficeArtSpContainer& o, Writer& out) 0139 { 0140 const QRectF rect = getRect(o); 0141 qreal x1 = rect.x(); 0142 qreal y1 = rect.y(); 0143 qreal x2 = rect.x() + rect.width(); 0144 qreal y2 = rect.y() + rect.height(); 0145 0146 // shape mirroring 0147 if (o.shapeProp.fFlipV) { 0148 qSwap(y1, y2); 0149 } 0150 if (o.shapeProp.fFlipH) { 0151 qSwap(x1, x2); 0152 } 0153 0154 draw_line line(&out.xml, 0155 client->formatPos(out.hOffset(x1)), 0156 client->formatPos(out.hOffset(x2)), 0157 client->formatPos(out.vOffset(y1)), 0158 client->formatPos(out.vOffset(y2))); 0159 addGraphicStyleToDrawElement(out, o); 0160 line.set_draw_layer("layout"); 0161 processText(o, out); 0162 } 0163 0164 void ODrawToOdf::drawStraightConnector1(qreal l, qreal t, qreal r, qreal b, Writer& out, QPainterPath &shapePath) const 0165 { 0166 out.xml.addAttribute("draw:type", "line"); 0167 shapePath.moveTo(l, t); 0168 shapePath.lineTo(r, b); 0169 } 0170 0171 void ODrawToOdf::drawPathBentConnector2(qreal l, qreal t, qreal r, qreal b, Writer& out, QPainterPath &shapePath) const 0172 { 0173 Q_UNUSED(out); 0174 shapePath.moveTo(l, t); 0175 shapePath.lineTo(r, t); 0176 shapePath.lineTo(r, b); 0177 } 0178 0179 void ODrawToOdf::drawPathBentConnector3(qreal l, qreal t, qreal r, qreal b, Writer& out, QPainterPath &shapePath) const 0180 { 0181 Q_UNUSED(out); 0182 qreal w = qAbs(r - l); 0183 qreal adj1 = 50000; 0184 qreal x1 = w * adj1 / 100000; 0185 0186 shapePath.moveTo(l, t); 0187 shapePath.lineTo(l + x1, t); 0188 shapePath.lineTo(l + x1, b); 0189 shapePath.lineTo(r, b); 0190 } 0191 0192 void ODrawToOdf::drawPathBentConnector4(qreal l, qreal t, qreal r, qreal b, Writer& out, QPainterPath &shapePath) const 0193 { 0194 Q_UNUSED(out); 0195 qreal w = qAbs(r - l); 0196 qreal h = qAbs(b - t); 0197 qreal adj1 = 50000; 0198 qreal adj2 = 50000; 0199 qreal x1 = w * adj1 / 100000; 0200 // qreal x2 = x1 + r / 2; 0201 qreal y2 = h * adj2 / 100000; 0202 // qreal y1 = t + y2 / 2; 0203 0204 shapePath.moveTo(l, t); 0205 shapePath.lineTo(l + x1, t); 0206 shapePath.lineTo(l + x1, y2); 0207 shapePath.lineTo(r, y2); 0208 shapePath.lineTo(r, b); 0209 } 0210 0211 void ODrawToOdf::drawPathBentConnector5(qreal l, qreal t, qreal r, qreal b, Writer& out, QPainterPath &shapePath) const 0212 { 0213 Q_UNUSED(out); 0214 qreal w = qAbs(r - l); 0215 qreal h = qAbs(b - t); 0216 qreal adj1 = 50000; 0217 qreal adj2 = 50000; 0218 qreal adj3 = 50000; 0219 qreal x1 = w * adj1 / 100000; 0220 qreal x3 = w * adj3 / 100000; 0221 // qreal x2 = x1 + x3 / 2; 0222 qreal y2 = h * adj2 / 100000; 0223 // qreal y1 = t + y2 / 2; 0224 // qreal y3 = b + y2 / 2; 0225 0226 shapePath.moveTo(l, t); 0227 shapePath.lineTo(l + x1, t); 0228 shapePath.lineTo(l + x1, y2); 0229 shapePath.lineTo(l + x3, y2); 0230 shapePath.lineTo(l + x3, b); 0231 shapePath.lineTo(r, b); 0232 } 0233 0234 void ODrawToOdf::drawPathCurvedConnector2(qreal l, qreal t, qreal r, qreal b, Writer& out, QPainterPath &shapePath) const 0235 { 0236 Q_UNUSED(out); 0237 qreal w = qAbs(r - l); 0238 qreal h = qAbs(b - t); 0239 0240 shapePath.moveTo(l, t); 0241 shapePath.cubicTo(l + w / 2, t, r, h / 2, r, b); 0242 } 0243 0244 void ODrawToOdf::drawPathCurvedConnector3(qreal l, qreal t, qreal r, qreal b, Writer& out, QPainterPath &shapePath) const 0245 { 0246 Q_UNUSED(out); 0247 qreal w = qAbs(r - l); 0248 qreal h = qAbs(b - t); 0249 qreal adj1 = 50000; 0250 qreal x2 = w * adj1 / 100000; 0251 qreal x1 = l + x2 /*/ 2*/; 0252 // qreal x3 = r + x2 / 2; 0253 // qreal y3 = h * 3 / 4; 0254 0255 shapePath.moveTo(l, t); 0256 shapePath.cubicTo(x1, t, x1, t + h / 2, l + x2, t + h / 2); 0257 shapePath.cubicTo(l + x2, t + h / 2, l + x2, b, r, b); 0258 } 0259 0260 void ODrawToOdf::drawPathCurvedConnector4(qreal l, qreal t, qreal r, qreal b, Writer& out, QPainterPath &shapePath) const 0261 { 0262 Q_UNUSED(out); 0263 qreal w = qAbs(r - l); 0264 qreal h = qAbs(b - t); 0265 qreal adj1 = 50000; 0266 qreal adj2 = 50000; 0267 qreal x2 = w * adj1 / 100000; 0268 qreal x1 = l + x2 / 2; 0269 qreal x3 = r + x2 / 2; 0270 qreal x4 = x2 + x3 / 2; 0271 qreal x5 = x3 + r / 2; 0272 qreal y4 = h * adj2 / 100000; 0273 qreal y1 = t + y4 / 2; 0274 qreal y2 = t + y1 / 2; 0275 qreal y3 = y1 + y4 / 2; 0276 qreal y5 = b + y4 / 2; 0277 0278 shapePath.moveTo(l, t); 0279 shapePath.cubicTo(x1, t, l + x2, y2, l + x2, y1); 0280 shapePath.cubicTo(l + x2, y3, x4, y4, x3, y4); 0281 shapePath.cubicTo(x5, y4, r, y5, r, b); 0282 } 0283 0284 void ODrawToOdf::drawPathCurvedConnector5(qreal l, qreal t, qreal r, qreal b, Writer& out, QPainterPath &shapePath) const 0285 { 0286 Q_UNUSED(out); 0287 qreal w = qAbs(r - l); 0288 qreal h = qAbs(b - t); 0289 qreal adj1 = 50000; 0290 qreal adj2 = 50000; 0291 qreal adj3 = 50000; 0292 qreal x3 = w * adj1 / 100000; 0293 qreal x6 = w * adj3 / 100000; 0294 qreal x1 = x3 + x6 / 2; 0295 qreal x2 = l + x3 / 2; 0296 qreal x4 = x3 + x1 / 2; 0297 qreal x5 = x6 + x1 / 2; 0298 qreal x7 = x6 + r / 2; 0299 qreal y4 = h * adj2 / 100000; 0300 qreal y1 = t + y4 / 2; 0301 qreal y2 = t + y1 / 2; 0302 qreal y3 = y1 + y4 / 2; 0303 qreal y5 = b + y4 / 2; 0304 qreal y6 = y5 + y4 / 2; 0305 qreal y7 = y5 + b / 2; 0306 0307 shapePath.moveTo(l, t); 0308 shapePath.cubicTo(x2, t, l + x3, y2, l + x3, y1); 0309 shapePath.cubicTo(x3, y3, x4, y4, x1, y4); 0310 shapePath.cubicTo(x5, y4, l + x6, y6, l + x6, y5); 0311 shapePath.cubicTo(l + x6, y7, x7, b, r, b); 0312 } 0313 0314 /** 0315 * Common handler for Connectors. 0316 */ 0317 void ODrawToOdf::processConnector(const OfficeArtSpContainer& o, Writer& out, PathArtist drawPath) 0318 { 0319 const OfficeArtDggContainer * drawingGroup = 0; 0320 if (client) { 0321 drawingGroup = client->getOfficeArtDggContainer(); 0322 } 0323 0324 const OfficeArtSpContainer* master = 0; 0325 const DrawStyle ds(drawingGroup, master, &o); 0326 qreal rotation = toQReal( ds.rotation() ); 0327 0328 const QRectF rect = getRect(o); 0329 qreal x1 = rect.x(); 0330 qreal y1 = rect.y(); 0331 qreal x2 = rect.x() + rect.width(); 0332 qreal y2 = rect.y() + rect.height(); 0333 0334 QRectF shapeRect = rect; 0335 0336 qreal sx1 = x1; 0337 qreal sy1 = y1; 0338 qreal sx2 = x2; 0339 qreal sy2 = y2; 0340 0341 if (rotation != 0.0) { 0342 QTransform m; 0343 m.rotate( -rotation ); 0344 shapeRect = m.mapRect(rect.translated(-rect.center())).translated(rect.center()); 0345 0346 sx1 = shapeRect.topLeft().x(); 0347 sy1 = shapeRect.topLeft().y(); 0348 sx2 = shapeRect.bottomRight().x(); 0349 sy2 = shapeRect.bottomRight().y(); 0350 } 0351 0352 // Prepare to transform the path according the shape properties like flip 0353 // and rotation. 0354 QTransform m; 0355 m.reset(); 0356 m.translate( -shapeRect.center().x(), -shapeRect.center().y() ); 0357 0358 // Mirroring 0359 if (o.shapeProp.fFlipH){ 0360 m.scale(-1,1); 0361 } 0362 0363 if (o.shapeProp.fFlipV){ 0364 m.scale(1,-1); 0365 } 0366 0367 if (rotation != 0) { 0368 m.rotate(rotation); 0369 } 0370 0371 m.translate( shapeRect.center().x(), shapeRect.center().y() ); 0372 0373 // the viewbox should be set, where is this done for draw:connector? 0374 out.xml.startElement("draw:connector"); 0375 addGraphicStyleToDrawElement(out, o); 0376 out.xml.addAttribute("draw:layer", "layout"); 0377 0378 // Compute path and transform it. 0379 QPainterPath shapePath; 0380 (this->*drawPath)(sx1, sy1, sx2, sy2, out, shapePath); 0381 0382 shapePath = m.map(shapePath); 0383 0384 // translate the QPainterPath into svg:d attribute 0385 QString path = path2svg(shapePath); 0386 0387 out.xml.addAttribute("svg:x1", client->formatPos(out.hOffset(x1))); 0388 out.xml.addAttribute("svg:y1", client->formatPos(out.vOffset(y1))); 0389 out.xml.addAttribute("svg:x2", client->formatPos(out.hOffset(x2))); 0390 out.xml.addAttribute("svg:y2", client->formatPos(out.vOffset(y2))); 0391 if (!path.isEmpty()) { 0392 out.xml.addAttribute("svg:d", path); 0393 } 0394 0395 processText(o, out); 0396 out.xml.endElement(); 0397 } 0398 0399 void ODrawToOdf::processPictureFrame(const OfficeArtSpContainer& o, Writer& out) 0400 { 0401 DrawStyle ds(0, &o); 0402 0403 // A value of 0x00000000 MUST be ignored. [MS-ODRAW] — v20101219 0404 if (!ds.pib()) return; 0405 0406 draw_frame frame(&out.xml); 0407 processStyle(o, out); 0408 0409 //NOTE: OfficeArtClienData might contain additional information 0410 //about a shape. 0411 0412 QString url; 0413 if (client) { 0414 url = client->getPicturePath(ds.pib()); 0415 } 0416 // if the image cannot be found, just place an empty frame 0417 if (url.isEmpty()) { 0418 return; 0419 } 0420 draw_image image(frame.add_draw_image()); 0421 image.set_xlink_href(QUrl(url)); 0422 image.set_xlink_type("simple"); 0423 image.set_xlink_show("embed"); 0424 image.set_xlink_actuate("onLoad"); 0425 } 0426 0427 void ODrawToOdf::processNotPrimitive(const MSO::OfficeArtSpContainer& o, Writer& out) 0428 { 0429 draw_custom_shape shape(&out.xml); 0430 processStyleAndText(o, out); 0431 draw_enhanced_geometry eg(shape.add_draw_enhanced_geometry()); 0432 setEnhancedGeometry(o, out); 0433 } 0434 0435 0436 void ODrawToOdf::processDrawingObject(const OfficeArtSpContainer& o, Writer& out) 0437 { 0438 if (!client) { 0439 qWarning() << "Warning: There's no Client!"; 0440 return; 0441 } 0442 0443 quint16 shapeType = o.shapeProp.rh.recInstance; 0444 client->m_currentShapeType = o.shapeProp.rh.recInstance; 0445 0446 switch (shapeType) { 0447 case msosptNotPrimitive: 0448 processNotPrimitive(o, out); 0449 break; 0450 case msosptRectangle: 0451 processRectangle(o, out); 0452 break; 0453 case msosptRoundRectangle: 0454 processRoundRectangle(o, out); 0455 break; 0456 case msosptEllipse: 0457 // TODO: Something has to be done here (LukasT). LukasT: 0458 // "Great comment", can you provide more details? :) 0459 processEllipse(o, out); 0460 break; 0461 case msosptDiamond: 0462 processDiamond(o, out); 0463 break; 0464 case msosptIsocelesTriangle: 0465 processIsocelesTriangle(o, out); 0466 break; 0467 case msosptRightTriangle: 0468 processRightTriangle(o, out); 0469 break; 0470 case msosptParallelogram: 0471 processParallelogram(o, out); 0472 break; 0473 case msosptTrapezoid: 0474 processTrapezoid(o, out); 0475 break; 0476 case msosptHexagon: 0477 processHexagon(o, out); 0478 break; 0479 case msosptOctagon: 0480 processOctagon(o, out); 0481 break; 0482 case msosptPlus: 0483 processPlus(o, out); 0484 break; 0485 case msosptStar: 0486 processStar(o, out); 0487 break; 0488 case msosptArrow: 0489 processArrow(o, out); 0490 break; 0491 // 0492 // TODO: msosptThickArrow 0493 // 0494 case msosptHomePlate: 0495 processHomePlate(o, out); 0496 break; 0497 case msosptCube: 0498 processCube(o, out); 0499 break; 0500 // 0501 // TODO: msosptBaloon, msosptSeal 0502 // 0503 0504 // NOTE: OpenOffice treats msosptNotchedCircularArrow as msosptArc. The 0505 // msosptNotchedCircularArrow value SHOULD NOT be used according to the 0506 // MS-ODRAW spec. However it occurs in many Word8 files. 0507 case msosptArc: 0508 processNotchedCircularArrow(o, out); 0509 break; 0510 case msosptLine: 0511 processLine(o, out); 0512 break; 0513 case msosptPlaque: 0514 processPlaque(o, out); 0515 break; 0516 case msosptCan: 0517 processCan(o, out); 0518 break; 0519 case msosptDonut: 0520 processDonut(o, out); 0521 break; 0522 // 0523 // TODO: msosptTextSimple, msosptTextOctagon, msosptTextHexagon, 0524 // msosptTextCurve, msosptTextWave, msosptTextRing, msosptTextOnCurve, 0525 // msosptTextOnRing 0526 // 0527 case msosptStraightConnector1: 0528 processConnector(o, out, &ODrawToOdf::drawStraightConnector1); 0529 break; 0530 case msosptBentConnector2: 0531 processConnector(o, out, &ODrawToOdf::drawPathBentConnector2); 0532 break; 0533 case msosptBentConnector3: 0534 processConnector(o, out, &ODrawToOdf::drawPathBentConnector3); 0535 break; 0536 case msosptBentConnector4: 0537 processConnector(o, out, &ODrawToOdf::drawPathBentConnector4); 0538 break; 0539 case msosptBentConnector5: 0540 processConnector(o, out, &ODrawToOdf::drawPathBentConnector5); 0541 break; 0542 case msosptCurvedConnector2: 0543 processConnector(o, out, &ODrawToOdf::drawPathCurvedConnector2); 0544 break; 0545 case msosptCurvedConnector3: 0546 processConnector(o, out, &ODrawToOdf::drawPathCurvedConnector3); 0547 break; 0548 case msosptCurvedConnector4: 0549 processConnector(o, out, &ODrawToOdf::drawPathCurvedConnector4); 0550 break; 0551 case msosptCurvedConnector5: 0552 processConnector(o, out, &ODrawToOdf::drawPathCurvedConnector5); 0553 break; 0554 case msosptCallout1: 0555 processCallout1(o, out); 0556 break; 0557 case msosptCallout2: 0558 processCallout2(o, out); 0559 break; 0560 case msosptCallout3: 0561 processCallout3(o, out); 0562 break; 0563 case msosptAccentCallout1: 0564 processAccentCallout1(o, out); 0565 break; 0566 case msosptAccentCallout2: 0567 processAccentCallout2(o, out); 0568 break; 0569 case msosptAccentCallout3: 0570 processAccentCallout3(o, out); 0571 break; 0572 case msosptBorderCallout1: 0573 processBorderCallout1(o, out); 0574 break; 0575 case msosptBorderCallout2: 0576 processBorderCallout2(o, out); 0577 break; 0578 case msosptBorderCallout3: 0579 processBorderCallout3(o, out); 0580 break; 0581 case msosptAccentBorderCallout1: 0582 processAccentBorderCallout1(o, out); 0583 break; 0584 case msosptAccentBorderCallout2: 0585 processAccentBorderCallout2(o, out); 0586 break; 0587 case msosptAccentBorderCallout3: 0588 processAccentBorderCallout3(o, out); 0589 break; 0590 case msosptRibbon: 0591 processRibbon(o, out); 0592 break; 0593 case msosptRibbon2: 0594 processRibbon2(o, out); 0595 break; 0596 case msosptChevron: 0597 processChevron(o, out); 0598 break; 0599 case msosptPentagon: 0600 processPentagon(o, out); 0601 break; 0602 case msosptNoSmoking: 0603 processNoSmoking(o, out); 0604 break; 0605 case msosptSeal8: 0606 processSeal8(o, out); 0607 break; 0608 case msosptSeal16: 0609 processSeal16(o, out); 0610 break; 0611 case msosptSeal32: 0612 processSeal32(o, out); 0613 break; 0614 case msosptWedgeRectCallout: 0615 processWedgeRectCallout(o, out); 0616 break; 0617 case msosptWedgeRRectCallout: 0618 processWedgeRRectCallout(o, out); 0619 break; 0620 case msosptWedgeEllipseCallout: 0621 processWedgeEllipseCallout(o, out); 0622 break; 0623 case msosptWave: 0624 processWave(o, out); 0625 break; 0626 case msosptFoldedCorner: 0627 processFoldedCorner(o, out); 0628 break; 0629 case msosptLeftArrow: 0630 processLeftArrow(o, out); 0631 break; 0632 case msosptDownArrow: 0633 processDownArrow(o, out); 0634 break; 0635 case msosptUpArrow: 0636 processUpArrow(o, out); 0637 break; 0638 case msosptLeftRightArrow: 0639 processLeftRightArrow(o, out); 0640 break; 0641 case msosptUpDownArrow: 0642 processUpDownArrow(o, out); 0643 break; 0644 case msosptIrregularSeal1: 0645 processIrregularSeal1(o, out); 0646 break; 0647 case msosptIrregularSeal2: 0648 processIrregularSeal2(o, out); 0649 break; 0650 case msosptLightningBolt: 0651 processLightningBolt(o, out); 0652 break; 0653 case msosptHeart: 0654 processHeart(o, out); 0655 break; 0656 case msosptPictureFrame: 0657 processPictureFrame(o, out); 0658 break; 0659 case msosptQuadArrow: 0660 processQuadArrow(o, out); 0661 break; 0662 case msosptLeftArrowCallout: 0663 processLeftArrowCallout(o, out); 0664 break; 0665 case msosptRightArrowCallout: 0666 processRightArrowCallout(o, out); 0667 break; 0668 case msosptUpArrowCallout: 0669 processUpArrowCallout(o, out); 0670 break; 0671 case msosptDownArrowCallout: 0672 processDownArrowCallout(o, out); 0673 break; 0674 case msosptLeftRightArrowCallout: 0675 processLeftRightArrowCallout(o, out); 0676 break; 0677 case msosptUpDownArrowCallout: 0678 processUpDownArrowCallout(o, out); 0679 break; 0680 case msosptQuadArrowCallout: 0681 processQuadArrowCallout(o, out); 0682 break; 0683 case msosptBevel: 0684 processBevel(o, out); 0685 break; 0686 case msosptLeftBracket: 0687 processLeftBracket(o, out); 0688 break; 0689 case msosptRightBracket: 0690 processRightBracket(o, out); 0691 break; 0692 case msosptLeftBrace: 0693 processLeftBrace(o, out); 0694 break; 0695 case msosptRightBrace: 0696 processRightBrace(o, out); 0697 break; 0698 case msosptLeftUpArrow: 0699 processLeftUpArrow(o, out); 0700 break; 0701 case msosptBentUpArrow: 0702 processBentUpArrow(o, out); 0703 break; 0704 case msosptBentArrow: 0705 processBentArrow(o, out); 0706 break; 0707 case msosptSeal24: 0708 processSeal24(o, out); 0709 break; 0710 case msosptStripedRightArrow: 0711 processStripedRightArrow(o, out); 0712 break; 0713 case msosptNotchedRightArrow: 0714 processNotchedRightArrow(o, out); 0715 break; 0716 case msosptBlockArc: 0717 processBlockArc(o, out); 0718 break; 0719 case msosptSmileyFace: 0720 processSmileyFace(o, out); 0721 break; 0722 case msosptVerticalScroll: 0723 processVerticalScroll(o, out); 0724 break; 0725 case msosptHorizontalScroll: 0726 processHorizontalScroll(o, out); 0727 break; 0728 case msosptCircularArrow: 0729 processCircularArrow(o, out); 0730 break; 0731 case msosptNotchedCircularArrow: 0732 processNotchedCircularArrow(o, out); 0733 break; 0734 case msosptUturnArrow: 0735 processUturnArrow(o, out); 0736 break; 0737 case msosptCurvedRightArrow: 0738 processCurvedRightArrow(o, out); 0739 break; 0740 case msosptCurvedLeftArrow: 0741 processCurvedLeftArrow(o, out); 0742 break; 0743 case msosptCurvedUpArrow: 0744 processCurvedUpArrow(o, out); 0745 break; 0746 case msosptCurvedDownArrow: 0747 processCurvedDownArrow(o, out); 0748 break; 0749 case msosptCloudCallout: 0750 processCloudCallout(o, out); 0751 break; 0752 case msosptEllipseRibbon: 0753 processEllipseRibbon(o, out); 0754 break; 0755 case msosptEllipseRibbon2: 0756 processEllipseRibbon2(o, out); 0757 break; 0758 case msosptFlowChartProcess: 0759 processFlowChartProcess(o, out); 0760 break; 0761 case msosptFlowChartDecision: 0762 processFlowChartDecision(o, out); 0763 break; 0764 case msosptFlowChartInputOutput: 0765 processFlowChartInputOutput(o, out); 0766 break; 0767 case msosptFlowChartPredefinedProcess: 0768 processFlowChartPredefinedProcess(o, out); 0769 break; 0770 case msosptFlowChartInternalStorage: 0771 processFlowChartInternalStorage(o, out); 0772 break; 0773 case msosptFlowChartDocument: 0774 processFlowChartDocument(o, out); 0775 break; 0776 case msosptFlowChartMultidocument: 0777 processFlowChartMultidocument(o, out); 0778 break; 0779 case msosptFlowChartTerminator: 0780 processFlowChartTerminator(o, out); 0781 break; 0782 case msosptFlowChartPreparation: 0783 processFlowChartPreparation(o, out); 0784 break; 0785 case msosptFlowChartManualInput: 0786 processFlowChartManualInput(o, out); 0787 break; 0788 case msosptFlowChartManualOperation: 0789 processFlowChartManualOperation(o, out); 0790 break; 0791 case msosptFlowChartConnector: 0792 processFlowChartConnector(o, out); 0793 break; 0794 case msosptFlowChartPunchedCard: 0795 processFlowChartPunchedCard(o, out); 0796 break; 0797 case msosptFlowChartPunchedTape: 0798 processFlowChartPunchedTape(o, out); 0799 break; 0800 case msosptFlowChartSummingJunction: 0801 processFlowChartSummingJunction(o, out); 0802 break; 0803 case msosptFlowChartOr: 0804 processFlowChartOr(o, out); 0805 break; 0806 case msosptFlowChartCollate: 0807 processFlowChartCollate(o, out); 0808 break; 0809 case msosptFlowChartSort: 0810 processFlowChartSort(o, out); 0811 break; 0812 case msosptFlowChartExtract: 0813 processFlowChartExtract(o, out); 0814 break; 0815 case msosptFlowChartMerge: 0816 processFlowChartMerge(o, out); 0817 break; 0818 // 0819 // TODO: msosptFlowChartOfflineStorage 0820 // 0821 case msosptFlowChartOnlineStorage: 0822 processFlowChartOnlineStorage(o, out); 0823 break; 0824 case msosptFlowChartMagneticTape: 0825 processFlowChartMagneticTape(o, out); 0826 break; 0827 case msosptFlowChartMagneticDisk: 0828 processFlowChartMagneticDisk(o, out); 0829 break; 0830 case msosptFlowChartMagneticDrum: 0831 processFlowChartMagneticDrum(o, out); 0832 break; 0833 case msosptFlowChartDisplay: 0834 processFlowChartDisplay(o, out); 0835 break; 0836 case msosptFlowChartDelay: 0837 processFlowChartDelay(o, out); 0838 break; 0839 // 0840 // TODO: msosptTextPlainText, msosptTextStop, msosptTextTriangle, 0841 // msosptTextTriangleInverted, msosptTextChevron, 0842 // msosptTextChevronInverted, msosptTextRingInside, msosptTextRingOutside, 0843 // msosptTextArchUpCurve, msosptTextArchDownCurve, msosptTextCircleCurve, 0844 // msosptTextButtonCurve, msosptTextArchUpPour, msosptTextArchDownPour, 0845 // msosptTextCirclePour, msosptTextButtonPour, msosptTextCurveUp, 0846 // msosptTextCurveDown, msosptTextCascadeUp, msosptTextCascadeDown, 0847 // msosptTextWave1, msosptTextWave2, msosptTextWave3, msosptTextWave4, 0848 // msosptTextInflate, msosptTextDeflate, msosptTextInflateBottom, 0849 // msosptTextDeflateBottom, msosptTextInflateTop, msosptTextDeflateTop, 0850 // msosptTextDeflateInflate, msosptTextDeflateInflateDeflate, 0851 // msosptTextFadeRight, msosptTextFadeLeft, msosptTextFadeUp, 0852 // msosptTextFadeDown, msosptTextSlantUp, msosptTextSlantDown, 0853 // msosptTextCanUp, msosptTextCanDown 0854 // 0855 case msosptFlowChartAlternateProcess: 0856 processFlowChartAlternateProcess(o, out); 0857 break; 0858 case msosptFlowChartOffpageConnector: 0859 processFlowChartOffpageConnector(o, out); 0860 break; 0861 case msosptCallout90: 0862 processCallout90(o, out); 0863 break; 0864 case msosptAccentCallout90: 0865 processAccentCallout90(o, out); 0866 break; 0867 case msosptBorderCallout90: 0868 processBorderCallout90(o, out); 0869 break; 0870 case msosptAccentBorderCallout90: 0871 processAccentBorderCallout90(o, out); 0872 break; 0873 case msosptLeftRightUpArrow: 0874 processLeftRightUpArrow(o, out); 0875 break; 0876 case msosptSun: 0877 processSun(o, out); 0878 break; 0879 case msosptMoon: 0880 processMoon(o, out); 0881 break; 0882 case msosptBracketPair: 0883 processBracketPair(o, out); 0884 break; 0885 case msosptBracePair: 0886 processBracePair(o, out); 0887 break; 0888 case msosptSeal4: 0889 processSeal4(o, out); 0890 break; 0891 case msosptDoubleWave: 0892 processDoubleWave(o, out); 0893 break; 0894 case msosptActionButtonBlank: 0895 processActionButtonBlank(o, out); 0896 break; 0897 case msosptActionButtonHome: 0898 processActionButtonHome(o, out); 0899 break; 0900 case msosptActionButtonHelp: 0901 processActionButtonHelp(o, out); 0902 break; 0903 case msosptActionButtonInformation: 0904 processActionButtonInformation(o, out); 0905 break; 0906 case msosptActionButtonForwardNext: 0907 processActionButtonForwardNext(o, out); 0908 break; 0909 case msosptActionButtonBackPrevious: 0910 processActionButtonBackPrevious(o, out); 0911 break; 0912 case msosptActionButtonEnd: 0913 processActionButtonEnd(o, out); 0914 break; 0915 case msosptActionButtonBeginning: 0916 processActionButtonBeginning(o, out); 0917 break; 0918 case msosptActionButtonReturn: 0919 processActionButtonReturn(o, out); 0920 break; 0921 case msosptActionButtonDocument: 0922 processActionButtonDocument(o, out); 0923 break; 0924 case msosptActionButtonSound: 0925 processActionButtonSound(o, out); 0926 break; 0927 case msosptActionButtonMovie: 0928 processActionButtonMovie(o, out); 0929 break; 0930 case msosptHostControl: 0931 processPictureFrame(o, out); 0932 break; 0933 case msosptTextBox: 0934 processTextBox(o, out); 0935 break; 0936 default: 0937 qDebug() << "Cannot handle shape 0x" << hex << shapeType; 0938 break; 0939 } 0940 } 0941 0942 void ODrawToOdf::processStyleAndText(const MSO::OfficeArtSpContainer& o, 0943 Writer& out) 0944 { 0945 processStyle(o, out); 0946 processText(o, out); 0947 } 0948 0949 void ODrawToOdf::processStyle(const MSO::OfficeArtSpContainer& o, 0950 Writer& out) 0951 { 0952 addGraphicStyleToDrawElement(out, o); 0953 set2dGeometry(o, out); 0954 } 0955 0956 void ODrawToOdf::processText(const MSO::OfficeArtSpContainer& o, 0957 Writer& out) 0958 { 0959 if (!client) { 0960 qWarning() << "Warning: There's no Client!"; 0961 return; 0962 } 0963 0964 if (o.clientData && client->onlyClientData(*o.clientData)) { 0965 client->processClientData(o.clientTextbox.data(), *o.clientData, out); 0966 } else if (o.clientTextbox) { 0967 client->processClientTextBox(*o.clientTextbox, o.clientData.data(), out); 0968 } 0969 } 0970 0971 void ODrawToOdf::processModifiers(const MSO::OfficeArtSpContainer &o, Writer &out, const QList<int>& defaults) 0972 { 0973 const AdjustValue* val1 = get<AdjustValue>(o); 0974 if (!val1 && defaults.isEmpty()) return; 0975 const Adjust2Value* val2 = get<Adjust2Value>(o); 0976 const Adjust3Value* val3 = get<Adjust3Value>(o); 0977 const Adjust4Value* val4 = get<Adjust4Value>(o); 0978 const Adjust5Value* val5 = get<Adjust5Value>(o); 0979 const Adjust6Value* val6 = get<Adjust6Value>(o); 0980 const Adjust7Value* val7 = get<Adjust7Value>(o); 0981 const Adjust8Value* val8 = get<Adjust8Value>(o); 0982 0983 QString modifiers = QString::number(val1 ? val1->adjustvalue : defaults[0]); 0984 if (val2 || defaults.size() > 1) { 0985 modifiers += QString(" %1").arg(val2 ? val2->adjust2value : defaults[1]); 0986 if (val3 || defaults.size() > 2) { 0987 modifiers += QString(" %1").arg(val3 ? val3->adjust3value : defaults[2]); 0988 if (val4 || defaults.size() > 3) { 0989 modifiers += QString(" %1").arg(val4 ? val4->adjust4value : defaults[3]); 0990 if (val5 || defaults.size() > 4) { 0991 modifiers += QString(" %1").arg(val5 ? val5->adjust5value : defaults[4]); 0992 if (val6 || defaults.size() > 5) { 0993 modifiers += QString(" %1").arg(val6 ? val6->adjust6value : defaults[5]); 0994 if (val7 || defaults.size() > 6) { 0995 modifiers += QString(" %1").arg(val7 ? val7->adjust7value : defaults[6]); 0996 if (val8 || defaults.size() > 7) { 0997 modifiers += QString(" %1").arg(val8 ? val8->adjust8value : defaults[7]); 0998 } 0999 } 1000 } 1001 } 1002 } 1003 } 1004 } 1005 1006 out.xml.addAttribute("draw:modifiers", modifiers); 1007 } 1008 1009 // Position the shape into the slide or into a group shape 1010 void ODrawToOdf::set2dGeometry(const OfficeArtSpContainer& o, Writer& out) 1011 { 1012 const OfficeArtDggContainer* dgg = 0; 1013 const OfficeArtSpContainer* master = 0; 1014 const DrawStyle ds(dgg, master, &o); 1015 const qreal rotation = toQReal(ds.rotation()); 1016 1017 //transform the rectangle into the coordinate system of the group shape 1018 QRectF rect = getRect(o); 1019 QRectF trect (out.hOffset(rect.x()), out.vOffset(rect.y()), 1020 out.hLength(rect.width()), out.vLength(rect.height())); 1021 1022 //draw:caption-id 1023 //draw:class-names 1024 //draw:data 1025 //draw:engine 1026 //draw:layer 1027 out.xml.addAttribute("draw:layer", "layout"); 1028 //draw:name 1029 //draw:style-name 1030 //draw:text-style-name 1031 //draw:transform 1032 if (rotation) { 1033 1034 const quint16 shapeType = o.shapeProp.rh.recInstance; 1035 const quint16 nrotation = normalizeRotation(rotation); 1036 const qreal angle = (nrotation / (qreal)180) * M_PI; 1037 1038 trect = processRect(shapeType, rotation, trect); 1039 1040 static const QString transform_str("translate(%1 %2) rotate(%3) translate(%4 %5)"); 1041 const QPointF center = trect.center(); 1042 const qreal height = trect.height(); 1043 const qreal width = trect.width(); 1044 1045 out.xml.addAttribute("draw:transform", 1046 transform_str.arg(client->formatPos(-width/2)).arg(client->formatPos(-height/2)).arg(-angle).arg(client->formatPos(center.x())).arg(client->formatPos(center.y()))); 1047 } 1048 //svg:x 1049 //svg:y 1050 else { 1051 out.xml.addAttribute("svg:x", client->formatPos(trect.x())); 1052 out.xml.addAttribute("svg:y", client->formatPos(trect.y())); 1053 } 1054 //NOTE: z-index is set in ODrawToOdf::Client::addTextStyles 1055 //draw:z-index 1056 //presentation:class-names 1057 //presentation:style-name 1058 //svg:height 1059 out.xml.addAttribute("svg:height", client->formatPos(trect.height())); 1060 //svg:width 1061 out.xml.addAttribute("svg:width", client->formatPos(trect.width())); 1062 //table:end-cell-address 1063 //table:end-x 1064 //table:end-y 1065 //table:table-background 1066 //text:anchor-page-number 1067 //text:anchor-type 1068 //xml:id 1069 } 1070 1071 void ODrawToOdf::setEnhancedGeometry(const MSO::OfficeArtSpContainer& o, Writer& out) 1072 { 1073 const OfficeArtDggContainer* drawingGroup = 0; 1074 const OfficeArtSpContainer* master = 0; 1075 const DrawStyle ds(drawingGroup, master, &o); 1076 1077 IMsoArray _v = ds.pVertices_complex(); 1078 IMsoArray segmentInfo = ds.pSegmentInfo_complex(); 1079 1080 if (!_v.data.isEmpty() && !segmentInfo.data.isEmpty()) { 1081 1082 QVector<QPoint> verticesPoints; 1083 1084 //_v.data is an array of POINTs, MS-ODRAW, page 89 1085 QByteArray xArray(sizeof(int), 0), yArray(sizeof(int), 0); 1086 int step = _v.cbElem; 1087 if (step == 0xfff0) { 1088 step = 4; 1089 } 1090 1091 int maxX = 0, minX = INT_MAX, maxY = 0, minY = INT_MAX; 1092 int x,y; 1093 1094 //get vertice points 1095 for (int i = 0, offset = 0; i < _v.nElems; i++, offset += step) { 1096 // x coordinate of this point 1097 xArray.replace(0, step/2, _v.data.mid(offset, step/2)); 1098 x = *(int*) xArray.data(); 1099 1100 // y coordinate of this point 1101 yArray.replace(0, step/2, _v.data.mid(offset + step/2, step/2)); 1102 y = *(int*) yArray.data(); 1103 1104 verticesPoints.append(QPoint(x, y)); 1105 1106 // find maximum and minimum coordinates 1107 if (maxY < y) { 1108 maxY = y; 1109 } 1110 if (minY > y) { 1111 minY = y ; 1112 } 1113 if (maxX < x) { 1114 maxX = x; 1115 } 1116 if (minX > x) { 1117 minX = x; 1118 } 1119 } 1120 1121 //TODO: geoLeft, geoTop, geoRight, geoBottom 1122 QString viewBox = QString::number(minX) + ' ' + QString::number(minY) + ' ' + 1123 QString::number(maxX) + ' ' + QString::number(maxY); 1124 1125 // combine segmentationInfoData and verticePoints into enhanced-path string 1126 QString enhancedPath; 1127 ushort msopathtype; 1128 bool nOffRange = false; 1129 1130 for (int i = 0, n = 0; ((i < segmentInfo.nElems) && !nOffRange); i++) { 1131 1132 msopathtype = (((*(ushort *)(segmentInfo.data.data() + i * 2)) >> 13) & 0x7); 1133 1134 switch (msopathtype) { 1135 case msopathLineTo: 1136 { 1137 if (n >= verticesPoints.size()) { 1138 qDebug() << "EnhancedGeometry: index into verticesPoints out of range!"; 1139 nOffRange = true; 1140 break; 1141 } 1142 enhancedPath = enhancedPath + "L " + QString::number(verticesPoints[n].x()) + ' ' + 1143 QString::number(verticesPoints[n].y()) + ' '; 1144 n++; 1145 break; 1146 } 1147 case msopathCurveTo: 1148 { 1149 if (n + 2 >= verticesPoints.size()) { 1150 qDebug() << "EnhancedGeometry: index into verticesPoints out of range!"; 1151 nOffRange = true; 1152 break; 1153 } 1154 QPoint pt1 = verticesPoints.at(n); 1155 QPoint pt2 = verticesPoints.at(n + 1); 1156 QPoint pt3 = verticesPoints.at(n + 2); 1157 1158 enhancedPath = enhancedPath + "C " + 1159 QString::number(pt1.x()) + ' ' + 1160 QString::number(pt1.y()) + ' ' + 1161 QString::number(pt2.x()) + ' ' + 1162 QString::number(pt2.y()) + ' ' + 1163 QString::number(pt3.x()) + ' ' + 1164 QString::number(pt3.y()) + ' '; 1165 n = n + 3; 1166 break; 1167 } 1168 case msopathMoveTo: 1169 { 1170 if (n >= verticesPoints.size()) { 1171 qDebug() << "EnhancedGeometry: index into verticesPoints out of range!"; 1172 nOffRange = true; 1173 break; 1174 } 1175 enhancedPath = enhancedPath + "M " + QString::number(verticesPoints[n].x()) + ' ' + 1176 QString::number(verticesPoints[n].y()) + ' '; 1177 n++; 1178 break; 1179 } 1180 case msopathClose: 1181 enhancedPath = enhancedPath + "Z "; 1182 break; 1183 case msopathEnd: 1184 enhancedPath = enhancedPath + "N "; 1185 break; 1186 case msopathEscape: 1187 case msopathClientEscape: 1188 break; 1189 } 1190 } 1191 //dr3d:projection 1192 //dr3d:shade-mode 1193 //draw:concentric-gradient-fill-allowed 1194 //draw:enhanced-path 1195 out.xml.addAttribute("draw:enhanced-path", enhancedPath); 1196 //draw:extrusion 1197 //draw:extrusion-allowed 1198 //draw:extrusion-brightness 1199 //draw:extrusion-color 1200 //draw:extrusion-depth 1201 //draw:extrusion-diffusion 1202 //draw:extrusion-first-light-direction 1203 //draw:extrusion-first-light-harsh 1204 //draw:extrusion-first-light-level 1205 //draw:extrusion-light-face 1206 //draw:extrusion-metal 1207 //draw:extrusion-number-of-line-segments 1208 //draw:extrusion-origin 1209 //draw:extrusion-rotation-angle 1210 //draw:extrusion-rotation-center 1211 //draw:extrusion-second-light-direction 1212 //draw:extrusion-second-light-harsh 1213 //draw:extrusion-second-light-level 1214 //draw:extrusion-shininess 1215 //draw:extrusion-skew 1216 //draw:extrusion-specularity 1217 //draw:extrusion-viewpoint 1218 //draw:glue-point-leaving-directions 1219 //draw:glue-points 1220 //draw:glue-point-type 1221 //draw:mirror-horizontal 1222 if (o.shapeProp.fFlipH) { 1223 out.xml.addAttribute("draw:mirror-horizontal", "true"); 1224 } 1225 //draw:mirror-vertical 1226 if (o.shapeProp.fFlipV) { 1227 out.xml.addAttribute("draw:mirror-vertical", "true"); 1228 } 1229 //draw:modifiers 1230 //draw:path-stretchpoint-x 1231 //draw:path-stretchpoint-y 1232 //draw:text-areas 1233 //draw:text-path 1234 //draw:text-path-allowed 1235 //draw:text-path-mode 1236 //draw:text-path-same-letter-heights 1237 //draw:text-path-scale 1238 //draw:text-rotate-angle 1239 //draw:type 1240 out.xml.addAttribute("draw:type", "non-primitive"); 1241 //svg:viewBox 1242 out.xml.addAttribute("svg:viewBox", viewBox); 1243 } 1244 } 1245 1246 QString ODrawToOdf::path2svg(const QPainterPath &path) 1247 { 1248 QString d; 1249 1250 int count = path.elementCount(); 1251 for (int i = 0; i < count; i++) { 1252 1253 QPainterPath::Element e = path.elementAt(i); 1254 switch(e.type) { 1255 case QPainterPath::MoveToElement: 1256 d.append(QString("M %1 %2").arg(e.x).arg(e.y)); 1257 break; 1258 case QPainterPath::LineToElement: 1259 d.append(QString("L %1 %2").arg(e.x).arg(e.y)); 1260 break; 1261 case QPainterPath::CurveToElement: 1262 d.append(QString("C %1 %2").arg(e.x).arg(e.y)); 1263 break; 1264 case QPainterPath::CurveToDataElement: 1265 d.append(QString(" %1 %2").arg(e.x).arg(e.y)); 1266 break; 1267 default: 1268 qWarning() << "This element unhandled: " << e.type; 1269 } 1270 } 1271 return d; 1272 } 1273 1274 void ODrawToOdf::setShapeMirroring(const MSO::OfficeArtSpContainer& o, Writer& out) 1275 { 1276 if (o.shapeProp.fFlipV) { 1277 out.xml.addAttribute("draw:mirror-vertical", "true"); 1278 } 1279 if (o.shapeProp.fFlipH) { 1280 out.xml.addAttribute("draw:mirror-horizontal", "true"); 1281 } 1282 }