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 }