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()
154 bool KRenderingPaintServerRadialGradientQt::setup(KRenderingDeviceContext* context, const RenderObject* object, KCPaintTargetType type) const
156 KRenderingDeviceContextQt* qtContext = static_cast<KRenderingDeviceContextQt*>(context);
157 Q_ASSERT(qtContext != 0);
160 listener()->resourceNotification();
162 RenderStyle* renderStyle = object->style();
164 qtContext->painter().setPen(Qt::NoPen);
165 qtContext->painter().setBrush(Qt::NoBrush);
166 QMatrix mat = qtContext->ctm();
168 double cx, fx, cy, fy, r;
169 if (boundingBoxMode()) {
170 QRectF bbox = qtContext->pathBBox();
171 cx = double(bbox.left()) + (double(gradientCenter().x() / 100.0) * double(bbox.width()));
172 cy = double(bbox.top()) + (double(gradientCenter().y() / 100.0) * double(bbox.height()));
173 fx = double(bbox.left()) + (double(gradientFocal().x() / 100.0) * double(bbox.width())) - cx;
174 fy = double(bbox.top()) + (double(gradientFocal().y() / 100.0) * double(bbox.height())) - cy;
175 r = double(gradientRadius() / 100.0) * (sqrt(pow(bbox.width(), 2) + pow(bbox.height(), 2)));
177 float width = bbox.width();
178 float height = bbox.height();
180 int diff = int(width - height); // allow slight tolerance
181 if (!(diff > -2 && diff < 2)) {
182 // make elliptical or circular depending on bbox aspect ratio
183 float ratioX = (width / height);
184 float ratioY = (height / width);
185 mat.scale((width > height) ? 1 : ratioX, (width > height) ? ratioY : 1);
188 cx = gradientCenter().x();
189 cy = gradientCenter().y();
191 fx = gradientFocal().x();
192 fy = gradientFocal().y();
197 r = gradientRadius();
200 if (sqrt(fx * fx + fy * fy) > r) {
201 // Spec: If (fx, fy) lies outside the circle defined by (cx, cy) and r, set (fx, fy)
202 // to the point of intersection of the line through (fx, fy) and the circle.
203 double angle = atan2(fy, fx);
204 fx = int(cos(angle) * r) - 1;
205 fy = int(sin(angle) * r) - 1;
208 QRadialGradient gradient(QPointF(cx, cy), gradientRadius(), QPointF(fx + cx, fy + cy));
209 if (spreadMethod() == SPREADMETHOD_REPEAT)
210 gradient.setSpread(QGradient::RepeatSpread);
211 else if (spreadMethod() == SPREADMETHOD_REFLECT)
212 gradient.setSpread(QGradient::ReflectSpread);
214 gradient.setSpread(QGradient::PadSpread);
216 double opacity = 1.0;
218 // TODO: Gradient transform + opacity fixes!
220 // AffineTransform gradientTrans = gradientTransform();
221 // gradientTrans.map(cx, cy, &cx, &cy);
222 // qtContext->painter().setMatrix(mat);
224 if ((type & APPLY_TO_FILL) && KSVGPainterFactory::isFilled(renderStyle)) {
225 KRenderingFillPainter fillPainter = KSVGPainterFactory::fillPainter(renderStyle, object);
226 fill_color_array(gradient, gradientStops(), opacity);
228 QBrush brush(gradient);
230 qtContext->painter().setBrush(brush);
231 qtContext->setFillRule(fillPainter.fillRule());
234 if ((type & APPLY_TO_STROKE) && KSVGPainterFactory::isStroked(renderStyle)) {
235 KRenderingStrokePainter strokePainter = KSVGPainterFactory::strokePainter(renderStyle, object);
236 fill_color_array(gradient, gradientStops(), opacity);
239 QBrush brush(gradient);
241 setPenProperties(strokePainter, pen);
244 qtContext->painter().setPen(pen);
250 void KRenderingPaintServerRadialGradientQt::draw(KRenderingDeviceContext* context, const RenderPath* path, KCPaintTargetType type) const
252 if (!setup(context, path, type))
255 renderPath(context, path, type);
256 teardown(context, path, type);
259 void KRenderingPaintServerRadialGradientQt::teardown(KRenderingDeviceContext*, const RenderObject*, KCPaintTargetType) const
263 void KRenderingPaintServerRadialGradientQt::renderPath(KRenderingDeviceContext* context, const RenderPath* path, KCPaintTargetType type) const
265 RenderStyle* renderStyle = path->style();
266 KRenderingDeviceContextQt* qtContext = static_cast<KRenderingDeviceContextQt*>(context);
268 if ((type & APPLY_TO_FILL) && KSVGPainterFactory::isFilled(renderStyle))
269 qtContext->fillPath();
271 if ((type & APPLY_TO_STROKE) && KSVGPainterFactory::isStroked(renderStyle))
272 qtContext->strokePath();