Warning, file /office/calligra/libs/odf/KoOdfGraphicStyles.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 Copyright (C) 2004-2006 David Faure <faure@kde.org> 0003 Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net> 0004 Copyright (C) 2007-2008,2010-2011 Thorsten Zachmann <zachmann@kde.org> 0005 Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com> 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Library General Public 0009 License as published by the Free Software Foundation; either 0010 version 2 of the License, or (at your option) any later version. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Library General Public License for more details. 0016 0017 You should have received a copy of the GNU Library General Public License 0018 along with this library; see the file COPYING.LIB. If not, write to 0019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "KoOdfGraphicStyles.h" 0024 0025 #include <QBrush> 0026 #include <QBuffer> 0027 #include <QPen> 0028 0029 #include <OdfDebug.h> 0030 0031 #include <KoGenStyles.h> 0032 #include <KoStyleStack.h> 0033 #include <KoUnit.h> 0034 #include <KoXmlNS.h> 0035 #include <KoXmlWriter.h> 0036 0037 #include "KoOdfStylesReader.h" 0038 0039 void KoOdfGraphicStyles::saveOdfFillStyle(KoGenStyle &styleFill, KoGenStyles& mainStyles, const QBrush & brush) 0040 { 0041 KoGenStyle::Type type = styleFill.type(); 0042 KoGenStyle::PropertyType propertyType = (type == KoGenStyle::GraphicStyle || type == KoGenStyle::GraphicAutoStyle || 0043 type == KoGenStyle::DrawingPageStyle || type == KoGenStyle::DrawingPageAutoStyle ) 0044 ? KoGenStyle::DefaultType : KoGenStyle::GraphicType; 0045 switch (brush.style()) { 0046 case Qt::Dense1Pattern: 0047 styleFill.addProperty("draw:opacity", "6%", propertyType); 0048 styleFill.addProperty("draw:fill", "solid", propertyType); 0049 styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType); 0050 break; 0051 case Qt::Dense2Pattern: 0052 styleFill.addProperty("draw:opacity", "12%", propertyType); 0053 styleFill.addProperty("draw:fill", "solid", propertyType); 0054 styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType); 0055 break; 0056 case Qt::Dense3Pattern: 0057 styleFill.addProperty("draw:opacity", "37%", propertyType); 0058 styleFill.addProperty("draw:fill", "solid", propertyType); 0059 styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType); 0060 break; 0061 case Qt::Dense4Pattern: 0062 styleFill.addProperty("draw:opacity", "50%", propertyType); 0063 styleFill.addProperty("draw:fill", "solid", propertyType); 0064 styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType); 0065 break; 0066 case Qt::Dense5Pattern: 0067 styleFill.addProperty("draw:opacity", "63%", propertyType); 0068 styleFill.addProperty("draw:fill", "solid", propertyType); 0069 styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType); 0070 break; 0071 case Qt::Dense6Pattern: 0072 styleFill.addProperty("draw:opacity", "88%", propertyType); 0073 styleFill.addProperty("draw:fill", "solid", propertyType); 0074 styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType); 0075 break; 0076 case Qt::Dense7Pattern: 0077 styleFill.addProperty("draw:opacity", "94%", propertyType); 0078 styleFill.addProperty("draw:fill", "solid", propertyType); 0079 styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType); 0080 break; 0081 case Qt::LinearGradientPattern: 0082 case Qt::RadialGradientPattern: 0083 case Qt::ConicalGradientPattern: 0084 styleFill.addProperty("draw:fill", "gradient", propertyType); 0085 styleFill.addProperty("draw:fill-gradient-name", saveOdfGradientStyle(mainStyles, brush), propertyType); 0086 break; 0087 case Qt::HorPattern: 0088 case Qt::VerPattern: 0089 case Qt::CrossPattern: 0090 case Qt::BDiagPattern: 0091 case Qt::FDiagPattern: 0092 case Qt::DiagCrossPattern: 0093 styleFill.addProperty("draw:fill", "hatch", propertyType); 0094 styleFill.addProperty("draw:fill-hatch-name", saveOdfHatchStyle(mainStyles, brush), propertyType); 0095 break; 0096 case Qt::SolidPattern: 0097 styleFill.addProperty("draw:fill", "solid", propertyType); 0098 styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType); 0099 if (! brush.isOpaque()) 0100 styleFill.addProperty("draw:opacity", QString("%1%").arg(brush.color().alphaF() * 100.0), propertyType); 0101 break; 0102 case Qt::NoBrush: 0103 default: 0104 styleFill.addProperty("draw:fill", "none", propertyType); 0105 break; 0106 } 0107 } 0108 0109 void KoOdfGraphicStyles::saveOdfStrokeStyle(KoGenStyle &styleStroke, KoGenStyles &mainStyles, const QPen &pen) 0110 { 0111 // TODO implement all possibilities 0112 switch (pen.style()) { 0113 case Qt::NoPen: 0114 styleStroke.addProperty("draw:stroke", "none", KoGenStyle::GraphicType); 0115 return; 0116 case Qt::SolidLine: 0117 styleStroke.addProperty("draw:stroke", "solid", KoGenStyle::GraphicType); 0118 break; 0119 default: { // must be a dashed line 0120 styleStroke.addProperty("draw:stroke", "dash", KoGenStyle::GraphicType); 0121 // save stroke dash (14.14.7) which is severely limited, but still 0122 KoGenStyle dashStyle(KoGenStyle::StrokeDashStyle); 0123 dashStyle.addAttribute("draw:style", "rect"); 0124 QVector<qreal> dashes = pen.dashPattern(); 0125 dashStyle.addAttribute("draw:dots1", static_cast<int>(1)); 0126 dashStyle.addAttributePt("draw:dots1-length", dashes[0]*pen.widthF()); 0127 dashStyle.addAttributePt("draw:distance", dashes[1]*pen.widthF()); 0128 if (dashes.size() > 2) { 0129 dashStyle.addAttribute("draw:dots2", static_cast<int>(1)); 0130 dashStyle.addAttributePt("draw:dots2-length", dashes[2]*pen.widthF()); 0131 } 0132 QString dashStyleName = mainStyles.insert(dashStyle, "dash"); 0133 styleStroke.addProperty("draw:stroke-dash", dashStyleName, KoGenStyle::GraphicType); 0134 break; 0135 } 0136 } 0137 0138 if (pen.brush().gradient()) { 0139 styleStroke.addProperty("calligra:stroke-gradient", saveOdfGradientStyle(mainStyles, pen.brush()), KoGenStyle::GraphicType); 0140 } 0141 else { 0142 styleStroke.addProperty("svg:stroke-color", pen.color().name(), KoGenStyle::GraphicType); 0143 styleStroke.addProperty("svg:stroke-opacity", QString("%1").arg(pen.color().alphaF()), KoGenStyle::GraphicType); 0144 } 0145 styleStroke.addPropertyPt("svg:stroke-width", pen.widthF(), KoGenStyle::GraphicType); 0146 0147 switch (pen.joinStyle()) { 0148 case Qt::MiterJoin: 0149 styleStroke.addProperty("draw:stroke-linejoin", "miter", KoGenStyle::GraphicType); 0150 break; 0151 case Qt::BevelJoin: 0152 styleStroke.addProperty("draw:stroke-linejoin", "bevel", KoGenStyle::GraphicType); 0153 break; 0154 case Qt::RoundJoin: 0155 styleStroke.addProperty("draw:stroke-linejoin", "round", KoGenStyle::GraphicType); 0156 break; 0157 default: 0158 styleStroke.addProperty("draw:stroke-linejoin", "miter", KoGenStyle::GraphicType); 0159 styleStroke.addProperty("calligra:stroke-miterlimit", QString("%1").arg(pen.miterLimit()), KoGenStyle::GraphicType); 0160 break; 0161 } 0162 switch (pen.capStyle()) { 0163 case Qt::RoundCap: 0164 styleStroke.addProperty("svg:stroke-linecap", "round", KoGenStyle::GraphicType); 0165 break; 0166 case Qt::SquareCap: 0167 styleStroke.addProperty("svg:stroke-linecap", "square", KoGenStyle::GraphicType); 0168 break; 0169 default: 0170 styleStroke.addProperty("svg:stroke-linecap", "butt", KoGenStyle::GraphicType); 0171 break; 0172 } 0173 } 0174 0175 QString KoOdfGraphicStyles::saveOdfHatchStyle(KoGenStyles& mainStyles, const QBrush &brush) 0176 { 0177 KoGenStyle hatchStyle(KoGenStyle::HatchStyle /*no family name*/); 0178 hatchStyle.addAttribute("draw:color", brush.color().name()); 0179 //hatchStyle.addAttribute( "draw:distance", m_distance ); not implemented into Stage 0180 switch (brush.style()) { 0181 case Qt::HorPattern: 0182 hatchStyle.addAttribute("draw:style", "single"); 0183 hatchStyle.addAttribute("draw:rotation", 0); 0184 break; 0185 case Qt::BDiagPattern: 0186 hatchStyle.addAttribute("draw:style", "single"); 0187 hatchStyle.addAttribute("draw:rotation", 450); 0188 break; 0189 case Qt::VerPattern: 0190 hatchStyle.addAttribute("draw:style", "single"); 0191 hatchStyle.addAttribute("draw:rotation", 900); 0192 break; 0193 case Qt::FDiagPattern: 0194 hatchStyle.addAttribute("draw:style", "single"); 0195 hatchStyle.addAttribute("draw:rotation", 1350); 0196 break; 0197 case Qt::CrossPattern: 0198 hatchStyle.addAttribute("draw:style", "double"); 0199 hatchStyle.addAttribute("draw:rotation", 0); 0200 break; 0201 case Qt::DiagCrossPattern: 0202 hatchStyle.addAttribute("draw:style", "double"); 0203 hatchStyle.addAttribute("draw:rotation", 450); 0204 break; 0205 default: 0206 break; 0207 } 0208 0209 return mainStyles.insert(hatchStyle, "hatch"); 0210 } 0211 0212 QString KoOdfGraphicStyles::saveOdfGradientStyle(KoGenStyles &mainStyles, const QBrush &brush) 0213 { 0214 KoGenStyle gradientStyle; 0215 if (brush.style() == Qt::RadialGradientPattern) { 0216 const QRadialGradient *gradient = static_cast<const QRadialGradient*>(brush.gradient()); 0217 gradientStyle = KoGenStyle(KoGenStyle::RadialGradientStyle /*no family name*/); 0218 gradientStyle.addAttributePercent("svg:cx", gradient->center().x() * 100); 0219 gradientStyle.addAttributePercent("svg:cy", gradient->center().y() * 100); 0220 gradientStyle.addAttributePercent("svg:r", gradient->radius() * 100); 0221 gradientStyle.addAttributePercent("svg:fx", gradient->focalPoint().x() * 100); 0222 gradientStyle.addAttributePercent("svg:fy", gradient->focalPoint().y() * 100); 0223 } else if (brush.style() == Qt::LinearGradientPattern) { 0224 const QLinearGradient *gradient = static_cast<const QLinearGradient*>(brush.gradient()); 0225 gradientStyle = KoGenStyle(KoGenStyle::LinearGradientStyle /*no family name*/); 0226 gradientStyle.addAttributePercent("svg:x1", gradient->start().x() * 100); 0227 gradientStyle.addAttributePercent("svg:y1", gradient->start().y() * 100); 0228 gradientStyle.addAttributePercent("svg:x2", gradient->finalStop().x() * 100); 0229 gradientStyle.addAttributePercent("svg:y2", gradient->finalStop().y() * 100); 0230 } else if (brush.style() == Qt::ConicalGradientPattern) { 0231 const QConicalGradient * gradient = static_cast<const QConicalGradient*>(brush.gradient()); 0232 gradientStyle = KoGenStyle(KoGenStyle::ConicalGradientStyle /*no family name*/); 0233 gradientStyle.addAttributePercent("svg:cx", gradient->center().x() * 100); 0234 gradientStyle.addAttributePercent("svg:cy", gradient->center().y() * 100); 0235 gradientStyle.addAttribute("draw:angle", QString("%1").arg(gradient->angle())); 0236 } 0237 const QGradient * gradient = brush.gradient(); 0238 if (gradient->spread() == QGradient::RepeatSpread) 0239 gradientStyle.addAttribute("svg:spreadMethod", "repeat"); 0240 else if (gradient->spread() == QGradient::ReflectSpread) 0241 gradientStyle.addAttribute("svg:spreadMethod", "reflect"); 0242 else 0243 gradientStyle.addAttribute("svg:spreadMethod", "pad"); 0244 0245 if (! brush.transform().isIdentity()) { 0246 gradientStyle.addAttribute("svg:gradientTransform", saveTransformation(brush.transform())); 0247 } 0248 0249 QBuffer buffer; 0250 buffer.open(QIODevice::WriteOnly); 0251 KoXmlWriter elementWriter(&buffer); // TODO pass indentation level 0252 0253 // save stops 0254 QGradientStops stops = gradient->stops(); 0255 foreach(const QGradientStop & stop, stops) { 0256 elementWriter.startElement("svg:stop"); 0257 elementWriter.addAttribute("svg:offset", QString("%1").arg(stop.first)); 0258 elementWriter.addAttribute("svg:stop-color", stop.second.name()); 0259 if (stop.second.alphaF() < 1.0) 0260 elementWriter.addAttribute("svg:stop-opacity", QString("%1").arg(stop.second.alphaF())); 0261 elementWriter.endElement(); 0262 } 0263 0264 QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size()); 0265 gradientStyle.addChildElement("svg:stop", elementContents); 0266 0267 return mainStyles.insert(gradientStyle, "gradient"); 0268 } 0269 0270 QBrush KoOdfGraphicStyles::loadOdfGradientStyle(const KoStyleStack &styleStack, const KoOdfStylesReader & stylesReader, const QSizeF &size) 0271 { 0272 QString styleName = styleStack.property(KoXmlNS::draw, "fill-gradient-name"); 0273 return loadOdfGradientStyleByName(stylesReader, styleName, size); 0274 } 0275 0276 qreal percent(const KoXmlElement &element, const QString &ns, const QString &type, const QString &defaultValue, qreal absolute) 0277 { 0278 qreal tmp = 0.0; 0279 QString value = element.attributeNS(ns, type, defaultValue); 0280 if (value.indexOf('%') > -1) { // percent value 0281 tmp = value.remove('%').toDouble() / 100.0; 0282 } 0283 else { // fixed value 0284 tmp = KoUnit::parseValue(value) / absolute; 0285 // The following is done so that we get the same data as when we save/load. 0286 // This is needed that we get the same values due to rounding differences 0287 // of absolute and relative values. 0288 QString value = QString("%1").arg(tmp * 100.0); 0289 tmp = value.toDouble() / 100; 0290 } 0291 0292 return tmp; 0293 } 0294 0295 QBrush KoOdfGraphicStyles::loadOdfGradientStyleByName(const KoOdfStylesReader &stylesReader, const QString &styleName, const QSizeF &size) 0296 { 0297 KoXmlElement* e = stylesReader.drawStyles("gradient").value(styleName); 0298 if (! e) 0299 return QBrush(); 0300 0301 QGradient * gradient = 0; 0302 QTransform transform; 0303 0304 if (e->namespaceURI() == KoXmlNS::draw && e->localName() == "gradient") { 0305 // FIXME seems like oo renders the gradient start stop color at the center of the 0306 // radial gradient, and the start color at the radius of the radial gradient 0307 // whereas it is not mentioned in the spec how it should be rendered 0308 // note that svg defines that exactly as the opposite as oo does 0309 // so what should we do? 0310 QString type = e->attributeNS(KoXmlNS::draw, "style", QString()); 0311 if (type == "radial") { 0312 // Zagge: at the moment the only objectBoundingBox is supported: 0313 // 18.539 svg:gradientUnits 0314 // See §13.2.2 and §13.2.3 of [SVG]. 0315 // The default value for this attribute is objectBoundingBox. 0316 // The only value of the svg:gradientUnits attribute is objectBoundingBox. 0317 0318 qreal cx = KoUnit::parseValue(e->attributeNS(KoXmlNS::draw, "cx", QString()).remove('%')); 0319 qreal cy = KoUnit::parseValue(e->attributeNS(KoXmlNS::draw, "cy", QString()).remove('%')); 0320 gradient = new QRadialGradient(QPointF(cx * 0.01, cy * 0.01), sqrt(0.5)); 0321 gradient->setCoordinateMode(QGradient::ObjectBoundingMode); 0322 } else if (type == "linear" || type == "axial") { 0323 QLinearGradient * lg = new QLinearGradient(); 0324 lg->setCoordinateMode(QGradient::ObjectBoundingMode); 0325 // Dividing by 10 here because OOo saves as degree * 10 0326 qreal angle = 90 + e->attributeNS(KoXmlNS::draw, "angle", "0").toDouble() / 10; 0327 qreal radius = sqrt(0.5); 0328 0329 qreal sx = cos(angle * M_PI / 180) * radius; 0330 qreal sy = sin(angle * M_PI / 180) * radius; 0331 lg->setStart(QPointF(0.5 + sx, 0.5 - sy)); 0332 lg->setFinalStop(QPointF(0.5 - sx, 0.5 + sy)); 0333 gradient = lg; 0334 } else 0335 return QBrush(); 0336 0337 qreal border = 0.01 * e->attributeNS(KoXmlNS::draw, "border", "0").remove('%').toDouble(); 0338 QGradientStops stops; 0339 if (type != "axial") { 0340 // In case of radial gradients the colors are reversed, because OOo saves them as the opposite of the SVG direction 0341 // see bug 137639 0342 QGradientStop start; 0343 start.first = (type != "radial") ? border : 1.0 - border; 0344 start.second = QColor(e->attributeNS(KoXmlNS::draw, "start-color", QString())); 0345 start.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "start-intensity", "100").remove('%').toDouble()); 0346 0347 QGradientStop end; 0348 end.first = (type != "radial") ? 1.0 : 0.0; 0349 end.second = QColor(e->attributeNS(KoXmlNS::draw, "end-color", QString())); 0350 end.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "end-intensity", "100").remove('%').toDouble()); 0351 0352 stops << start << end; 0353 } else { 0354 QGradientStop start; 0355 start.first = 0.5 * border; 0356 start.second = QColor(e->attributeNS(KoXmlNS::draw, "end-color", QString())); 0357 start.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "end-intensity", "100").remove('%').toDouble()); 0358 0359 QGradientStop middle; 0360 middle.first = 0.5; 0361 middle.second = QColor(e->attributeNS(KoXmlNS::draw, "start-color", QString())); 0362 middle.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "start-intensity", "100").remove('%').toDouble()); 0363 0364 QGradientStop end; 0365 end.first = 1.0 - 0.5 * border; 0366 end.second = QColor(e->attributeNS(KoXmlNS::draw, "end-color", QString())); 0367 end.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "end-intensity", "100").remove('%').toDouble()); 0368 0369 stops << start << middle << end; 0370 } 0371 0372 gradient->setStops(stops); 0373 } else if (e->namespaceURI() == KoXmlNS::svg) { 0374 if (e->localName() == "linearGradient") { 0375 QPointF start, stop; 0376 start.setX(percent(*e, KoXmlNS::svg, "x1", "0%", size.width())); 0377 start.setY(percent(*e, KoXmlNS::svg, "y1", "0%", size.height())); 0378 stop.setX(percent(*e, KoXmlNS::svg, "x2", "100%", size.width())); 0379 stop.setY(percent(*e, KoXmlNS::svg, "y2", "100%", size.height())); 0380 gradient = new QLinearGradient(start, stop); 0381 } else if (e->localName() == "radialGradient") { 0382 QPointF center, focalPoint; 0383 center.setX(percent(*e, KoXmlNS::svg, "cx", "50%", size.width())); 0384 center.setY(percent(*e, KoXmlNS::svg, "cy", "50%", size.height())); 0385 qreal r = percent(*e, KoXmlNS::svg, "r", "50%", sqrt(size.width() * size.width() + size.height() * size.height())); 0386 focalPoint.setX(percent(*e, KoXmlNS::svg, "fx", QString(), size.width())); 0387 focalPoint.setY(percent(*e, KoXmlNS::svg, "fy", QString(), size.height())); 0388 gradient = new QRadialGradient(center, r, focalPoint ); 0389 } 0390 if (! gradient) 0391 return QBrush(); 0392 0393 gradient->setCoordinateMode(QGradient::ObjectBoundingMode); 0394 0395 QString strSpread(e->attributeNS(KoXmlNS::svg, "spreadMethod", "pad")); 0396 if (strSpread == "repeat") 0397 gradient->setSpread(QGradient::RepeatSpread); 0398 else if (strSpread == "reflect") 0399 gradient->setSpread(QGradient::ReflectSpread); 0400 else 0401 gradient->setSpread(QGradient::PadSpread); 0402 0403 if (e->hasAttributeNS(KoXmlNS::svg, "gradientTransform")) 0404 transform = loadTransformation(e->attributeNS(KoXmlNS::svg, "gradientTransform", QString())); 0405 0406 QGradientStops stops; 0407 0408 // load stops 0409 KoXmlElement colorstop; 0410 forEachElement(colorstop, (*e)) { 0411 if (colorstop.namespaceURI() == KoXmlNS::svg && colorstop.localName() == "stop") { 0412 QGradientStop stop; 0413 stop.second = QColor(colorstop.attributeNS(KoXmlNS::svg, "stop-color", QString())); 0414 stop.second.setAlphaF(colorstop.attributeNS(KoXmlNS::svg, "stop-opacity", "1.0").toDouble()); 0415 stop.first = colorstop.attributeNS(KoXmlNS::svg, "offset", "0.0").toDouble(); 0416 stops.append(stop); 0417 } 0418 } 0419 gradient->setStops(stops); 0420 } else if (e->namespaceURI() == KoXmlNS::calligra) { 0421 if (e->localName() == "conicalGradient") { 0422 QPointF center; 0423 center.setX(percent(*e, KoXmlNS::svg, "cx", "50%", size.width())); 0424 center.setY(percent(*e, KoXmlNS::svg, "cy", "50%", size.height())); 0425 qreal angle = KoUnit::parseValue(e->attributeNS(KoXmlNS::draw, "angle", QString())); 0426 gradient = new QConicalGradient(center, angle); 0427 gradient->setCoordinateMode(QGradient::ObjectBoundingMode); 0428 0429 QString strSpread(e->attributeNS(KoXmlNS::svg, "spreadMethod", "pad")); 0430 if (strSpread == "repeat") 0431 gradient->setSpread(QGradient::RepeatSpread); 0432 else if (strSpread == "reflect") 0433 gradient->setSpread(QGradient::ReflectSpread); 0434 else 0435 gradient->setSpread(QGradient::PadSpread); 0436 0437 if (e->hasAttributeNS(KoXmlNS::svg, "gradientTransform")) 0438 transform = loadTransformation(e->attributeNS(KoXmlNS::svg, "gradientTransform", QString())); 0439 0440 QGradientStops stops; 0441 0442 // load stops 0443 KoXmlElement colorstop; 0444 forEachElement(colorstop, (*e)) { 0445 if (colorstop.namespaceURI() == KoXmlNS::svg && colorstop.localName() == "stop") { 0446 QGradientStop stop; 0447 stop.second = QColor(colorstop.attributeNS(KoXmlNS::svg, "stop-color", QString())); 0448 stop.second.setAlphaF(colorstop.attributeNS(KoXmlNS::svg, "stop-opacity", "1.0").toDouble()); 0449 stop.first = colorstop.attributeNS(KoXmlNS::svg, "offset", "0.0").toDouble(); 0450 stops.append(stop); 0451 } 0452 } 0453 gradient->setStops(stops); 0454 } 0455 } 0456 0457 if (! gradient) 0458 return QBrush(); 0459 0460 QBrush resultBrush(*gradient); 0461 resultBrush.setTransform(transform); 0462 0463 delete gradient; 0464 return resultBrush; 0465 } 0466 0467 QBrush KoOdfGraphicStyles::loadOdfFillStyle(const KoStyleStack &styleStack, const QString & fill, const KoOdfStylesReader & stylesReader) 0468 { 0469 QBrush tmpBrush; // default brush for "none" is a Qt::NoBrush 0470 0471 if (fill == "solid") { 0472 tmpBrush.setStyle(Qt::SolidPattern); 0473 if (styleStack.hasProperty(KoXmlNS::draw, "fill-color")) 0474 tmpBrush.setColor(styleStack.property(KoXmlNS::draw, "fill-color")); 0475 if (styleStack.hasProperty(KoXmlNS::draw, "opacity")) { 0476 QString opacity = styleStack.property(KoXmlNS::draw, "opacity"); 0477 if (! opacity.isEmpty() && opacity.right(1) == "%") { 0478 float percent = opacity.leftRef(opacity.length() - 1).toFloat(); 0479 QColor color = tmpBrush.color(); 0480 color.setAlphaF(percent / 100.0); 0481 tmpBrush.setColor(color); 0482 } 0483 } 0484 //TODO 0485 if (styleStack.hasProperty(KoXmlNS::draw, "transparency")) { 0486 QString transparency = styleStack.property(KoXmlNS::draw, "transparency"); 0487 if (transparency == "94%") { 0488 tmpBrush.setStyle(Qt::Dense1Pattern); 0489 } else if (transparency == "88%") { 0490 tmpBrush.setStyle(Qt::Dense2Pattern); 0491 } else if (transparency == "63%") { 0492 tmpBrush.setStyle(Qt::Dense3Pattern); 0493 0494 } else if (transparency == "50%") { 0495 tmpBrush.setStyle(Qt::Dense4Pattern); 0496 0497 } else if (transparency == "37%") { 0498 tmpBrush.setStyle(Qt::Dense5Pattern); 0499 0500 } else if (transparency == "12%") { 0501 tmpBrush.setStyle(Qt::Dense6Pattern); 0502 0503 } else if (transparency == "6%") { 0504 tmpBrush.setStyle(Qt::Dense7Pattern); 0505 0506 } else 0507 debugOdf << " transparency is not defined into Stage :" << transparency; 0508 } 0509 } else if (fill == "hatch") { 0510 QString style = styleStack.property(KoXmlNS::draw, "fill-hatch-name"); 0511 debugOdf << " hatch style is :" << style; 0512 0513 //type not defined by default 0514 //try to use style. 0515 KoXmlElement* draw = stylesReader.drawStyles("hatch").value(style); 0516 if (draw) { 0517 debugOdf << "We have a style"; 0518 int angle = 0; 0519 if (draw->hasAttributeNS(KoXmlNS::draw, "rotation")) { 0520 angle = (draw->attributeNS(KoXmlNS::draw, "rotation", QString()).toInt()) / 10; 0521 debugOdf << "angle :" << angle; 0522 } 0523 if (draw->hasAttributeNS(KoXmlNS::draw, "color")) { 0524 //debugOdf<<" draw:color :"<<draw->attributeNS( KoXmlNS::draw,"color", QString() ); 0525 tmpBrush.setColor(draw->attributeNS(KoXmlNS::draw, "color", QString())); 0526 } 0527 if (draw->hasAttributeNS(KoXmlNS::draw, "distance")) { 0528 //TODO: implement it into Stage 0529 } 0530 if (draw->hasAttributeNS(KoXmlNS::draw, "display-name")) { 0531 //TODO: implement it into Stage 0532 } 0533 if (draw->hasAttributeNS(KoXmlNS::draw, "style")) { 0534 //TODO: implement it into Stage 0535 QString styleHash = draw->attributeNS(KoXmlNS::draw, "style", QString()); 0536 if (styleHash == "single") { 0537 switch (angle) { 0538 case 0: 0539 case 180: 0540 tmpBrush.setStyle(Qt::HorPattern); 0541 break; 0542 case 45: 0543 case 225: 0544 tmpBrush.setStyle(Qt::BDiagPattern); 0545 break; 0546 case 90: 0547 case 270: 0548 tmpBrush.setStyle(Qt::VerPattern); 0549 break; 0550 case 135: 0551 case 315: 0552 tmpBrush.setStyle(Qt::FDiagPattern); 0553 break; 0554 default: 0555 //todo fixme when we will have a kopaint 0556 debugOdf << " draw:rotation 'angle' :" << angle; 0557 break; 0558 } 0559 } else if (styleHash == "double") { 0560 switch (angle) { 0561 case 0: 0562 case 180: 0563 case 90: 0564 case 270: 0565 tmpBrush.setStyle(Qt::CrossPattern); 0566 break; 0567 case 45: 0568 case 135: 0569 case 225: 0570 case 315: 0571 tmpBrush.setStyle(Qt::DiagCrossPattern); 0572 break; 0573 default: 0574 //todo fixme when we will have a kopaint 0575 debugOdf << " draw:rotation 'angle' :" << angle; 0576 break; 0577 } 0578 0579 } else if (styleHash == "triple") { 0580 debugOdf << " it is not implemented :("; 0581 } 0582 } 0583 } 0584 } 0585 0586 return tmpBrush; 0587 } 0588 0589 static qreal parseDashEntrySize(QString& attr, qreal penWidth, qreal defaultValue = 0.0){ 0590 qreal result = defaultValue; 0591 if (attr.endsWith('%')) { 0592 bool ok; 0593 const int percent = attr.remove('%').toInt(&ok); 0594 if (ok && percent >= 0) { 0595 result = percent / 100.0; 0596 } 0597 } else { 0598 result = KoUnit::parseValue(attr) / penWidth; 0599 } 0600 return result; 0601 } 0602 0603 QPen KoOdfGraphicStyles::loadOdfStrokeStyle(const KoStyleStack &styleStack, const QString & stroke, const KoOdfStylesReader & stylesReader) 0604 { 0605 QPen tmpPen(Qt::NoPen); // default pen for "none" is a Qt::NoPen 0606 0607 if (stroke == "solid" || stroke == "dash") { 0608 // If solid or dash is set then we assume that the color is black and the penWidth 0609 // is zero till defined otherwise with the following attributes. 0610 tmpPen = QPen(); 0611 0612 if (styleStack.hasProperty(KoXmlNS::svg, "stroke-color")) 0613 tmpPen.setColor(styleStack.property(KoXmlNS::svg, "stroke-color")); 0614 if (styleStack.hasProperty(KoXmlNS::svg, "stroke-opacity")) { 0615 QColor color = tmpPen.color(); 0616 QString opacity = styleStack.property(KoXmlNS::svg, "stroke-opacity"); 0617 if (opacity.endsWith('%')) 0618 color.setAlphaF(0.01 * opacity.remove('%').toDouble()); 0619 else 0620 color.setAlphaF(opacity.toDouble()); 0621 tmpPen.setColor(color); 0622 } 0623 if (styleStack.hasProperty(KoXmlNS::svg, "stroke-width")) 0624 tmpPen.setWidthF(KoUnit::parseValue(styleStack.property(KoXmlNS::svg, "stroke-width"))); 0625 if (styleStack.hasProperty(KoXmlNS::draw, "stroke-linejoin")) { 0626 QString join = styleStack.property(KoXmlNS::draw, "stroke-linejoin"); 0627 if (join == "bevel") 0628 tmpPen.setJoinStyle(Qt::BevelJoin); 0629 else if (join == "round") 0630 tmpPen.setJoinStyle(Qt::RoundJoin); 0631 else { 0632 tmpPen.setJoinStyle(Qt::MiterJoin); 0633 if (styleStack.hasProperty(KoXmlNS::calligra, "stroke-miterlimit")) { 0634 QString miterLimit = styleStack.property(KoXmlNS::calligra, "stroke-miterlimit"); 0635 tmpPen.setMiterLimit(miterLimit.toDouble()); 0636 } 0637 } 0638 } 0639 if (styleStack.hasProperty(KoXmlNS::svg, "stroke-linecap")) { 0640 const QString cap = styleStack.property(KoXmlNS::svg, "stroke-linecap"); 0641 if (cap == "round") 0642 tmpPen.setCapStyle(Qt::RoundCap); 0643 else if (cap == "square") 0644 tmpPen.setCapStyle(Qt::SquareCap); 0645 else 0646 tmpPen.setCapStyle(Qt::FlatCap); 0647 } else { 0648 // default as per svg specification 0649 tmpPen.setCapStyle(Qt::FlatCap); 0650 } 0651 0652 if (stroke == "dash" && styleStack.hasProperty(KoXmlNS::draw, "stroke-dash")) { 0653 QString dashStyleName = styleStack.property(KoXmlNS::draw, "stroke-dash"); 0654 0655 // set width to 1 in case it is 0 as dividing by 0 gives infinity 0656 qreal width = tmpPen.widthF(); 0657 if ( width == 0 ) { 0658 width = 1; 0659 } 0660 0661 KoXmlElement * dashElement = stylesReader.drawStyles("stroke-dash").value(dashStyleName); 0662 if (dashElement) { 0663 QVector<qreal> dashes; 0664 if (dashElement->hasAttributeNS(KoXmlNS::draw, "dots1")) { 0665 QString distance( dashElement->attributeNS(KoXmlNS::draw, "distance", QString()) ); 0666 qreal space = parseDashEntrySize(distance, width, 0.0); 0667 0668 QString dots1Length(dashElement->attributeNS(KoXmlNS::draw, "dots1-length", QString())); 0669 qreal dot1Length = parseDashEntrySize(dots1Length,width,1.0); 0670 0671 bool ok; 0672 int dots1 = dashElement->attributeNS(KoXmlNS::draw, "dots1").toInt(&ok); 0673 if (!ok) { 0674 dots1 = 1; 0675 } 0676 0677 for (int i = 0; i < dots1; i++) { 0678 dashes.append(dot1Length); 0679 dashes.append(space); 0680 } 0681 0682 if (dashElement->hasAttributeNS(KoXmlNS::draw, "dots2")) { 0683 QString dots2Length(dashElement->attributeNS(KoXmlNS::draw, "dots2-length", QString())); 0684 qreal dot2Length = parseDashEntrySize(dots2Length,width,1.0); 0685 0686 int dots2 = dashElement->attributeNS(KoXmlNS::draw, "dots2").toInt(&ok); 0687 if (!ok) { 0688 dots2 = 1; 0689 } 0690 0691 for (int i = 0; i < dots2; i++) { 0692 dashes.append(dot2Length); 0693 dashes.append(space); 0694 } 0695 } 0696 tmpPen.setDashPattern(dashes); 0697 } 0698 } 0699 } 0700 } 0701 0702 return tmpPen; 0703 } 0704 0705 QTransform KoOdfGraphicStyles::loadTransformation(const QString &transformation) 0706 { 0707 QTransform transform; 0708 0709 // Split string for handling 1 transform statement at a time 0710 QStringList subtransforms = transformation.split(')', QString::SkipEmptyParts); 0711 QStringList::ConstIterator it = subtransforms.constBegin(); 0712 QStringList::ConstIterator end = subtransforms.constEnd(); 0713 for (; it != end; ++it) { 0714 QStringList subtransform = (*it).split('(', QString::SkipEmptyParts); 0715 0716 subtransform[0] = subtransform[0].trimmed().toLower(); 0717 subtransform[1] = subtransform[1].simplified(); 0718 QRegExp reg("[,( ]"); 0719 QStringList params = subtransform[1].split(reg, QString::SkipEmptyParts); 0720 0721 if (subtransform[0].startsWith(';') || subtransform[0].startsWith(',')) 0722 subtransform[0] = subtransform[0].right(subtransform[0].length() - 1); 0723 0724 if (subtransform[0] == "rotate") { 0725 // TODO find out what oo2 really does when rotating, it seems severely broken 0726 if (params.count() == 3) { 0727 qreal x = KoUnit::parseValue(params[1]); 0728 qreal y = KoUnit::parseValue(params[2]); 0729 0730 transform.translate(x, y); 0731 // oo2 rotates by radians 0732 transform.rotate(params[0].toDouble()*180.0 / M_PI); 0733 transform.translate(-x, -y); 0734 } else { 0735 // oo2 rotates by radians 0736 transform.rotate(params[0].toDouble()*180.0 / M_PI); 0737 } 0738 } else if (subtransform[0] == "translate") { 0739 if (params.count() == 2) { 0740 qreal x = KoUnit::parseValue(params[0]); 0741 qreal y = KoUnit::parseValue(params[1]); 0742 transform.translate(x, y); 0743 } else // Spec : if only one param given, assume 2nd param to be 0 0744 transform.translate(KoUnit::parseValue(params[0]) , 0); 0745 } else if (subtransform[0] == "scale") { 0746 if (params.count() == 2) 0747 transform.scale(params[0].toDouble(), params[1].toDouble()); 0748 else // Spec : if only one param given, assume uniform scaling 0749 transform.scale(params[0].toDouble(), params[0].toDouble()); 0750 } else if (subtransform[0] == "skewx") 0751 transform.shear(tan(params[0].toDouble()), 0.0F); 0752 else if (subtransform[0] == "skewy") 0753 transform.shear(tan(params[0].toDouble()), 0.0F); 0754 else if (subtransform[0] == "matrix") { 0755 if (params.count() >= 6) { 0756 transform.setMatrix(params[0].toDouble(), params[1].toDouble(), 0, 0757 params[2].toDouble(), params[3].toDouble(), 0, 0758 KoUnit::parseValue(params[4]), KoUnit::parseValue(params[5]), 1); 0759 } 0760 } 0761 } 0762 0763 return transform; 0764 } 0765 0766 QString KoOdfGraphicStyles::saveTransformation(const QTransform &transformation, bool appendTranslateUnit) 0767 { 0768 QString transform; 0769 if (appendTranslateUnit) 0770 transform = QString("matrix(%1 %2 %3 %4 %5pt %6pt)") 0771 .arg(transformation.m11()).arg(transformation.m12()) 0772 .arg(transformation.m21()).arg(transformation.m22()) 0773 .arg(transformation.dx()) .arg(transformation.dy()); 0774 else 0775 transform = QString("matrix(%1 %2 %3 %4 %5 %6)") 0776 .arg(transformation.m11()).arg(transformation.m12()) 0777 .arg(transformation.m21()).arg(transformation.m22()) 0778 .arg(transformation.dx()) .arg(transformation.dy()); 0779 0780 return transform; 0781 } 0782