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