Warning, file /office/calligra/libs/flake/KoOdfGradientBackground.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 * 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 #include "KoOdfGradientBackground.h" 0022 0023 #include "KoShapeBackground_p.h" 0024 #include "KoShapeSavingContext.h" 0025 0026 #include <KoUnit.h> 0027 #include <KoXmlNS.h> 0028 #include <KoXmlReader.h> 0029 #include <KoGenStyles.h> 0030 #include <KoOdfLoadingContext.h> 0031 #include <KoStyleStack.h> 0032 0033 #include <QPainter> 0034 #include <QPainterPath> 0035 #include <QColor> 0036 #include <QImage> 0037 #include <qmath.h> 0038 0039 0040 class KoOdfGradientBackgroundPrivate : public KoShapeBackgroundPrivate 0041 { 0042 public: 0043 KoOdfGradientBackgroundPrivate() 0044 : style(), cx(0), cy(0), startColor(), endColor(), angle(0), border(0), opacity(1.0) {}; 0045 ~KoOdfGradientBackgroundPrivate() override{}; 0046 //data 0047 QString style; 0048 int cx; 0049 int cy; 0050 QColor startColor; 0051 QColor endColor; 0052 qreal angle; 0053 qreal border; 0054 qreal opacity; 0055 0056 mutable QImage buffer; 0057 }; 0058 0059 0060 KoOdfGradientBackground::KoOdfGradientBackground() 0061 : KoShapeBackground(*(new KoOdfGradientBackgroundPrivate())) 0062 { 0063 0064 } 0065 0066 KoOdfGradientBackground::~KoOdfGradientBackground() 0067 { 0068 0069 } 0070 0071 0072 bool KoOdfGradientBackground::loadOdf(const KoXmlElement& e) 0073 { 0074 Q_D(KoOdfGradientBackground); 0075 d->style = e.attributeNS(KoXmlNS::draw, "style", QString()); 0076 //TODO: support ellipsoid here too 0077 if ((d->style != "rectangular") && (d->style != "square")) { 0078 return false; 0079 } 0080 0081 d->cx = KoUnit::parseValue(e.attributeNS(KoXmlNS::draw, "cx", QString()).remove('%')); 0082 d->cy = KoUnit::parseValue(e.attributeNS(KoXmlNS::draw, "cy", QString()).remove('%')); 0083 0084 d->border = qBound(0.0,0.01 * e.attributeNS(KoXmlNS::draw, "border", "0").remove('%').toDouble(),1.0); 0085 0086 d->startColor = QColor(e.attributeNS(KoXmlNS::draw, "start-color", QString())); 0087 d->startColor.setAlphaF((0.01 * e.attributeNS(KoXmlNS::draw, "start-intensity", "100").remove('%').toDouble())); 0088 0089 d->endColor = QColor(e.attributeNS(KoXmlNS::draw, "end-color", QString())); 0090 d->endColor.setAlphaF(0.01 * e.attributeNS(KoXmlNS::draw, "end-intensity", "100").remove('%').toDouble()); 0091 d->angle = e.attributeNS(KoXmlNS::draw, "angle", "0").toDouble() / 10; 0092 0093 return true; 0094 } 0095 0096 0097 void KoOdfGradientBackground::saveOdf(KoGenStyle& styleFill, KoGenStyles& mainStyles) const 0098 { 0099 Q_D(const KoOdfGradientBackground); 0100 0101 KoGenStyle::Type type = styleFill.type(); 0102 KoGenStyle::PropertyType propertyType = (type == KoGenStyle::GraphicStyle || type == KoGenStyle::GraphicAutoStyle || 0103 type == KoGenStyle::DrawingPageStyle || type == KoGenStyle::DrawingPageAutoStyle ) 0104 ? KoGenStyle::DefaultType : KoGenStyle::GraphicType; 0105 0106 KoGenStyle gradientStyle(KoGenStyle::GradientStyle); 0107 0108 gradientStyle.addAttribute("draw:style", d->style); // draw:style="square" 0109 gradientStyle.addAttribute("draw:cx", QString("%1%").arg(d->cx)); 0110 gradientStyle.addAttribute("draw:cy", QString("%1%").arg(d->cy)); 0111 gradientStyle.addAttribute("draw:start-color", d->startColor.name()); 0112 gradientStyle.addAttribute("draw:end-color", d->endColor.name()); 0113 gradientStyle.addAttribute("draw:start-intensity", QString("%1%").arg(qRound(d->startColor.alphaF() * 100)) ); 0114 gradientStyle.addAttribute("draw:end-intensity", QString("%1%").arg(qRound(d->endColor.alphaF() * 100)) ); 0115 gradientStyle.addAttribute("draw:angle", QString("%1").arg(d->angle * 10)); 0116 gradientStyle.addAttribute("draw:border", QString("%1%").arg(qRound(d->border * 100.0))); 0117 0118 QString gradientStyleName = mainStyles.insert(gradientStyle, "gradient"); 0119 0120 styleFill.addProperty("draw:fill", "gradient", propertyType); 0121 styleFill.addProperty("draw:fill-gradient-name", gradientStyleName, propertyType); 0122 if (d->opacity <= 1.0) { 0123 styleFill.addProperty("draw:opacity", QString("%1%").arg(d->opacity * 100.0), propertyType); 0124 } 0125 } 0126 0127 void KoOdfGradientBackground::paint(QPainter& painter, const KoViewConverter &/*converter*/, KoShapePaintingContext &/*context*/, const QPainterPath& fillPath) const 0128 { 0129 Q_D(const KoOdfGradientBackground); 0130 QRectF targetRect = fillPath.boundingRect(); 0131 QRectF pixels = painter.transform().mapRect(QRectF(0,0,targetRect.width(), targetRect.height())); 0132 QSize currentSize( qCeil(pixels.size().width()), qCeil(pixels.size().height()) ); 0133 if (d->buffer.isNull() || d->buffer.size() != currentSize){ 0134 d->buffer = QImage(currentSize, QImage::Format_ARGB32_Premultiplied); 0135 if (d->style == "square") { 0136 renderSquareGradient(d->buffer); 0137 } else { 0138 renderRectangleGradient(d->buffer); 0139 } 0140 } 0141 0142 painter.setClipPath(fillPath); 0143 0144 painter.setOpacity(d->opacity); 0145 painter.drawImage(targetRect, d->buffer, QRectF(QPointF(0,0), d->buffer.size())); 0146 } 0147 0148 void KoOdfGradientBackground::fillStyle(KoGenStyle& style, KoShapeSavingContext& context) 0149 { 0150 saveOdf(style, context.mainStyles()); 0151 } 0152 0153 bool KoOdfGradientBackground::loadStyle(KoOdfLoadingContext& context, const QSizeF& shapeSize) 0154 { 0155 Q_UNUSED(shapeSize); 0156 Q_D(KoOdfGradientBackground); 0157 0158 KoStyleStack &styleStack = context.styleStack(); 0159 if (!styleStack.hasProperty(KoXmlNS::draw, "fill")) { 0160 return false; 0161 } 0162 0163 QString fillStyle = styleStack.property(KoXmlNS::draw, "fill"); 0164 if (fillStyle == "gradient") { 0165 0166 if (styleStack.hasProperty(KoXmlNS::draw, "opacity")) { 0167 QString opacity = styleStack.property(KoXmlNS::draw, "opacity"); 0168 if (! opacity.isEmpty() && opacity.right(1) == "%") { 0169 d->opacity = qMin(opacity.leftRef(opacity.length() - 1).toDouble(), 100.0) / 100; 0170 } 0171 } 0172 0173 QString styleName = styleStack.property(KoXmlNS::draw, "fill-gradient-name"); 0174 auto gradient = context.stylesReader().drawStyles("gradient"); 0175 auto it = gradient.constFind(styleName); 0176 if (it != gradient.constEnd() && it.value()) { 0177 return loadOdf(*it.value()); 0178 } 0179 } 0180 0181 return false; 0182 } 0183 0184 0185 void KoOdfGradientBackground::renderSquareGradient(QImage& buffer) const 0186 { 0187 Q_D(const KoOdfGradientBackground); 0188 buffer.fill(d->startColor.rgba()); 0189 0190 QPainter painter(&buffer); 0191 painter.setPen(Qt::NoPen); 0192 painter.setRenderHint(QPainter::Antialiasing, false); 0193 0194 int width = buffer.width(); 0195 int height = buffer.height(); 0196 0197 qreal gradientCenterX = qRound(width * d->cx * 0.01); 0198 qreal gradientCenterY = qRound(height * d->cy * 0.01); 0199 qreal centerX = width * 0.5; 0200 qreal centerY = height * 0.5; 0201 0202 qreal areaCenterX = qRound(centerX); 0203 qreal areaCenterY = qRound(centerY); 0204 0205 QTransform m; 0206 m.translate(gradientCenterX, gradientCenterY); 0207 m.rotate(-d->angle); 0208 m.scale(1.0 - d->border, 1.0 - d->border); 0209 m.translate(-gradientCenterX, -gradientCenterY); 0210 m.translate(gradientCenterX - areaCenterX,gradientCenterY - areaCenterY); 0211 painter.setTransform(m); 0212 0213 QLinearGradient linearGradient; 0214 linearGradient.setColorAt(1, d->startColor); 0215 linearGradient.setColorAt(0, d->endColor); 0216 0217 // from center going North 0218 linearGradient.setStart(centerX, centerY); 0219 linearGradient.setFinalStop(centerX, 0); 0220 painter.setBrush(linearGradient); 0221 painter.drawRect(0, 0, width, centerY); 0222 0223 // from center going South 0224 linearGradient.setFinalStop(centerX, height); 0225 painter.setBrush(linearGradient); 0226 painter.drawRect(0, centerY, width, centerY); 0227 0228 // clip the East and West portion 0229 QPainterPath clip; 0230 clip.moveTo(width, 0); 0231 clip.lineTo(width, height); 0232 clip.lineTo(0, 0); 0233 clip.lineTo(0, height); 0234 clip.closeSubpath(); 0235 painter.setClipPath(clip); 0236 0237 // from center going East 0238 linearGradient.setFinalStop(width, centerY); 0239 painter.setBrush(linearGradient); 0240 painter.drawRect(centerX, 0, width, height); 0241 0242 // from center going West 0243 linearGradient.setFinalStop( 0, centerY); 0244 painter.setBrush(linearGradient); 0245 painter.drawRect(0, 0, centerX, height); 0246 } 0247 0248 0249 void KoOdfGradientBackground::renderRectangleGradient(QImage& buffer) const 0250 { 0251 Q_D(const KoOdfGradientBackground); 0252 buffer.fill(d->startColor.rgba()); 0253 0254 QPainter painter(&buffer); 0255 painter.setPen(Qt::NoPen); 0256 painter.setRenderHint(QPainter::Antialiasing, false); 0257 0258 int width = buffer.width(); 0259 int height = buffer.height(); 0260 0261 qreal gradientCenterX = qRound(width * d->cx * 0.01); 0262 qreal gradientCenterY = qRound(height * d->cy * 0.01); 0263 qreal centerX = width * 0.5; 0264 qreal centerY = height * 0.5; 0265 0266 qreal areaCenterY = qRound(centerY); 0267 qreal areaCenterX = qRound(centerX); 0268 0269 QTransform m; 0270 m.translate(gradientCenterX, gradientCenterY); 0271 // m.rotate(-d->angle); // OOo rotates the gradient differently 0272 m.scale(1.0 - d->border, 1.0 - d->border); 0273 m.translate(-gradientCenterX, -gradientCenterY); 0274 m.translate(gradientCenterX - areaCenterX,gradientCenterY - areaCenterY); 0275 painter.setTransform(m); 0276 0277 QLinearGradient linearGradient; 0278 linearGradient.setColorAt(1, d->startColor); 0279 linearGradient.setColorAt(0, d->endColor); 0280 0281 // render background 0282 QPainterPath clipPath; 0283 if (width < height) { 0284 QRectF west(0,0,centerX, height); 0285 QRectF east(centerX, 0, centerX, height); 0286 0287 linearGradient.setStart(centerX, centerY); 0288 linearGradient.setFinalStop(0, centerY); 0289 painter.setBrush(linearGradient); 0290 painter.drawRect(west); 0291 0292 linearGradient.setFinalStop(width, centerY); 0293 painter.setBrush(linearGradient); 0294 painter.drawRect(east); 0295 0296 QRectF north(0,0,width, centerX); 0297 QRectF south(0,height - centerX, width, centerX); 0298 0299 clipPath.moveTo(0,0); 0300 clipPath.lineTo(width, 0); 0301 clipPath.lineTo(centerX, centerX); 0302 clipPath.closeSubpath(); 0303 0304 clipPath.moveTo(width, height); 0305 clipPath.lineTo(0, height); 0306 clipPath.lineTo(centerX, south.y()); 0307 clipPath.closeSubpath(); 0308 0309 linearGradient.setStart(centerX, centerX); 0310 linearGradient.setFinalStop(centerX, 0); 0311 0312 painter.setClipPath(clipPath); 0313 painter.setBrush(linearGradient); 0314 painter.drawRect(north); 0315 0316 linearGradient.setStart(centerX, south.y()); 0317 linearGradient.setFinalStop(centerX, height); 0318 0319 painter.setBrush(linearGradient); 0320 painter.drawRect(south); 0321 } else { 0322 QRectF north(0,0,width, centerY); 0323 QRectF south(0, centerY, width, centerY); 0324 0325 linearGradient.setStart(centerX, centerY); 0326 linearGradient.setFinalStop(centerX, 0); 0327 0328 painter.setBrush(linearGradient); 0329 painter.drawRect(north); 0330 0331 linearGradient.setFinalStop(centerX, height); 0332 painter.setBrush(linearGradient); 0333 painter.drawRect(south); 0334 0335 0336 QRectF west(0,0,centerY, height); 0337 QRectF east(width - centerY, 0, centerY, height); 0338 0339 clipPath.moveTo(0,0); 0340 clipPath.lineTo(centerY, centerY); 0341 clipPath.lineTo(0,height); 0342 clipPath.closeSubpath(); 0343 0344 clipPath.moveTo(width, height); 0345 clipPath.lineTo(east.x(), centerY); 0346 clipPath.lineTo(width,0); 0347 clipPath.closeSubpath(); 0348 0349 linearGradient.setStart(centerY, centerY); 0350 linearGradient.setFinalStop(0, centerY); 0351 0352 painter.setClipPath(clipPath); 0353 painter.setBrush(linearGradient); 0354 painter.drawRect(west); 0355 0356 linearGradient.setStart(east.x(), centerY); 0357 linearGradient.setFinalStop(width, centerY); 0358 0359 painter.setBrush(linearGradient); 0360 painter.drawRect(east); 0361 } 0362 } 0363 0364 0365 void KoOdfGradientBackground::debug() const 0366 { 0367 Q_D(const KoOdfGradientBackground); 0368 qDebug() << "cx,cy: "<< d->cx << d->cy; 0369 qDebug() << "style" << d->style; 0370 qDebug() << "colors" << d->startColor << d->endColor; 0371 qDebug() << "angle:" << d->angle; 0372 qDebug() << "border" << d->border; 0373 }