1/*
2    Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3    Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "CSSComputedStyleDeclaration.h"
23
24#include "CSSPrimitiveValueMappings.h"
25#include "CSSPropertyNames.h"
26#include "Document.h"
27#include "RenderStyle.h"
28#include "SVGPaint.h"
29
30namespace WebCore {
31
32static PassRefPtr<CSSValue> paintOrder(PaintOrder paintOrder)
33{
34    RefPtr<CSSValueList> paintOrderList = CSSValueList::createSpaceSeparated();
35    RefPtr<CSSValue> fill = CSSPrimitiveValue::createIdentifier(CSSValueFill);
36    RefPtr<CSSValue> stroke = CSSPrimitiveValue::createIdentifier(CSSValueStroke);
37    RefPtr<CSSValue> markers = CSSPrimitiveValue::createIdentifier(CSSValueMarkers);
38
39    switch (paintOrder) {
40    case PaintOrderNormal:
41        return CSSPrimitiveValue::createIdentifier(CSSValueNormal);
42    case PaintOrderFill:
43        paintOrderList->append(fill.release());
44        break;
45    case PaintOrderFillMarkers:
46        paintOrderList->append(fill.release());
47        paintOrderList->append(markers.release());
48        break;
49    case PaintOrderStroke:
50        paintOrderList->append(stroke.release());
51        break;
52    case PaintOrderStrokeMarkers:
53        paintOrderList->append(stroke.release());
54        paintOrderList->append(markers.release());
55        break;
56    case PaintOrderMarkers:
57        paintOrderList->append(markers.release());
58        break;
59    case PaintOrderMarkersStroke:
60        paintOrderList->append(markers.release());
61        paintOrderList->append(stroke.release());
62        break;
63    }
64    return paintOrderList.release();
65}
66
67static PassRefPtr<CSSPrimitiveValue> glyphOrientationToCSSPrimitiveValue(EGlyphOrientation orientation)
68{
69    switch (orientation) {
70        case GO_0DEG:
71            return CSSPrimitiveValue::create(0.0f, CSSPrimitiveValue::CSS_DEG);
72        case GO_90DEG:
73            return CSSPrimitiveValue::create(90.0f, CSSPrimitiveValue::CSS_DEG);
74        case GO_180DEG:
75            return CSSPrimitiveValue::create(180.0f, CSSPrimitiveValue::CSS_DEG);
76        case GO_270DEG:
77            return CSSPrimitiveValue::create(270.0f, CSSPrimitiveValue::CSS_DEG);
78        default:
79            return 0;
80    }
81}
82
83static PassRefPtr<CSSValue> strokeDashArrayToCSSValueList(const Vector<SVGLength>& dashes)
84{
85    if (dashes.isEmpty())
86        return CSSPrimitiveValue::createIdentifier(CSSValueNone);
87
88    RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
89    const Vector<SVGLength>::const_iterator end = dashes.end();
90    for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it)
91        list->append(SVGLength::toCSSPrimitiveValue(*it));
92
93    return list.release();
94}
95
96PassRefPtr<SVGPaint> ComputedStyleExtractor::adjustSVGPaintForCurrentColor(PassRefPtr<SVGPaint> newPaint, RenderStyle* style) const
97{
98    RefPtr<SVGPaint> paint = newPaint;
99    if (paint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR || paint->paintType() == SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR)
100        paint->setColor(style->color());
101    return paint.release();
102}
103
104PassRefPtr<CSSValue> ComputedStyleExtractor::svgPropertyValue(CSSPropertyID propertyID, EUpdateLayout updateLayout) const
105{
106    Node* node = m_node.get();
107    if (!node)
108        return 0;
109
110    // Make sure our layout is up to date before we allow a query on these attributes.
111    if (updateLayout)
112        node->document().updateLayout();
113
114    RenderStyle* style = node->computedStyle();
115    if (!style)
116        return 0;
117
118    const SVGRenderStyle& svgStyle = style->svgStyle();
119
120    switch (propertyID) {
121        case CSSPropertyClipRule:
122            return CSSPrimitiveValue::create(svgStyle.clipRule());
123        case CSSPropertyFloodOpacity:
124            return CSSPrimitiveValue::create(svgStyle.floodOpacity(), CSSPrimitiveValue::CSS_NUMBER);
125        case CSSPropertyStopOpacity:
126            return CSSPrimitiveValue::create(svgStyle.stopOpacity(), CSSPrimitiveValue::CSS_NUMBER);
127        case CSSPropertyColorInterpolation:
128            return CSSPrimitiveValue::create(svgStyle.colorInterpolation());
129        case CSSPropertyColorInterpolationFilters:
130            return CSSPrimitiveValue::create(svgStyle.colorInterpolationFilters());
131        case CSSPropertyFillOpacity:
132            return CSSPrimitiveValue::create(svgStyle.fillOpacity(), CSSPrimitiveValue::CSS_NUMBER);
133        case CSSPropertyFillRule:
134            return CSSPrimitiveValue::create(svgStyle.fillRule());
135        case CSSPropertyColorRendering:
136            return CSSPrimitiveValue::create(svgStyle.colorRendering());
137        case CSSPropertyShapeRendering:
138            return CSSPrimitiveValue::create(svgStyle.shapeRendering());
139        case CSSPropertyStrokeLinecap:
140            return CSSPrimitiveValue::create(svgStyle.capStyle());
141        case CSSPropertyStrokeLinejoin:
142            return CSSPrimitiveValue::create(svgStyle.joinStyle());
143        case CSSPropertyStrokeMiterlimit:
144            return CSSPrimitiveValue::create(svgStyle.strokeMiterLimit(), CSSPrimitiveValue::CSS_NUMBER);
145        case CSSPropertyStrokeOpacity:
146            return CSSPrimitiveValue::create(svgStyle.strokeOpacity(), CSSPrimitiveValue::CSS_NUMBER);
147        case CSSPropertyAlignmentBaseline:
148            return CSSPrimitiveValue::create(svgStyle.alignmentBaseline());
149        case CSSPropertyDominantBaseline:
150            return CSSPrimitiveValue::create(svgStyle.dominantBaseline());
151        case CSSPropertyTextAnchor:
152            return CSSPrimitiveValue::create(svgStyle.textAnchor());
153        case CSSPropertyWritingMode:
154            return CSSPrimitiveValue::create(svgStyle.writingMode());
155        case CSSPropertyClipPath:
156            if (!svgStyle.clipperResource().isEmpty())
157                return CSSPrimitiveValue::create(svgStyle.clipperResource(), CSSPrimitiveValue::CSS_URI);
158            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
159        case CSSPropertyMask:
160            if (!svgStyle.maskerResource().isEmpty())
161                return CSSPrimitiveValue::create(svgStyle.maskerResource(), CSSPrimitiveValue::CSS_URI);
162            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
163        case CSSPropertyFilter:
164            if (!svgStyle.filterResource().isEmpty())
165                return CSSPrimitiveValue::create(svgStyle.filterResource(), CSSPrimitiveValue::CSS_URI);
166            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
167        case CSSPropertyFloodColor:
168            return currentColorOrValidColor(style, svgStyle.floodColor());
169        case CSSPropertyLightingColor:
170            return currentColorOrValidColor(style, svgStyle.lightingColor());
171        case CSSPropertyStopColor:
172            return currentColorOrValidColor(style, svgStyle.stopColor());
173        case CSSPropertyFill:
174            return adjustSVGPaintForCurrentColor(SVGPaint::create(svgStyle.fillPaintType(), svgStyle.fillPaintUri(), svgStyle.fillPaintColor()), style);
175        case CSSPropertyKerning:
176            return SVGLength::toCSSPrimitiveValue(svgStyle.kerning());
177        case CSSPropertyMarkerEnd:
178            if (!svgStyle.markerEndResource().isEmpty())
179                return CSSPrimitiveValue::create(svgStyle.markerEndResource(), CSSPrimitiveValue::CSS_URI);
180            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
181        case CSSPropertyMarkerMid:
182            if (!svgStyle.markerMidResource().isEmpty())
183                return CSSPrimitiveValue::create(svgStyle.markerMidResource(), CSSPrimitiveValue::CSS_URI);
184            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
185        case CSSPropertyMarkerStart:
186            if (!svgStyle.markerStartResource().isEmpty())
187                return CSSPrimitiveValue::create(svgStyle.markerStartResource(), CSSPrimitiveValue::CSS_URI);
188            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
189        case CSSPropertyStroke:
190            return adjustSVGPaintForCurrentColor(SVGPaint::create(svgStyle.strokePaintType(), svgStyle.strokePaintUri(), svgStyle.strokePaintColor()), style);
191        case CSSPropertyStrokeDasharray:
192            return strokeDashArrayToCSSValueList(svgStyle.strokeDashArray());
193        case CSSPropertyStrokeDashoffset:
194            return SVGLength::toCSSPrimitiveValue(svgStyle.strokeDashOffset());
195        case CSSPropertyStrokeWidth:
196            return SVGLength::toCSSPrimitiveValue(svgStyle.strokeWidth());
197        case CSSPropertyBaselineShift: {
198            switch (svgStyle.baselineShift()) {
199                case BS_BASELINE:
200                    return CSSPrimitiveValue::createIdentifier(CSSValueBaseline);
201                case BS_SUPER:
202                    return CSSPrimitiveValue::createIdentifier(CSSValueSuper);
203                case BS_SUB:
204                    return CSSPrimitiveValue::createIdentifier(CSSValueSub);
205                case BS_LENGTH:
206                    return SVGLength::toCSSPrimitiveValue(svgStyle.baselineShiftValue());
207            }
208            ASSERT_NOT_REACHED();
209            return 0;
210        }
211        case CSSPropertyBufferedRendering:
212            return CSSPrimitiveValue::create(svgStyle.bufferedRendering());
213        case CSSPropertyGlyphOrientationHorizontal:
214            return glyphOrientationToCSSPrimitiveValue(svgStyle.glyphOrientationHorizontal());
215        case CSSPropertyGlyphOrientationVertical: {
216            if (RefPtr<CSSPrimitiveValue> value = glyphOrientationToCSSPrimitiveValue(svgStyle.glyphOrientationVertical()))
217                return value.release();
218
219            if (svgStyle.glyphOrientationVertical() == GO_AUTO)
220                return CSSPrimitiveValue::createIdentifier(CSSValueAuto);
221
222            return 0;
223        }
224        case CSSPropertyWebkitSvgShadow:
225            return valueForShadow(svgStyle.shadow(), propertyID, style);
226        case CSSPropertyVectorEffect:
227            return CSSPrimitiveValue::create(svgStyle.vectorEffect());
228        case CSSPropertyMaskType:
229            return CSSPrimitiveValue::create(svgStyle.maskType());
230        case CSSPropertyPaintOrder:
231            return paintOrder(svgStyle.paintOrder());
232        case CSSPropertyMarker:
233        case CSSPropertyEnableBackground:
234        case CSSPropertyColorProfile:
235            // the above properties are not yet implemented in the engine
236            break;
237    default:
238        // If you crash here, it's because you added a css property and are not handling it
239        // in either this switch statement or the one in CSSComputedStyleDelcaration::getPropertyCSSValue
240        ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propertyID);
241    }
242    LOG_ERROR("unimplemented propertyID: %d", propertyID);
243    return 0;
244}
245
246}
247