| 1 | /* |
| 2 | Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> |
| 3 | 2004, 2005, 2010 Rob Buis <buis@kde.org> |
| 4 | Copyright (C) Research In Motion Limited 2010. All rights reserved. |
| 5 | |
| 6 | Based on khtml code by: |
| 7 | Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 8 | Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) |
| 9 | Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org) |
| 10 | Copyright (C) 2002 Apple Inc. |
| 11 | |
| 12 | This library is free software; you can redistribute it and/or |
| 13 | modify it under the terms of the GNU Library General Public |
| 14 | License as published by the Free Software Foundation; either |
| 15 | version 2 of the License, or (at your option) any later version. |
| 16 | |
| 17 | This library is distributed in the hope that it will be useful, |
| 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 20 | Library General Public License for more details. |
| 21 | |
| 22 | You should have received a copy of the GNU Library General Public License |
| 23 | along with this library; see the file COPYING.LIB. If not, write to |
| 24 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 25 | Boston, MA 02110-1301, USA. |
| 26 | */ |
| 27 | |
| 28 | #include "config.h" |
| 29 | #include "SVGRenderStyle.h" |
| 30 | |
| 31 | #include "CSSPrimitiveValue.h" |
| 32 | #include "CSSValueList.h" |
| 33 | #include "IntRect.h" |
| 34 | #include "NodeRenderStyle.h" |
| 35 | #include "SVGElement.h" |
| 36 | #include <wtf/NeverDestroyed.h> |
| 37 | |
| 38 | namespace WebCore { |
| 39 | |
| 40 | static const SVGRenderStyle& defaultSVGStyle() |
| 41 | { |
| 42 | static NeverDestroyed<DataRef<SVGRenderStyle>> style(SVGRenderStyle::createDefaultStyle()); |
| 43 | return *style.get(); |
| 44 | } |
| 45 | |
| 46 | Ref<SVGRenderStyle> SVGRenderStyle::createDefaultStyle() |
| 47 | { |
| 48 | return adoptRef(*new SVGRenderStyle(CreateDefault)); |
| 49 | } |
| 50 | |
| 51 | SVGRenderStyle::SVGRenderStyle() |
| 52 | : m_fillData(defaultSVGStyle().m_fillData) |
| 53 | , m_strokeData(defaultSVGStyle().m_strokeData) |
| 54 | , m_textData(defaultSVGStyle().m_textData) |
| 55 | , m_inheritedResourceData(defaultSVGStyle().m_inheritedResourceData) |
| 56 | , m_stopData(defaultSVGStyle().m_stopData) |
| 57 | , m_miscData(defaultSVGStyle().m_miscData) |
| 58 | , m_shadowData(defaultSVGStyle().m_shadowData) |
| 59 | , m_layoutData(defaultSVGStyle().m_layoutData) |
| 60 | , m_nonInheritedResourceData(defaultSVGStyle().m_nonInheritedResourceData) |
| 61 | { |
| 62 | setBitDefaults(); |
| 63 | } |
| 64 | |
| 65 | SVGRenderStyle::SVGRenderStyle(CreateDefaultType) |
| 66 | : m_fillData(StyleFillData::create()) |
| 67 | , m_strokeData(StyleStrokeData::create()) |
| 68 | , m_textData(StyleTextData::create()) |
| 69 | , m_inheritedResourceData(StyleInheritedResourceData::create()) |
| 70 | , m_stopData(StyleStopData::create()) |
| 71 | , m_miscData(StyleMiscData::create()) |
| 72 | , m_shadowData(StyleShadowSVGData::create()) |
| 73 | , m_layoutData(StyleLayoutData::create()) |
| 74 | , m_nonInheritedResourceData(StyleResourceData::create()) |
| 75 | { |
| 76 | setBitDefaults(); |
| 77 | } |
| 78 | |
| 79 | inline SVGRenderStyle::SVGRenderStyle(const SVGRenderStyle& other) |
| 80 | : RefCounted<SVGRenderStyle>() |
| 81 | , m_inheritedFlags(other.m_inheritedFlags) |
| 82 | , m_nonInheritedFlags(other.m_nonInheritedFlags) |
| 83 | , m_fillData(other.m_fillData) |
| 84 | , m_strokeData(other.m_strokeData) |
| 85 | , m_textData(other.m_textData) |
| 86 | , m_inheritedResourceData(other.m_inheritedResourceData) |
| 87 | , m_stopData(other.m_stopData) |
| 88 | , m_miscData(other.m_miscData) |
| 89 | , m_shadowData(other.m_shadowData) |
| 90 | , m_layoutData(other.m_layoutData) |
| 91 | , m_nonInheritedResourceData(other.m_nonInheritedResourceData) |
| 92 | { |
| 93 | } |
| 94 | |
| 95 | Ref<SVGRenderStyle> SVGRenderStyle::copy() const |
| 96 | { |
| 97 | return adoptRef(*new SVGRenderStyle(*this)); |
| 98 | } |
| 99 | |
| 100 | SVGRenderStyle::~SVGRenderStyle() = default; |
| 101 | |
| 102 | bool SVGRenderStyle::operator==(const SVGRenderStyle& other) const |
| 103 | { |
| 104 | return m_fillData == other.m_fillData |
| 105 | && m_strokeData == other.m_strokeData |
| 106 | && m_textData == other.m_textData |
| 107 | && m_stopData == other.m_stopData |
| 108 | && m_miscData == other.m_miscData |
| 109 | && m_shadowData == other.m_shadowData |
| 110 | && m_layoutData == other.m_layoutData |
| 111 | && m_inheritedResourceData == other.m_inheritedResourceData |
| 112 | && m_nonInheritedResourceData == other.m_nonInheritedResourceData |
| 113 | && m_inheritedFlags == other.m_inheritedFlags |
| 114 | && m_nonInheritedFlags == other.m_nonInheritedFlags; |
| 115 | } |
| 116 | |
| 117 | bool SVGRenderStyle::inheritedNotEqual(const SVGRenderStyle& other) const |
| 118 | { |
| 119 | return m_fillData != other.m_fillData |
| 120 | || m_strokeData != other.m_strokeData |
| 121 | || m_textData != other.m_textData |
| 122 | || m_inheritedResourceData != other.m_inheritedResourceData |
| 123 | || m_inheritedFlags != other.m_inheritedFlags; |
| 124 | } |
| 125 | |
| 126 | void SVGRenderStyle::inheritFrom(const SVGRenderStyle& other) |
| 127 | { |
| 128 | m_fillData = other.m_fillData; |
| 129 | m_strokeData = other.m_strokeData; |
| 130 | m_textData = other.m_textData; |
| 131 | m_inheritedResourceData = other.m_inheritedResourceData; |
| 132 | |
| 133 | m_inheritedFlags = other.m_inheritedFlags; |
| 134 | } |
| 135 | |
| 136 | void SVGRenderStyle::copyNonInheritedFrom(const SVGRenderStyle& other) |
| 137 | { |
| 138 | m_nonInheritedFlags = other.m_nonInheritedFlags; |
| 139 | m_stopData = other.m_stopData; |
| 140 | m_miscData = other.m_miscData; |
| 141 | m_shadowData = other.m_shadowData; |
| 142 | m_layoutData = other.m_layoutData; |
| 143 | m_nonInheritedResourceData = other.m_nonInheritedResourceData; |
| 144 | } |
| 145 | |
| 146 | StyleDifference SVGRenderStyle::diff(const SVGRenderStyle& other) const |
| 147 | { |
| 148 | // NOTE: All comparisions that may return StyleDifference::Layout have to go before those who return StyleDifference::Repaint |
| 149 | |
| 150 | // If kerning changes, we need a relayout, to force SVGCharacterData to be recalculated in the SVGRootInlineBox. |
| 151 | if (m_textData != other.m_textData) |
| 152 | return StyleDifference::Layout; |
| 153 | |
| 154 | // If resources change, we need a relayout, as the presence of resources influences the repaint rect. |
| 155 | if (m_nonInheritedResourceData != other.m_nonInheritedResourceData) |
| 156 | return StyleDifference::Layout; |
| 157 | |
| 158 | // If markers change, we need a relayout, as marker boundaries are cached in RenderSVGPath. |
| 159 | if (m_inheritedResourceData != other.m_inheritedResourceData) |
| 160 | return StyleDifference::Layout; |
| 161 | |
| 162 | // All text related properties influence layout. |
| 163 | if (m_inheritedFlags.textAnchor != other.m_inheritedFlags.textAnchor |
| 164 | || m_inheritedFlags.glyphOrientationHorizontal != other.m_inheritedFlags.glyphOrientationHorizontal |
| 165 | || m_inheritedFlags.glyphOrientationVertical != other.m_inheritedFlags.glyphOrientationVertical |
| 166 | || m_nonInheritedFlags.flagBits.alignmentBaseline != other.m_nonInheritedFlags.flagBits.alignmentBaseline |
| 167 | || m_nonInheritedFlags.flagBits.dominantBaseline != other.m_nonInheritedFlags.flagBits.dominantBaseline |
| 168 | || m_nonInheritedFlags.flagBits.baselineShift != other.m_nonInheritedFlags.flagBits.baselineShift) |
| 169 | return StyleDifference::Layout; |
| 170 | |
| 171 | // Text related properties influence layout. |
| 172 | bool miscNotEqual = m_miscData != other.m_miscData; |
| 173 | if (miscNotEqual && m_miscData->baselineShiftValue != other.m_miscData->baselineShiftValue) |
| 174 | return StyleDifference::Layout; |
| 175 | |
| 176 | // Shadow changes require relayouts, as they affect the repaint rects. |
| 177 | if (m_shadowData != other.m_shadowData) |
| 178 | return StyleDifference::Layout; |
| 179 | |
| 180 | // The x or y properties require relayout. |
| 181 | if (m_layoutData != other.m_layoutData) |
| 182 | return StyleDifference::Layout; |
| 183 | |
| 184 | // Some stroke properties, requires relayouts, as the cached stroke boundaries need to be recalculated. |
| 185 | if (m_strokeData != other.m_strokeData) { |
| 186 | if (m_strokeData->paintType != other.m_strokeData->paintType |
| 187 | || m_strokeData->paintColor != other.m_strokeData->paintColor |
| 188 | || m_strokeData->paintUri != other.m_strokeData->paintUri |
| 189 | || m_strokeData->dashArray != other.m_strokeData->dashArray |
| 190 | || m_strokeData->dashOffset != other.m_strokeData->dashOffset |
| 191 | || m_strokeData->visitedLinkPaintColor != other.m_strokeData->visitedLinkPaintColor |
| 192 | || m_strokeData->visitedLinkPaintUri != other.m_strokeData->visitedLinkPaintUri |
| 193 | || m_strokeData->visitedLinkPaintType != other.m_strokeData->visitedLinkPaintType) |
| 194 | return StyleDifference::Layout; |
| 195 | |
| 196 | // Only the stroke-opacity case remains, where we only need a repaint. |
| 197 | ASSERT(m_strokeData->opacity != other.m_strokeData->opacity); |
| 198 | return StyleDifference::Repaint; |
| 199 | } |
| 200 | |
| 201 | // vector-effect changes require a re-layout. |
| 202 | if (m_nonInheritedFlags.flagBits.vectorEffect != other.m_nonInheritedFlags.flagBits.vectorEffect) |
| 203 | return StyleDifference::Layout; |
| 204 | |
| 205 | // NOTE: All comparisions below may only return StyleDifference::Repaint |
| 206 | |
| 207 | // Painting related properties only need repaints. |
| 208 | if (miscNotEqual) { |
| 209 | if (m_miscData->floodColor != other.m_miscData->floodColor |
| 210 | || m_miscData->floodOpacity != other.m_miscData->floodOpacity |
| 211 | || m_miscData->lightingColor != other.m_miscData->lightingColor) |
| 212 | return StyleDifference::Repaint; |
| 213 | } |
| 214 | |
| 215 | // If fill data changes, we just need to repaint. Fill boundaries are not influenced by this, only by the Path, that RenderSVGPath contains. |
| 216 | if (m_fillData->paintType != other.m_fillData->paintType || m_fillData->paintColor != other.m_fillData->paintColor |
| 217 | || m_fillData->paintUri != other.m_fillData->paintUri || m_fillData->opacity != other.m_fillData->opacity) |
| 218 | return StyleDifference::Repaint; |
| 219 | |
| 220 | // If gradient stops change, we just need to repaint. Style updates are already handled through RenderSVGGradientSTop. |
| 221 | if (m_stopData != other.m_stopData) |
| 222 | return StyleDifference::Repaint; |
| 223 | |
| 224 | // Changes of these flags only cause repaints. |
| 225 | if (m_inheritedFlags.colorRendering != other.m_inheritedFlags.colorRendering |
| 226 | || m_inheritedFlags.shapeRendering != other.m_inheritedFlags.shapeRendering |
| 227 | || m_inheritedFlags.clipRule != other.m_inheritedFlags.clipRule |
| 228 | || m_inheritedFlags.fillRule != other.m_inheritedFlags.fillRule |
| 229 | || m_inheritedFlags.colorInterpolation != other.m_inheritedFlags.colorInterpolation |
| 230 | || m_inheritedFlags.colorInterpolationFilters != other.m_inheritedFlags.colorInterpolationFilters) |
| 231 | return StyleDifference::Repaint; |
| 232 | |
| 233 | if (m_nonInheritedFlags.flagBits.bufferedRendering != other.m_nonInheritedFlags.flagBits.bufferedRendering) |
| 234 | return StyleDifference::Repaint; |
| 235 | |
| 236 | if (m_nonInheritedFlags.flagBits.maskType != other.m_nonInheritedFlags.flagBits.maskType) |
| 237 | return StyleDifference::Repaint; |
| 238 | |
| 239 | return StyleDifference::Equal; |
| 240 | } |
| 241 | |
| 242 | } |
| 243 | |