Reviewed by Maciej.
[WebKit-https.git] / WebCore / platform / graphics / svg / qt / SVGPaintServerRadialGradientQt.cpp
1 /*
2     Copyright (C) 2006 Nikolas Zimmermann <wildfox@kde.org>
3
4     This file is part of the KDE project
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Library General Public License for more details.
15
16     You should have received a copy of the GNU Library General Public License
17     aint with this library; see the file COPYING.LIB.  If not, write to
18     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19     Boston, MA 02111-1307, USA.
20 */
21
22 #include "config.h"
23
24 #ifdef SVG_SUPPORT
25 #include "SVGPaintServerRadialGradient.h"
26
27 #include "KRenderingDeviceQt.h"
28 #include "RenderPath.h"
29
30 #include <math.h>
31 #include <QRadialGradient>
32
33 namespace WebCore {
34
35 bool SVGPaintServerRadialGradient:: setup(KRenderingDeviceContext* context, const RenderObject* object, SVGPaintTargetType type) const
36 {
37     KRenderingDeviceContextQt* qtContext = static_cast<KRenderingDeviceContextQt*>(context);
38     Q_ASSERT(qtContext != 0);
39
40     if (listener())
41         listener()->resourceNotification();
42
43     RenderStyle* renderStyle = object->style();
44
45     qtContext->painter().setPen(Qt::NoPen);
46     qtContext->painter().setBrush(Qt::NoBrush);
47     QMatrix mat = qtContext->ctm();
48
49     double cx, fx, cy, fy, r;
50     if (boundingBoxMode()) {
51         QRectF bbox = qtContext->pathBBox();
52         cx = double(bbox.left()) + (double(gradientCenter().x() / 100.0) * double(bbox.width()));
53         cy = double(bbox.top()) + (double(gradientCenter().y() / 100.0) * double(bbox.height()));
54         fx = double(bbox.left()) + (double(gradientFocal().x() / 100.0) * double(bbox.width())) - cx;
55         fy = double(bbox.top()) + (double(gradientFocal().y() / 100.0) * double(bbox.height())) - cy;
56         r = double(gradientRadius() / 100.0) * (sqrt(pow(bbox.width(), 2) + pow(bbox.height(), 2)));
57
58         float width = bbox.width();
59         float height = bbox.height();
60
61         int diff = int(width - height); // allow slight tolerance
62         if (!(diff > -2 && diff < 2)) {
63             // make elliptical or circular depending on bbox aspect ratio
64             float ratioX = (width / height);
65             float ratioY = (height / width);
66             mat.scale((width > height) ? 1 : ratioX, (width > height) ? ratioY : 1);
67         }
68     } else {
69         cx = gradientCenter().x();
70         cy = gradientCenter().y();
71
72         fx = gradientFocal().x();
73         fy = gradientFocal().y();
74
75         fx -= cx;
76         fy -= cy;
77
78         r = gradientRadius();
79     }
80
81     if (sqrt(fx * fx + fy * fy) > r) {
82         // Spec: If (fx, fy) lies outside the circle defined by (cx, cy) and r, set (fx, fy)
83         // to the point of intersection of the line through (fx, fy) and the circle.
84         double angle = atan2(fy, fx);
85         fx = int(cos(angle) * r) - 1;
86         fy = int(sin(angle) * r) - 1;
87     }
88
89     QRadialGradient gradient(QPointF(cx, cy), gradientRadius(), QPointF(fx + cx, fy + cy));
90     if (spreadMethod() == SPREADMETHOD_REPEAT)
91         gradient.setSpread(QGradient::RepeatSpread);
92     else if (spreadMethod() == SPREADMETHOD_REFLECT)
93         gradient.setSpread(QGradient::ReflectSpread);
94     else
95         gradient.setSpread(QGradient::PadSpread);
96
97     double opacity = 1.0;
98
99     // TODO: Gradient transform + opacity fixes!
100
101     // AffineTransform gradientTrans = gradientTransform();
102     // gradientTrans.map(cx, cy, &cx, &cy);
103     // qtContext->painter().setMatrix(mat);
104
105     if ((type & ApplyToFillTargetType) && renderStyle->svgStyle()->hasFill()) {
106         fillColorArray(gradient, gradientStops(), opacity);
107
108         QBrush brush(gradient);
109
110         qtContext->painter().setBrush(brush);
111         qtContext->setFillRule(renderStyle->svgStyle()->fillRule());
112     }
113
114     if ((type & ApplyToStrokeTargetType) && renderStyle->svgStyle()->hasStroke()) {
115         fillColorArray(gradient, gradientStops(), opacity);
116
117         QPen pen;
118         QBrush brush(gradient);
119
120         setPenProperties(object, renderStyle, pen);
121         pen.setBrush(brush);
122
123         qtContext->painter().setPen(pen);
124     }
125
126     return true;
127 }
128
129 } // namespace WebCore
130
131 #endif
132
133 // vim:ts=4:noet