1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6#include "core/animation/css/CSSPropertyEquality.h"
7
8#include "core/animation/css/CSSAnimations.h"
9#include "core/rendering/style/DataEquivalency.h"
10#include "core/rendering/style/RenderStyle.h"
11#include "core/rendering/style/ShadowList.h"
12
13namespace blink {
14
15namespace {
16
17template <CSSPropertyID property>
18bool fillLayersEqual(const FillLayer& aLayers, const FillLayer& bLayers)
19{
20    const FillLayer* aLayer = &aLayers;
21    const FillLayer* bLayer = &bLayers;
22    while (aLayer && bLayer) {
23        switch (property) {
24        case CSSPropertyBackgroundPositionX:
25        case CSSPropertyWebkitMaskPositionX:
26            if (aLayer->xPosition() != bLayer->xPosition())
27                return false;
28            break;
29        case CSSPropertyBackgroundPositionY:
30        case CSSPropertyWebkitMaskPositionY:
31            if (aLayer->yPosition() != bLayer->yPosition())
32                return false;
33            break;
34        case CSSPropertyBackgroundSize:
35        case CSSPropertyWebkitBackgroundSize:
36        case CSSPropertyWebkitMaskSize:
37            if (!(aLayer->sizeLength() == bLayer->sizeLength()))
38                return false;
39            break;
40        case CSSPropertyBackgroundImage:
41            if (!dataEquivalent(aLayer->image(), bLayer->image()))
42                return false;
43            break;
44        default:
45            ASSERT_NOT_REACHED();
46            return true;
47        }
48
49        aLayer = aLayer->next();
50        bLayer = bLayer->next();
51    }
52
53    // FIXME: Shouldn't this be return !aLayer && !bLayer; ?
54    return true;
55}
56
57}
58
59bool CSSPropertyEquality::propertiesEqual(CSSPropertyID prop, const RenderStyle& a, const RenderStyle& b)
60{
61    switch (prop) {
62    case CSSPropertyBackgroundColor:
63        return a.backgroundColor() == b.backgroundColor()
64            && a.visitedLinkBackgroundColor() == b.visitedLinkBackgroundColor();
65    case CSSPropertyBackgroundImage:
66        return fillLayersEqual<CSSPropertyBackgroundImage>(a.backgroundLayers(), b.backgroundLayers());
67    case CSSPropertyBackgroundPositionX:
68        return fillLayersEqual<CSSPropertyBackgroundPositionX>(a.backgroundLayers(), b.backgroundLayers());
69    case CSSPropertyBackgroundPositionY:
70        return fillLayersEqual<CSSPropertyBackgroundPositionY>(a.backgroundLayers(), b.backgroundLayers());
71    case CSSPropertyBackgroundSize:
72        return fillLayersEqual<CSSPropertyBackgroundSize>(a.backgroundLayers(), b.backgroundLayers());
73    case CSSPropertyBaselineShift:
74        return dataEquivalent(a.baselineShiftValue(), b.baselineShiftValue());
75    case CSSPropertyBorderBottomColor:
76        return a.borderBottomColor() == b.borderBottomColor()
77            && a.visitedLinkBorderBottomColor() == b.visitedLinkBorderBottomColor();
78    case CSSPropertyBorderBottomLeftRadius:
79        return a.borderBottomLeftRadius() == b.borderBottomLeftRadius();
80    case CSSPropertyBorderBottomRightRadius:
81        return a.borderBottomRightRadius() == b.borderBottomRightRadius();
82    case CSSPropertyBorderBottomWidth:
83        return a.borderBottomWidth() == b.borderBottomWidth();
84    case CSSPropertyBorderImageOutset:
85        return a.borderImageOutset() == b.borderImageOutset();
86    case CSSPropertyBorderImageSlice:
87        return a.borderImageSlices() == b.borderImageSlices();
88    case CSSPropertyBorderImageSource:
89        return dataEquivalent(a.borderImageSource(), b.borderImageSource());
90    case CSSPropertyBorderImageWidth:
91        return a.borderImageWidth() == b.borderImageWidth();
92    case CSSPropertyBorderLeftColor:
93        return a.borderLeftColor() == b.borderLeftColor()
94            && a.visitedLinkBorderLeftColor() == b.visitedLinkBorderLeftColor();
95    case CSSPropertyBorderLeftWidth:
96        return a.borderLeftWidth() == b.borderLeftWidth();
97    case CSSPropertyBorderRightColor:
98        return a.borderRightColor() == b.borderRightColor()
99            && a.visitedLinkBorderRightColor() == b.visitedLinkBorderRightColor();
100    case CSSPropertyBorderRightWidth:
101        return a.borderRightWidth() == b.borderRightWidth();
102    case CSSPropertyBorderTopColor:
103        return a.borderTopColor() == b.borderTopColor()
104            && a.visitedLinkBorderTopColor() == b.visitedLinkBorderTopColor();
105    case CSSPropertyBorderTopLeftRadius:
106        return a.borderTopLeftRadius() == b.borderTopLeftRadius();
107    case CSSPropertyBorderTopRightRadius:
108        return a.borderTopRightRadius() == b.borderTopRightRadius();
109    case CSSPropertyBorderTopWidth:
110        return a.borderTopWidth() == b.borderTopWidth();
111    case CSSPropertyBottom:
112        return a.bottom() == b.bottom();
113    case CSSPropertyBoxShadow:
114        return dataEquivalent(a.boxShadow(), b.boxShadow());
115    case CSSPropertyClip:
116        return a.clip() == b.clip();
117    case CSSPropertyColor:
118        return a.color() == b.color() && a.visitedLinkColor() == b.visitedLinkColor();
119    case CSSPropertyFill: {
120        const SVGRenderStyle& aSVG = a.svgStyle();
121        const SVGRenderStyle& bSVG = b.svgStyle();
122        return aSVG.fillPaintType() == bSVG.fillPaintType()
123            && (aSVG.fillPaintType() != SVG_PAINTTYPE_RGBCOLOR || aSVG.fillPaintColor() == bSVG.fillPaintColor())
124            && aSVG.visitedLinkFillPaintType() == bSVG.visitedLinkFillPaintType()
125            && (aSVG.visitedLinkFillPaintType() != SVG_PAINTTYPE_RGBCOLOR || aSVG.visitedLinkFillPaintColor() == bSVG.visitedLinkFillPaintColor());
126    }
127    case CSSPropertyFillOpacity:
128        return a.fillOpacity() == b.fillOpacity();
129    case CSSPropertyFlexBasis:
130        return a.flexBasis() == b.flexBasis();
131    case CSSPropertyFlexGrow:
132        return a.flexGrow() == b.flexGrow();
133    case CSSPropertyFlexShrink:
134        return a.flexShrink() == b.flexShrink();
135    case CSSPropertyFloodColor:
136        return a.floodColor() == b.floodColor();
137    case CSSPropertyFloodOpacity:
138        return a.floodOpacity() == b.floodOpacity();
139    case CSSPropertyFontSize:
140        // CSSPropertyFontSize: Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size
141        // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
142        // FIXME: Should we introduce an option to pass the computed font size here, allowing consumers to
143        // enable text zoom rather than Text Autosizing? See http://crbug.com/227545.
144        return a.specifiedFontSize() == b.specifiedFontSize();
145    case CSSPropertyFontStretch:
146        return a.fontStretch() == b.fontStretch();
147    case CSSPropertyFontWeight:
148        return a.fontWeight() == b.fontWeight();
149    case CSSPropertyHeight:
150        return a.height() == b.height();
151    case CSSPropertyLeft:
152        return a.left() == b.left();
153    case CSSPropertyLetterSpacing:
154        return a.letterSpacing() == b.letterSpacing();
155    case CSSPropertyLightingColor:
156        return a.lightingColor() == b.lightingColor();
157    case CSSPropertyLineHeight:
158        return a.specifiedLineHeight() == b.specifiedLineHeight();
159    case CSSPropertyListStyleImage:
160        return dataEquivalent(a.listStyleImage(), b.listStyleImage());
161    case CSSPropertyMarginBottom:
162        return a.marginBottom() == b.marginBottom();
163    case CSSPropertyMarginLeft:
164        return a.marginLeft() == b.marginLeft();
165    case CSSPropertyMarginRight:
166        return a.marginRight() == b.marginRight();
167    case CSSPropertyMarginTop:
168        return a.marginTop() == b.marginTop();
169    case CSSPropertyMaxHeight:
170        return a.maxHeight() == b.maxHeight();
171    case CSSPropertyMaxWidth:
172        return a.maxWidth() == b.maxWidth();
173    case CSSPropertyMinHeight:
174        return a.minHeight() == b.minHeight();
175    case CSSPropertyMinWidth:
176        return a.minWidth() == b.minWidth();
177    case CSSPropertyObjectPosition:
178        return a.objectPosition() == b.objectPosition();
179    case CSSPropertyOpacity:
180        return a.opacity() == b.opacity();
181    case CSSPropertyOrphans:
182        return a.orphans() == b.orphans();
183    case CSSPropertyOutlineColor:
184        return a.outlineColor() == b.outlineColor()
185            && a.visitedLinkOutlineColor() == b.visitedLinkOutlineColor();
186    case CSSPropertyOutlineOffset:
187        return a.outlineOffset() == b.outlineOffset();
188    case CSSPropertyOutlineWidth:
189        return a.outlineWidth() == b.outlineWidth();
190    case CSSPropertyPaddingBottom:
191        return a.paddingBottom() == b.paddingBottom();
192    case CSSPropertyPaddingLeft:
193        return a.paddingLeft() == b.paddingLeft();
194    case CSSPropertyPaddingRight:
195        return a.paddingRight() == b.paddingRight();
196    case CSSPropertyPaddingTop:
197        return a.paddingTop() == b.paddingTop();
198    case CSSPropertyRight:
199        return a.right() == b.right();
200    case CSSPropertyShapeImageThreshold:
201        return a.shapeImageThreshold() == b.shapeImageThreshold();
202    case CSSPropertyShapeMargin:
203        return a.shapeMargin() == b.shapeMargin();
204    case CSSPropertyShapeOutside:
205        return dataEquivalent(a.shapeOutside(), b.shapeOutside());
206    case CSSPropertyStopColor:
207        return a.stopColor() == b.stopColor();
208    case CSSPropertyStopOpacity:
209        return a.stopOpacity() == b.stopOpacity();
210    case CSSPropertyStroke: {
211        const SVGRenderStyle& aSVG = a.svgStyle();
212        const SVGRenderStyle& bSVG = b.svgStyle();
213        return aSVG.strokePaintType() == bSVG.strokePaintType()
214            && (aSVG.strokePaintType() != SVG_PAINTTYPE_RGBCOLOR || aSVG.strokePaintColor() == bSVG.strokePaintColor())
215            && aSVG.visitedLinkStrokePaintType() == bSVG.visitedLinkStrokePaintType()
216            && (aSVG.visitedLinkStrokePaintType() != SVG_PAINTTYPE_RGBCOLOR || aSVG.visitedLinkStrokePaintColor() == bSVG.visitedLinkStrokePaintColor());
217    }
218    case CSSPropertyStrokeDasharray:
219        return dataEquivalent(a.strokeDashArray(), b.strokeDashArray());
220    case CSSPropertyStrokeDashoffset:
221        return dataEquivalent(a.strokeDashOffset(), b.strokeDashOffset());
222    case CSSPropertyStrokeMiterlimit:
223        return a.strokeMiterLimit() == b.strokeMiterLimit();
224    case CSSPropertyStrokeOpacity:
225        return a.strokeOpacity() == b.strokeOpacity();
226    case CSSPropertyStrokeWidth:
227        return dataEquivalent(a.strokeWidth(), b.strokeWidth());
228    case CSSPropertyTextDecorationColor:
229        return a.textDecorationColor() == b.textDecorationColor()
230            && a.visitedLinkTextDecorationColor() == b.visitedLinkTextDecorationColor();
231    case CSSPropertyTextIndent:
232        return a.textIndent() == b.textIndent();
233    case CSSPropertyTextShadow:
234        return dataEquivalent(a.textShadow(), b.textShadow());
235    case CSSPropertyTop:
236        return a.top() == b.top();
237    case CSSPropertyVerticalAlign:
238        return a.verticalAlign() == b.verticalAlign()
239            && (a.verticalAlign() != LENGTH || a.verticalAlignLength() == b.verticalAlignLength());
240    case CSSPropertyVisibility:
241        return a.visibility() == b.visibility();
242    case CSSPropertyWebkitBackgroundSize:
243        return fillLayersEqual<CSSPropertyWebkitBackgroundSize>(a.backgroundLayers(), b.backgroundLayers());
244    case CSSPropertyWebkitBorderHorizontalSpacing:
245        return a.horizontalBorderSpacing() == b.horizontalBorderSpacing();
246    case CSSPropertyWebkitBorderVerticalSpacing:
247        return a.verticalBorderSpacing() == b.verticalBorderSpacing();
248    case CSSPropertyWebkitBoxShadow:
249        return dataEquivalent(a.boxShadow(), b.boxShadow());
250    case CSSPropertyWebkitClipPath:
251        return dataEquivalent(a.clipPath(), b.clipPath());
252    case CSSPropertyWebkitColumnCount:
253        return a.columnCount() == b.columnCount();
254    case CSSPropertyWebkitColumnGap:
255        return a.columnGap() == b.columnGap();
256    case CSSPropertyWebkitColumnRuleColor:
257        return a.columnRuleColor() == b.columnRuleColor()
258            && a.visitedLinkColumnRuleColor() == b.visitedLinkColumnRuleColor();
259    case CSSPropertyWebkitColumnRuleWidth:
260        return a.columnRuleWidth() == b.columnRuleWidth();
261    case CSSPropertyWebkitColumnWidth:
262        return a.columnWidth() == b.columnWidth();
263    case CSSPropertyWebkitFilter:
264        return a.filter() == b.filter();
265    case CSSPropertyWebkitMaskBoxImageOutset:
266        return a.maskBoxImageOutset() == b.maskBoxImageOutset();
267    case CSSPropertyWebkitMaskBoxImageSlice:
268        return a.maskBoxImageSlices() == b.maskBoxImageSlices();
269    case CSSPropertyWebkitMaskBoxImageSource:
270        return dataEquivalent(a.maskBoxImageSource(), b.maskBoxImageSource());
271    case CSSPropertyWebkitMaskBoxImageWidth:
272        return a.maskBoxImageWidth() == b.maskBoxImageWidth();
273    case CSSPropertyWebkitMaskImage:
274        return dataEquivalent(a.maskImage(), b.maskImage());
275    case CSSPropertyWebkitMaskPositionX:
276        return fillLayersEqual<CSSPropertyWebkitMaskPositionX>(a.maskLayers(), b.maskLayers());
277    case CSSPropertyWebkitMaskPositionY:
278        return fillLayersEqual<CSSPropertyWebkitMaskPositionY>(a.maskLayers(), b.maskLayers());
279    case CSSPropertyWebkitMaskSize:
280        return fillLayersEqual<CSSPropertyWebkitMaskSize>(a.maskLayers(), b.maskLayers());
281    case CSSPropertyPerspective:
282        return a.perspective() == b.perspective();
283    case CSSPropertyPerspectiveOrigin:
284        return a.perspectiveOriginX() == b.perspectiveOriginX() && a.perspectiveOriginY() == b.perspectiveOriginY();
285    case CSSPropertyWebkitTextStrokeColor:
286        return a.textStrokeColor() == b.textStrokeColor()
287            && a.visitedLinkTextStrokeColor() == b.visitedLinkTextStrokeColor();
288    case CSSPropertyTransform:
289        return a.transform() == b.transform();
290    case CSSPropertyTransformOrigin:
291        return a.transformOriginX() == b.transformOriginX() && a.transformOriginY() == b.transformOriginY() && a.transformOriginZ() == b.transformOriginZ();
292    case CSSPropertyWidows:
293        return a.widows() == b.widows();
294    case CSSPropertyWidth:
295        return a.width() == b.width();
296    case CSSPropertyWordSpacing:
297        return a.wordSpacing() == b.wordSpacing();
298    case CSSPropertyZIndex:
299        return a.zIndex() == b.zIndex();
300    case CSSPropertyZoom:
301        return a.zoom() == b.zoom();
302    default:
303        ASSERT_NOT_REACHED();
304        return true;
305    }
306}
307
308}
309