2 Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org>
3 2004, 2005, 2006 Rob Buis <buis@kde.org>
5 This file is part of the KDE project
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
28 #include "RenderStyle.h"
29 #include "AffineTransform.h"
30 #include "KRenderingDeviceQt.h"
31 #include "KCanvasRenderingStyle.h"
32 #include "KRenderingFillPainter.h"
33 #include "KRenderingStrokePainter.h"
34 #include "KRenderingPaintServerGradientQt.h"
38 void fill_color_array(QGradient& gradient, const Vector<KCGradientStop>& stops, float opacity)
40 for (unsigned i = 0; i < stops.size(); ++i) {
41 float offset = stops[i].first;
42 Color color = stops[i].second;
44 QColor c(color.red(), color.green(), color.blue());
45 c.setAlpha(int(color.alpha() * opacity));
47 gradient.setColorAt(offset, c);
51 // KRenderingPaintServerLinearGradientQt
52 KRenderingPaintServerLinearGradientQt::KRenderingPaintServerLinearGradientQt()
53 : KRenderingPaintServerLinearGradient()
54 , KRenderingPaintServerQt()
58 void KRenderingPaintServerLinearGradientQt::renderPath(KRenderingDeviceContext* context, const RenderPath* path, KCPaintTargetType type) const
60 RenderStyle* renderStyle = path->style();
61 KRenderingDeviceContextQt* qtContext = static_cast<KRenderingDeviceContextQt*>(context);
63 if ((type & APPLY_TO_FILL) && KSVGPainterFactory::isFilled(renderStyle))
64 qtContext->fillPath();
66 if ((type & APPLY_TO_STROKE) && KSVGPainterFactory::isStroked(renderStyle))
67 qtContext->strokePath();
70 bool KRenderingPaintServerLinearGradientQt::setup(KRenderingDeviceContext* context, const RenderObject* object, KCPaintTargetType type) const
72 KRenderingDeviceContextQt* qtContext = static_cast<KRenderingDeviceContextQt*>(context);
73 Q_ASSERT(qtContext != 0);
76 listener()->resourceNotification();
78 RenderStyle* renderStyle = object->style();
80 double x1, x2, y1, y2;
81 if (boundingBoxMode()) {
82 QRectF bbox = qtContext->pathBBox();
83 x1 = double(bbox.left()) + (double(gradientStart().x() / 100.0) * double(bbox.width()));
84 y1 = double(bbox.top()) + (double(gradientStart().y() / 100.0) * double(bbox.height()));
85 x2 = double(bbox.left()) + (double(gradientEnd().x() / 100.0) * double(bbox.width()));
86 y2 = double(bbox.top()) + (double(gradientEnd().y() / 100.0) * double(bbox.height()));
88 x1 = gradientStart().x();
89 y1 = gradientStart().y();
90 x2 = gradientEnd().x();
91 y2 = gradientEnd().y();
94 qtContext->painter().setPen(Qt::NoPen);
95 qtContext->painter().setBrush(Qt::NoBrush);
97 QLinearGradient gradient(QPointF(x1, y1), QPointF(x2, y2));
98 if (spreadMethod() == SPREADMETHOD_REPEAT)
99 gradient.setSpread(QGradient::RepeatSpread);
100 else if (spreadMethod() == SPREADMETHOD_REFLECT)
101 gradient.setSpread(QGradient::ReflectSpread);
103 gradient.setSpread(QGradient::PadSpread);
105 double opacity = 1.0;
107 // TODO: Gradient transform + opacity fixes!
109 if ((type & APPLY_TO_FILL) && KSVGPainterFactory::isFilled(renderStyle)) {
110 KRenderingFillPainter fillPainter = KSVGPainterFactory::fillPainter(renderStyle, object);
111 fill_color_array(gradient, gradientStops(), opacity);
113 QBrush brush(gradient);
115 qtContext->painter().setBrush(brush);
116 qtContext->setFillRule(fillPainter.fillRule());
119 if ((type & APPLY_TO_STROKE) && KSVGPainterFactory::isStroked(renderStyle)) {
120 KRenderingStrokePainter strokePainter = KSVGPainterFactory::strokePainter(renderStyle, object);
121 fill_color_array(gradient, gradientStops(), opacity);
124 QBrush brush(gradient);
126 setPenProperties(strokePainter, pen);
129 qtContext->painter().setPen(pen);
135 void KRenderingPaintServerLinearGradientQt::teardown(KRenderingDeviceContext*, const RenderObject*, KCPaintTargetType) const
139 void KRenderingPaintServerLinearGradientQt::draw(KRenderingDeviceContext* context, const RenderPath* path, KCPaintTargetType type) const
141 if (!setup(context, path, type))
144 renderPath(context, path, type);
145 teardown(context, path, type);
148 // KRenderingPaintServerRadialGradientQt
149 KRenderingPaintServerRadialGradientQt::KRenderingPaintServerRadialGradientQt()
150 : KRenderingPaintServerRadialGradient()
151 , KRenderingPaintServerQt()
155 bool KRenderingPaintServerRadialGradientQt::setup(KRenderingDeviceContext* context, const RenderObject* object, KCPaintTargetType type) const
157 KRenderingDeviceContextQt* qtContext = static_cast<KRenderingDeviceContextQt*>(context);
158 Q_ASSERT(qtContext != 0);
161 listener()->resourceNotification();
163 RenderStyle* renderStyle = object->style();
165 qtContext->painter().setPen(Qt::NoPen);
166 qtContext->painter().setBrush(Qt::NoBrush);
167 QMatrix mat = qtContext->ctm();
169 double cx, fx, cy, fy, r;
170 if (boundingBoxMode()) {
171 QRectF bbox = qtContext->pathBBox();
172 cx = double(bbox.left()) + (double(gradientCenter().x() / 100.0) * double(bbox.width()));
173 cy = double(bbox.top()) + (double(gradientCenter().y() / 100.0) * double(bbox.height()));
174 fx = double(bbox.left()) + (double(gradientFocal().x() / 100.0) * double(bbox.width())) - cx;
175 fy = double(bbox.top()) + (double(gradientFocal().y() / 100.0) * double(bbox.height())) - cy;
176 r = double(gradientRadius() / 100.0) * (sqrt(pow(bbox.width(), 2) + pow(bbox.height(), 2)));
178 float width = bbox.width();
179 float height = bbox.height();
181 int diff = int(width - height); // allow slight tolerance
182 if (!(diff > -2 && diff < 2)) {
183 // make elliptical or circular depending on bbox aspect ratio
184 float ratioX = (width / height);
185 float ratioY = (height / width);
186 mat.scale((width > height) ? 1 : ratioX, (width > height) ? ratioY : 1);
189 cx = gradientCenter().x();
190 cy = gradientCenter().y();
192 fx = gradientFocal().x();
193 fy = gradientFocal().y();
198 r = gradientRadius();
201 if (sqrt(fx * fx + fy * fy) > r) {
202 // Spec: If (fx, fy) lies outside the circle defined by (cx, cy) and r, set (fx, fy)
203 // to the point of intersection of the line through (fx, fy) and the circle.
204 double angle = atan2(fy, fx);
205 fx = int(cos(angle) * r) - 1;
206 fy = int(sin(angle) * r) - 1;
209 QRadialGradient gradient(QPointF(cx, cy), gradientRadius(), QPointF(fx + cx, fy + cy));
210 if (spreadMethod() == SPREADMETHOD_REPEAT)
211 gradient.setSpread(QGradient::RepeatSpread);
212 else if (spreadMethod() == SPREADMETHOD_REFLECT)
213 gradient.setSpread(QGradient::ReflectSpread);
215 gradient.setSpread(QGradient::PadSpread);
217 double opacity = 1.0;
219 // TODO: Gradient transform + opacity fixes!
221 // AffineTransform gradientTrans = gradientTransform();
222 // gradientTrans.map(cx, cy, &cx, &cy);
223 // qtContext->painter().setMatrix(mat);
225 if ((type & APPLY_TO_FILL) && KSVGPainterFactory::isFilled(renderStyle)) {
226 KRenderingFillPainter fillPainter = KSVGPainterFactory::fillPainter(renderStyle, object);
227 fill_color_array(gradient, gradientStops(), opacity);
229 QBrush brush(gradient);
231 qtContext->painter().setBrush(brush);
232 qtContext->setFillRule(fillPainter.fillRule());
235 if ((type & APPLY_TO_STROKE) && KSVGPainterFactory::isStroked(renderStyle)) {
236 KRenderingStrokePainter strokePainter = KSVGPainterFactory::strokePainter(renderStyle, object);
237 fill_color_array(gradient, gradientStops(), opacity);
240 QBrush brush(gradient);
242 setPenProperties(strokePainter, pen);
245 qtContext->painter().setPen(pen);
251 void KRenderingPaintServerRadialGradientQt::draw(KRenderingDeviceContext* context, const RenderPath* path, KCPaintTargetType type) const
253 if (!setup(context, path, type))
256 renderPath(context, path, type);
257 teardown(context, path, type);
260 void KRenderingPaintServerRadialGradientQt::teardown(KRenderingDeviceContext*, const RenderObject*, KCPaintTargetType) const
264 void KRenderingPaintServerRadialGradientQt::renderPath(KRenderingDeviceContext* context, const RenderPath* path, KCPaintTargetType type) const
266 RenderStyle* renderStyle = path->style();
267 KRenderingDeviceContextQt* qtContext = static_cast<KRenderingDeviceContextQt*>(context);
269 if ((type & APPLY_TO_FILL) && KSVGPainterFactory::isFilled(renderStyle))
270 qtContext->fillPath();
272 if ((type & APPLY_TO_STROKE) && KSVGPainterFactory::isStroked(renderStyle))
273 qtContext->strokePath();