|
1 /* |
|
2 * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) |
|
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. |
|
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 |
|
22 #include "config.h" |
|
23 #include "RenderStyle.h" |
|
24 |
|
25 #include "CSSPropertyNames.h" |
|
26 #include "CSSStyleSelector.h" |
|
27 #include "CachedImage.h" |
|
28 #include "CounterContent.h" |
|
29 #include "FontSelector.h" |
|
30 #include "RenderArena.h" |
|
31 #include "RenderObject.h" |
|
32 #include "StyleImage.h" |
|
33 #include <wtf/StdLibExtras.h> |
|
34 #include <algorithm> |
|
35 |
|
36 using namespace std; |
|
37 |
|
38 namespace WebCore { |
|
39 |
|
40 inline RenderStyle* defaultStyle() |
|
41 { |
|
42 static RenderStyle* s_defaultStyle = RenderStyle::createDefaultStyle().releaseRef(); |
|
43 return s_defaultStyle; |
|
44 } |
|
45 |
|
46 PassRefPtr<RenderStyle> RenderStyle::create() |
|
47 { |
|
48 return adoptRef(new RenderStyle()); |
|
49 } |
|
50 |
|
51 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle() |
|
52 { |
|
53 return adoptRef(new RenderStyle(true)); |
|
54 } |
|
55 |
|
56 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other) |
|
57 { |
|
58 return adoptRef(new RenderStyle(*other)); |
|
59 } |
|
60 |
|
61 ALWAYS_INLINE RenderStyle::RenderStyle() |
|
62 : m_affectedByAttributeSelectors(false) |
|
63 , m_unique(false) |
|
64 , m_affectedByEmpty(false) |
|
65 , m_emptyState(false) |
|
66 , m_childrenAffectedByFirstChildRules(false) |
|
67 , m_childrenAffectedByLastChildRules(false) |
|
68 , m_childrenAffectedByDirectAdjacentRules(false) |
|
69 , m_childrenAffectedByForwardPositionalRules(false) |
|
70 , m_childrenAffectedByBackwardPositionalRules(false) |
|
71 , m_firstChildState(false) |
|
72 , m_lastChildState(false) |
|
73 , m_childIndex(0) |
|
74 , m_box(defaultStyle()->m_box) |
|
75 , visual(defaultStyle()->visual) |
|
76 , m_background(defaultStyle()->m_background) |
|
77 , surround(defaultStyle()->surround) |
|
78 , rareNonInheritedData(defaultStyle()->rareNonInheritedData) |
|
79 , rareInheritedData(defaultStyle()->rareInheritedData) |
|
80 , inherited(defaultStyle()->inherited) |
|
81 #if ENABLE(SVG) |
|
82 , m_svgStyle(defaultStyle()->m_svgStyle) |
|
83 #endif |
|
84 { |
|
85 setBitDefaults(); // Would it be faster to copy this from the default style? |
|
86 } |
|
87 |
|
88 ALWAYS_INLINE RenderStyle::RenderStyle(bool) |
|
89 : m_affectedByAttributeSelectors(false) |
|
90 , m_unique(false) |
|
91 , m_affectedByEmpty(false) |
|
92 , m_emptyState(false) |
|
93 , m_childrenAffectedByFirstChildRules(false) |
|
94 , m_childrenAffectedByLastChildRules(false) |
|
95 , m_childrenAffectedByDirectAdjacentRules(false) |
|
96 , m_childrenAffectedByForwardPositionalRules(false) |
|
97 , m_childrenAffectedByBackwardPositionalRules(false) |
|
98 , m_firstChildState(false) |
|
99 , m_lastChildState(false) |
|
100 , m_childIndex(0) |
|
101 { |
|
102 setBitDefaults(); |
|
103 |
|
104 m_box.init(); |
|
105 visual.init(); |
|
106 m_background.init(); |
|
107 surround.init(); |
|
108 rareNonInheritedData.init(); |
|
109 rareNonInheritedData.access()->flexibleBox.init(); |
|
110 rareNonInheritedData.access()->marquee.init(); |
|
111 rareNonInheritedData.access()->m_multiCol.init(); |
|
112 rareNonInheritedData.access()->m_transform.init(); |
|
113 rareInheritedData.init(); |
|
114 inherited.init(); |
|
115 |
|
116 #if ENABLE(SVG) |
|
117 m_svgStyle.init(); |
|
118 #endif |
|
119 } |
|
120 |
|
121 ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o) |
|
122 : RefCounted<RenderStyle>() |
|
123 , m_affectedByAttributeSelectors(false) |
|
124 , m_unique(false) |
|
125 , m_affectedByEmpty(false) |
|
126 , m_emptyState(false) |
|
127 , m_childrenAffectedByFirstChildRules(false) |
|
128 , m_childrenAffectedByLastChildRules(false) |
|
129 , m_childrenAffectedByDirectAdjacentRules(false) |
|
130 , m_childrenAffectedByForwardPositionalRules(false) |
|
131 , m_childrenAffectedByBackwardPositionalRules(false) |
|
132 , m_firstChildState(false) |
|
133 , m_lastChildState(false) |
|
134 , m_childIndex(0) |
|
135 , m_box(o.m_box) |
|
136 , visual(o.visual) |
|
137 , m_background(o.m_background) |
|
138 , surround(o.surround) |
|
139 , rareNonInheritedData(o.rareNonInheritedData) |
|
140 , rareInheritedData(o.rareInheritedData) |
|
141 , inherited(o.inherited) |
|
142 #if ENABLE(SVG) |
|
143 , m_svgStyle(o.m_svgStyle) |
|
144 #endif |
|
145 , inherited_flags(o.inherited_flags) |
|
146 , noninherited_flags(o.noninherited_flags) |
|
147 { |
|
148 } |
|
149 |
|
150 void RenderStyle::inheritFrom(const RenderStyle* inheritParent) |
|
151 { |
|
152 rareInheritedData = inheritParent->rareInheritedData; |
|
153 inherited = inheritParent->inherited; |
|
154 inherited_flags = inheritParent->inherited_flags; |
|
155 #if ENABLE(SVG) |
|
156 if (m_svgStyle != inheritParent->m_svgStyle) |
|
157 m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get()); |
|
158 #endif |
|
159 } |
|
160 |
|
161 RenderStyle::~RenderStyle() |
|
162 { |
|
163 } |
|
164 |
|
165 bool RenderStyle::operator==(const RenderStyle& o) const |
|
166 { |
|
167 // compare everything except the pseudoStyle pointer |
|
168 return inherited_flags == o.inherited_flags && |
|
169 noninherited_flags == o.noninherited_flags && |
|
170 m_box == o.m_box && |
|
171 visual == o.visual && |
|
172 m_background == o.m_background && |
|
173 surround == o.surround && |
|
174 rareNonInheritedData == o.rareNonInheritedData && |
|
175 rareInheritedData == o.rareInheritedData && |
|
176 inherited == o.inherited |
|
177 #if ENABLE(SVG) |
|
178 && m_svgStyle == o.m_svgStyle |
|
179 #endif |
|
180 ; |
|
181 } |
|
182 |
|
183 bool RenderStyle::isStyleAvailable() const |
|
184 { |
|
185 return this != CSSStyleSelector::styleNotYetAvailable(); |
|
186 } |
|
187 |
|
188 static inline int pseudoBit(PseudoId pseudo) |
|
189 { |
|
190 return 1 << (pseudo - 1); |
|
191 } |
|
192 |
|
193 bool RenderStyle::hasAnyPublicPseudoStyles() const |
|
194 { |
|
195 return PUBLIC_PSEUDOID_MASK & noninherited_flags._pseudoBits; |
|
196 } |
|
197 |
|
198 bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const |
|
199 { |
|
200 ASSERT(pseudo > NOPSEUDO); |
|
201 ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID); |
|
202 return pseudoBit(pseudo) & noninherited_flags._pseudoBits; |
|
203 } |
|
204 |
|
205 void RenderStyle::setHasPseudoStyle(PseudoId pseudo) |
|
206 { |
|
207 ASSERT(pseudo > NOPSEUDO); |
|
208 ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID); |
|
209 noninherited_flags._pseudoBits |= pseudoBit(pseudo); |
|
210 } |
|
211 |
|
212 RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const |
|
213 { |
|
214 ASSERT(styleType() != VISITED_LINK); |
|
215 |
|
216 if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size()) |
|
217 return 0; |
|
218 |
|
219 if (styleType() != NOPSEUDO) { |
|
220 if (pid == VISITED_LINK) |
|
221 return m_cachedPseudoStyles->at(0)->styleType() == VISITED_LINK ? m_cachedPseudoStyles->at(0).get() : 0; |
|
222 return 0; |
|
223 } |
|
224 |
|
225 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) { |
|
226 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get(); |
|
227 if (pseudoStyle->styleType() == pid) |
|
228 return pseudoStyle; |
|
229 } |
|
230 |
|
231 return 0; |
|
232 } |
|
233 |
|
234 RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo) |
|
235 { |
|
236 if (!pseudo) |
|
237 return 0; |
|
238 |
|
239 RenderStyle* result = pseudo.get(); |
|
240 |
|
241 if (!m_cachedPseudoStyles) |
|
242 m_cachedPseudoStyles.set(new PseudoStyleCache); |
|
243 |
|
244 m_cachedPseudoStyles->append(pseudo); |
|
245 |
|
246 return result; |
|
247 } |
|
248 |
|
249 bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const |
|
250 { |
|
251 return inherited_flags != other->inherited_flags || |
|
252 inherited != other->inherited || |
|
253 #if ENABLE(SVG) |
|
254 m_svgStyle->inheritedNotEqual(other->m_svgStyle.get()) || |
|
255 #endif |
|
256 rareInheritedData != other->rareInheritedData; |
|
257 } |
|
258 |
|
259 static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b) |
|
260 { |
|
261 // If any unit types are different, then we can't guarantee |
|
262 // that this was just a movement. |
|
263 if (a.left().type() != b.left().type() || |
|
264 a.right().type() != b.right().type() || |
|
265 a.top().type() != b.top().type() || |
|
266 a.bottom().type() != b.bottom().type()) |
|
267 return false; |
|
268 |
|
269 // Only one unit can be non-auto in the horizontal direction and |
|
270 // in the vertical direction. Otherwise the adjustment of values |
|
271 // is changing the size of the box. |
|
272 if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto()) |
|
273 return false; |
|
274 if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto()) |
|
275 return false; |
|
276 |
|
277 // One of the units is fixed or percent in both directions and stayed |
|
278 // that way in the new style. Therefore all we are doing is moving. |
|
279 return true; |
|
280 } |
|
281 |
|
282 /* |
|
283 compares two styles. The result gives an idea of the action that |
|
284 needs to be taken when replacing the old style with a new one. |
|
285 |
|
286 CbLayout: The containing block of the object needs a relayout. |
|
287 Layout: the RenderObject needs a relayout after the style change |
|
288 Visible: The change is visible, but no relayout is needed |
|
289 NonVisible: The object does need neither repaint nor relayout after |
|
290 the change. |
|
291 |
|
292 ### TODO: |
|
293 A lot can be optimised here based on the display type, lots of |
|
294 optimisations are unimplemented, and currently result in the |
|
295 worst case result causing a relayout of the containing block. |
|
296 */ |
|
297 StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const |
|
298 { |
|
299 changedContextSensitiveProperties = ContextSensitivePropertyNone; |
|
300 |
|
301 #if ENABLE(SVG) |
|
302 if (m_svgStyle != other->m_svgStyle) |
|
303 return m_svgStyle->diff(other->m_svgStyle.get()); |
|
304 #endif |
|
305 |
|
306 if (m_box->width() != other->m_box->width() || |
|
307 m_box->minWidth() != other->m_box->minWidth() || |
|
308 m_box->maxWidth() != other->m_box->maxWidth() || |
|
309 m_box->height() != other->m_box->height() || |
|
310 m_box->minHeight() != other->m_box->minHeight() || |
|
311 m_box->maxHeight() != other->m_box->maxHeight()) |
|
312 return StyleDifferenceLayout; |
|
313 |
|
314 if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align) |
|
315 return StyleDifferenceLayout; |
|
316 |
|
317 if (m_box->boxSizing() != other->m_box->boxSizing()) |
|
318 return StyleDifferenceLayout; |
|
319 |
|
320 if (surround->margin != other->surround->margin) |
|
321 return StyleDifferenceLayout; |
|
322 |
|
323 if (surround->padding != other->surround->padding) |
|
324 return StyleDifferenceLayout; |
|
325 |
|
326 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { |
|
327 if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance || |
|
328 rareNonInheritedData->marginTopCollapse != other->rareNonInheritedData->marginTopCollapse || |
|
329 rareNonInheritedData->marginBottomCollapse != other->rareNonInheritedData->marginBottomCollapse || |
|
330 rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp || |
|
331 rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow) |
|
332 return StyleDifferenceLayout; |
|
333 |
|
334 if (rareNonInheritedData->flexibleBox.get() != other->rareNonInheritedData->flexibleBox.get() && |
|
335 *rareNonInheritedData->flexibleBox.get() != *other->rareNonInheritedData->flexibleBox.get()) |
|
336 return StyleDifferenceLayout; |
|
337 |
|
338 // FIXME: We should add an optimized form of layout that just recomputes visual overflow. |
|
339 if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get())) |
|
340 return StyleDifferenceLayout; |
|
341 |
|
342 if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get())) |
|
343 return StyleDifferenceLayout; |
|
344 |
|
345 if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() && |
|
346 *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get()) |
|
347 return StyleDifferenceLayout; |
|
348 |
|
349 if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() && |
|
350 *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) { |
|
351 #if USE(ACCELERATED_COMPOSITING) |
|
352 changedContextSensitiveProperties |= ContextSensitivePropertyTransform; |
|
353 // Don't return; keep looking for another change |
|
354 #else |
|
355 return StyleDifferenceLayout; |
|
356 #endif |
|
357 } |
|
358 |
|
359 #if !USE(ACCELERATED_COMPOSITING) |
|
360 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { |
|
361 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D || |
|
362 rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility || |
|
363 rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective || |
|
364 rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX || |
|
365 rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) |
|
366 return StyleDifferenceLayout; |
|
367 } |
|
368 #endif |
|
369 |
|
370 #if ENABLE(DASHBOARD_SUPPORT) |
|
371 // If regions change, trigger a relayout to re-calc regions. |
|
372 if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions) |
|
373 return StyleDifferenceLayout; |
|
374 #endif |
|
375 } |
|
376 |
|
377 if (rareInheritedData.get() != other->rareInheritedData.get()) { |
|
378 if (rareInheritedData->highlight != other->rareInheritedData->highlight || |
|
379 rareInheritedData->indent != other->rareInheritedData->indent || |
|
380 rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom || |
|
381 rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust || |
|
382 rareInheritedData->wordBreak != other->rareInheritedData->wordBreak || |
|
383 rareInheritedData->wordWrap != other->rareInheritedData->wordWrap || |
|
384 rareInheritedData->nbspMode != other->rareInheritedData->nbspMode || |
|
385 rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak || |
|
386 rareInheritedData->textSecurity != other->rareInheritedData->textSecurity || |
|
387 rareInheritedData->hyphens != other->rareInheritedData->hyphens || |
|
388 rareInheritedData->hyphenateCharacter != other->rareInheritedData->hyphenateCharacter) |
|
389 return StyleDifferenceLayout; |
|
390 |
|
391 if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get())) |
|
392 return StyleDifferenceLayout; |
|
393 |
|
394 if (textStrokeWidth() != other->textStrokeWidth()) |
|
395 return StyleDifferenceLayout; |
|
396 } |
|
397 |
|
398 if (inherited->line_height != other->inherited->line_height || |
|
399 inherited->list_style_image != other->inherited->list_style_image || |
|
400 inherited->font != other->inherited->font || |
|
401 inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing || |
|
402 inherited->vertical_border_spacing != other->inherited->vertical_border_spacing || |
|
403 inherited_flags._box_direction != other->inherited_flags._box_direction || |
|
404 inherited_flags._visuallyOrdered != other->inherited_flags._visuallyOrdered || |
|
405 inherited_flags._htmlHacks != other->inherited_flags._htmlHacks || |
|
406 noninherited_flags._position != other->noninherited_flags._position || |
|
407 noninherited_flags._floating != other->noninherited_flags._floating || |
|
408 noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay) |
|
409 return StyleDifferenceLayout; |
|
410 |
|
411 |
|
412 if (((int)noninherited_flags._effectiveDisplay) >= TABLE) { |
|
413 if (inherited_flags._border_collapse != other->inherited_flags._border_collapse || |
|
414 inherited_flags._empty_cells != other->inherited_flags._empty_cells || |
|
415 inherited_flags._caption_side != other->inherited_flags._caption_side || |
|
416 noninherited_flags._table_layout != other->noninherited_flags._table_layout) |
|
417 return StyleDifferenceLayout; |
|
418 |
|
419 // In the collapsing border model, 'hidden' suppresses other borders, while 'none' |
|
420 // does not, so these style differences can be width differences. |
|
421 if (inherited_flags._border_collapse && |
|
422 ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE) || |
|
423 (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN) || |
|
424 (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE) || |
|
425 (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN) || |
|
426 (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE) || |
|
427 (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN) || |
|
428 (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE) || |
|
429 (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN))) |
|
430 return StyleDifferenceLayout; |
|
431 } |
|
432 |
|
433 if (noninherited_flags._effectiveDisplay == LIST_ITEM) { |
|
434 if (inherited_flags._list_style_type != other->inherited_flags._list_style_type || |
|
435 inherited_flags._list_style_position != other->inherited_flags._list_style_position) |
|
436 return StyleDifferenceLayout; |
|
437 } |
|
438 |
|
439 if (inherited_flags._text_align != other->inherited_flags._text_align || |
|
440 inherited_flags._text_transform != other->inherited_flags._text_transform || |
|
441 inherited_flags._direction != other->inherited_flags._direction || |
|
442 inherited_flags._white_space != other->inherited_flags._white_space || |
|
443 noninherited_flags._clear != other->noninherited_flags._clear) |
|
444 return StyleDifferenceLayout; |
|
445 |
|
446 // Overflow returns a layout hint. |
|
447 if (noninherited_flags._overflowX != other->noninherited_flags._overflowX || |
|
448 noninherited_flags._overflowY != other->noninherited_flags._overflowY) |
|
449 return StyleDifferenceLayout; |
|
450 |
|
451 // If our border widths change, then we need to layout. Other changes to borders |
|
452 // only necessitate a repaint. |
|
453 if (borderLeftWidth() != other->borderLeftWidth() || |
|
454 borderTopWidth() != other->borderTopWidth() || |
|
455 borderBottomWidth() != other->borderBottomWidth() || |
|
456 borderRightWidth() != other->borderRightWidth()) |
|
457 return StyleDifferenceLayout; |
|
458 |
|
459 // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree. |
|
460 const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get(); |
|
461 const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get(); |
|
462 if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB))) |
|
463 return StyleDifferenceLayout; |
|
464 if (rareNonInheritedData->m_counterIncrement != other->rareNonInheritedData->m_counterIncrement || |
|
465 rareNonInheritedData->m_counterReset != other->rareNonInheritedData->m_counterReset) |
|
466 return StyleDifferenceLayout; |
|
467 |
|
468 if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) || |
|
469 (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) { |
|
470 // FIXME: We should add an optimized form of layout that just recomputes visual overflow. |
|
471 return StyleDifferenceLayout; |
|
472 } |
|
473 |
|
474 // Make sure these left/top/right/bottom checks stay below all layout checks and above |
|
475 // all visible checks. |
|
476 if (position() != StaticPosition) { |
|
477 if (surround->offset != other->surround->offset) { |
|
478 // Optimize for the case where a positioned layer is moving but not changing size. |
|
479 if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset)) |
|
480 return StyleDifferenceLayoutPositionedMovementOnly; |
|
481 |
|
482 // FIXME: We will need to do a bit of work in RenderObject/Box::setStyle before we |
|
483 // can stop doing a layout when relative positioned objects move. In particular, we'll need |
|
484 // to update scrolling positions and figure out how to do a repaint properly of the updated layer. |
|
485 //if (other->position() == RelativePosition) |
|
486 // return RepaintLayer; |
|
487 //else |
|
488 return StyleDifferenceLayout; |
|
489 } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() || |
|
490 visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip) |
|
491 return StyleDifferenceRepaintLayer; |
|
492 } |
|
493 |
|
494 if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) { |
|
495 #if USE(ACCELERATED_COMPOSITING) |
|
496 changedContextSensitiveProperties |= ContextSensitivePropertyOpacity; |
|
497 // Don't return; keep looking for another change. |
|
498 #else |
|
499 return StyleDifferenceRepaintLayer; |
|
500 #endif |
|
501 } |
|
502 |
|
503 if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask || |
|
504 rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage) |
|
505 return StyleDifferenceRepaintLayer; |
|
506 |
|
507 if (inherited->color != other->inherited->color || |
|
508 inherited_flags._visibility != other->inherited_flags._visibility || |
|
509 inherited_flags._text_decorations != other->inherited_flags._text_decorations || |
|
510 inherited_flags._force_backgrounds_to_white != other->inherited_flags._force_backgrounds_to_white || |
|
511 inherited_flags._insideLink != other->inherited_flags._insideLink || |
|
512 surround->border != other->surround->border || |
|
513 *m_background.get() != *other->m_background.get() || |
|
514 visual->textDecoration != other->visual->textDecoration || |
|
515 rareInheritedData->userModify != other->rareInheritedData->userModify || |
|
516 rareInheritedData->userSelect != other->rareInheritedData->userSelect || |
|
517 rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag || |
|
518 rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit || |
|
519 rareInheritedData->textFillColor != other->rareInheritedData->textFillColor || |
|
520 rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor) |
|
521 return StyleDifferenceRepaint; |
|
522 |
|
523 #if USE(ACCELERATED_COMPOSITING) |
|
524 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { |
|
525 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D || |
|
526 rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility || |
|
527 rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective || |
|
528 rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX || |
|
529 rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) |
|
530 return StyleDifferenceRecompositeLayer; |
|
531 } |
|
532 #endif |
|
533 |
|
534 // Cursors are not checked, since they will be set appropriately in response to mouse events, |
|
535 // so they don't need to cause any repaint or layout. |
|
536 |
|
537 // Animations don't need to be checked either. We always set the new style on the RenderObject, so we will get a chance to fire off |
|
538 // the resulting transition properly. |
|
539 return StyleDifferenceEqual; |
|
540 } |
|
541 |
|
542 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left) |
|
543 { |
|
544 StyleVisualData* data = visual.access(); |
|
545 data->clip.m_top = top; |
|
546 data->clip.m_right = right; |
|
547 data->clip.m_bottom = bottom; |
|
548 data->clip.m_left = left; |
|
549 } |
|
550 |
|
551 void RenderStyle::addCursor(CachedImage* image, const IntPoint& hotSpot) |
|
552 { |
|
553 if (!rareInheritedData.access()->cursorData) |
|
554 rareInheritedData.access()->cursorData = CursorList::create(); |
|
555 rareInheritedData.access()->cursorData->append(CursorData(image, hotSpot)); |
|
556 } |
|
557 |
|
558 void RenderStyle::setCursorList(PassRefPtr<CursorList> other) |
|
559 { |
|
560 rareInheritedData.access()->cursorData = other; |
|
561 } |
|
562 |
|
563 void RenderStyle::clearCursorList() |
|
564 { |
|
565 if (rareInheritedData->cursorData) |
|
566 rareInheritedData.access()->cursorData = 0; |
|
567 } |
|
568 |
|
569 void RenderStyle::clearContent() |
|
570 { |
|
571 if (rareNonInheritedData->m_content) |
|
572 rareNonInheritedData->m_content->clear(); |
|
573 } |
|
574 |
|
575 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add) |
|
576 { |
|
577 if (!image) |
|
578 return; // The object is null. Nothing to do. Just bail. |
|
579 |
|
580 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; |
|
581 ContentData* lastContent = content.get(); |
|
582 while (lastContent && lastContent->next()) |
|
583 lastContent = lastContent->next(); |
|
584 |
|
585 bool reuseContent = !add; |
|
586 ContentData* newContentData; |
|
587 if (reuseContent && content) { |
|
588 content->clear(); |
|
589 newContentData = content.leakPtr(); |
|
590 } else |
|
591 newContentData = new ContentData; |
|
592 |
|
593 if (lastContent && !reuseContent) |
|
594 lastContent->setNext(newContentData); |
|
595 else |
|
596 content.set(newContentData); |
|
597 |
|
598 newContentData->setImage(image); |
|
599 } |
|
600 |
|
601 void RenderStyle::setContent(PassRefPtr<StringImpl> s, bool add) |
|
602 { |
|
603 if (!s) |
|
604 return; // The string is null. Nothing to do. Just bail. |
|
605 |
|
606 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; |
|
607 ContentData* lastContent = content.get(); |
|
608 while (lastContent && lastContent->next()) |
|
609 lastContent = lastContent->next(); |
|
610 |
|
611 bool reuseContent = !add; |
|
612 if (add && lastContent) { |
|
613 if (lastContent->isText()) { |
|
614 // We can augment the existing string and share this ContentData node. |
|
615 String newStr = lastContent->text(); |
|
616 newStr.append(s.get()); |
|
617 lastContent->setText(newStr.impl()); |
|
618 return; |
|
619 } |
|
620 } |
|
621 |
|
622 ContentData* newContentData = 0; |
|
623 if (reuseContent && content) { |
|
624 content->clear(); |
|
625 newContentData = content.leakPtr(); |
|
626 } else |
|
627 newContentData = new ContentData; |
|
628 |
|
629 if (lastContent && !reuseContent) |
|
630 lastContent->setNext(newContentData); |
|
631 else |
|
632 content.set(newContentData); |
|
633 |
|
634 newContentData->setText(s); |
|
635 } |
|
636 |
|
637 void RenderStyle::setContent(CounterContent* c, bool add) |
|
638 { |
|
639 if (!c) |
|
640 return; |
|
641 |
|
642 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; |
|
643 ContentData* lastContent = content.get(); |
|
644 while (lastContent && lastContent->next()) |
|
645 lastContent = lastContent->next(); |
|
646 |
|
647 bool reuseContent = !add; |
|
648 ContentData* newContentData = 0; |
|
649 if (reuseContent && content) { |
|
650 content->clear(); |
|
651 newContentData = content.leakPtr(); |
|
652 } else |
|
653 newContentData = new ContentData; |
|
654 |
|
655 if (lastContent && !reuseContent) |
|
656 lastContent->setNext(newContentData); |
|
657 else |
|
658 content.set(newContentData); |
|
659 |
|
660 newContentData->setCounter(c); |
|
661 } |
|
662 |
|
663 void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const |
|
664 { |
|
665 // transform-origin brackets the transform with translate operations. |
|
666 // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant |
|
667 // in that case. |
|
668 bool applyTransformOrigin = false; |
|
669 unsigned s = rareNonInheritedData->m_transform->m_operations.operations().size(); |
|
670 unsigned i; |
|
671 if (applyOrigin == IncludeTransformOrigin) { |
|
672 for (i = 0; i < s; i++) { |
|
673 TransformOperation::OperationType type = rareNonInheritedData->m_transform->m_operations.operations()[i]->getOperationType(); |
|
674 if (type != TransformOperation::TRANSLATE_X && |
|
675 type != TransformOperation::TRANSLATE_Y && |
|
676 type != TransformOperation::TRANSLATE && |
|
677 type != TransformOperation::TRANSLATE_Z && |
|
678 type != TransformOperation::TRANSLATE_3D |
|
679 ) { |
|
680 applyTransformOrigin = true; |
|
681 break; |
|
682 } |
|
683 } |
|
684 } |
|
685 |
|
686 if (applyTransformOrigin) { |
|
687 transform.translate3d(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height()), transformOriginZ()); |
|
688 } |
|
689 |
|
690 for (i = 0; i < s; i++) |
|
691 rareNonInheritedData->m_transform->m_operations.operations()[i]->apply(transform, borderBoxSize); |
|
692 |
|
693 if (applyTransformOrigin) { |
|
694 transform.translate3d(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()), -transformOriginZ()); |
|
695 } |
|
696 } |
|
697 |
|
698 #if ENABLE(XBL) |
|
699 void RenderStyle::addBindingURI(StringImpl* uri) |
|
700 { |
|
701 BindingURI* binding = new BindingURI(uri); |
|
702 if (!bindingURIs()) |
|
703 SET_VAR(rareNonInheritedData, bindingURI, binding) |
|
704 else |
|
705 for (BindingURI* b = bindingURIs(); b; b = b->next()) { |
|
706 if (!b->next()) |
|
707 b->setNext(binding); |
|
708 } |
|
709 } |
|
710 #endif |
|
711 |
|
712 void RenderStyle::setTextShadow(ShadowData* val, bool add) |
|
713 { |
|
714 ASSERT(!val || (!val->spread() && val->style() == Normal)); |
|
715 |
|
716 StyleRareInheritedData* rareData = rareInheritedData.access(); |
|
717 if (!add) { |
|
718 delete rareData->textShadow; |
|
719 rareData->textShadow = val; |
|
720 return; |
|
721 } |
|
722 |
|
723 val->setNext(rareData->textShadow); |
|
724 rareData->textShadow = val; |
|
725 } |
|
726 |
|
727 void RenderStyle::setBoxShadow(ShadowData* shadowData, bool add) |
|
728 { |
|
729 StyleRareNonInheritedData* rareData = rareNonInheritedData.access(); |
|
730 if (!add) { |
|
731 rareData->m_boxShadow.set(shadowData); |
|
732 return; |
|
733 } |
|
734 |
|
735 shadowData->setNext(rareData->m_boxShadow.leakPtr()); |
|
736 rareData->m_boxShadow.set(shadowData); |
|
737 } |
|
738 |
|
739 static void constrainCornerRadiiForRect(const IntRect& r, IntSize& topLeft, IntSize& topRight, IntSize& bottomLeft, IntSize& bottomRight) |
|
740 { |
|
741 // Constrain corner radii using CSS3 rules: |
|
742 // http://www.w3.org/TR/css3-background/#the-border-radius |
|
743 |
|
744 float factor = 1; |
|
745 unsigned radiiSum; |
|
746 |
|
747 // top |
|
748 radiiSum = static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()); // Casts to avoid integer overflow. |
|
749 if (radiiSum > static_cast<unsigned>(r.width())) |
|
750 factor = min(static_cast<float>(r.width()) / radiiSum, factor); |
|
751 |
|
752 // bottom |
|
753 radiiSum = static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width()); |
|
754 if (radiiSum > static_cast<unsigned>(r.width())) |
|
755 factor = min(static_cast<float>(r.width()) / radiiSum, factor); |
|
756 |
|
757 // left |
|
758 radiiSum = static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height()); |
|
759 if (radiiSum > static_cast<unsigned>(r.height())) |
|
760 factor = min(static_cast<float>(r.height()) / radiiSum, factor); |
|
761 |
|
762 // right |
|
763 radiiSum = static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height()); |
|
764 if (radiiSum > static_cast<unsigned>(r.height())) |
|
765 factor = min(static_cast<float>(r.height()) / radiiSum, factor); |
|
766 |
|
767 // Scale all radii by f if necessary. |
|
768 if (factor < 1) { |
|
769 // If either radius on a corner becomes zero, reset both radii on that corner. |
|
770 topLeft.scale(factor); |
|
771 if (!topLeft.width() || !topLeft.height()) |
|
772 topLeft = IntSize(); |
|
773 topRight.scale(factor); |
|
774 if (!topRight.width() || !topRight.height()) |
|
775 topRight = IntSize(); |
|
776 bottomLeft.scale(factor); |
|
777 if (!bottomLeft.width() || !bottomLeft.height()) |
|
778 bottomLeft = IntSize(); |
|
779 bottomRight.scale(factor); |
|
780 if (!bottomRight.width() || !bottomRight.height()) |
|
781 bottomRight = IntSize(); |
|
782 } |
|
783 } |
|
784 |
|
785 void RenderStyle::getBorderRadiiForRect(const IntRect& r, IntSize& topLeft, IntSize& topRight, IntSize& bottomLeft, IntSize& bottomRight) const |
|
786 { |
|
787 topLeft = surround->border.topLeft(); |
|
788 topRight = surround->border.topRight(); |
|
789 |
|
790 bottomLeft = surround->border.bottomLeft(); |
|
791 bottomRight = surround->border.bottomRight(); |
|
792 |
|
793 constrainCornerRadiiForRect(r, topLeft, topRight, bottomLeft, bottomRight); |
|
794 } |
|
795 |
|
796 void RenderStyle::getInnerBorderRadiiForRectWithBorderWidths(const IntRect& innerRect, unsigned short topWidth, unsigned short bottomWidth, unsigned short leftWidth, unsigned short rightWidth, IntSize& innerTopLeft, IntSize& innerTopRight, IntSize& innerBottomLeft, IntSize& innerBottomRight) const |
|
797 { |
|
798 innerTopLeft = surround->border.topLeft(); |
|
799 innerTopRight = surround->border.topRight(); |
|
800 innerBottomLeft = surround->border.bottomLeft(); |
|
801 innerBottomRight = surround->border.bottomRight(); |
|
802 |
|
803 innerTopLeft.setWidth(max(0, innerTopLeft.width() - leftWidth)); |
|
804 innerTopLeft.setHeight(max(0, innerTopLeft.height() - topWidth)); |
|
805 |
|
806 innerTopRight.setWidth(max(0, innerTopRight.width() - rightWidth)); |
|
807 innerTopRight.setHeight(max(0, innerTopRight.height() - topWidth)); |
|
808 |
|
809 innerBottomLeft.setWidth(max(0, innerBottomLeft.width() - leftWidth)); |
|
810 innerBottomLeft.setHeight(max(0, innerBottomLeft.height() - bottomWidth)); |
|
811 |
|
812 innerBottomRight.setWidth(max(0, innerBottomRight.width() - rightWidth)); |
|
813 innerBottomRight.setHeight(max(0, innerBottomRight.height() - bottomWidth)); |
|
814 |
|
815 constrainCornerRadiiForRect(innerRect, innerTopLeft, innerTopRight, innerBottomLeft, innerBottomRight); |
|
816 } |
|
817 |
|
818 const CounterDirectiveMap* RenderStyle::counterDirectives() const |
|
819 { |
|
820 return rareNonInheritedData->m_counterDirectives.get(); |
|
821 } |
|
822 |
|
823 CounterDirectiveMap& RenderStyle::accessCounterDirectives() |
|
824 { |
|
825 OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives; |
|
826 if (!map) |
|
827 map.set(new CounterDirectiveMap); |
|
828 return *map.get(); |
|
829 } |
|
830 |
|
831 const AtomicString& RenderStyle::hyphenString() const |
|
832 { |
|
833 ASSERT(hyphens() == HyphensAuto); |
|
834 |
|
835 const AtomicString& hyphenateCharacter = rareInheritedData.get()->hyphenateCharacter; |
|
836 if (!hyphenateCharacter.isNull()) |
|
837 return hyphenateCharacter; |
|
838 |
|
839 // FIXME: This should depend on locale. |
|
840 DEFINE_STATIC_LOCAL(AtomicString, hyphenMinusString, (&hyphen, 1)); |
|
841 return hyphenMinusString; |
|
842 } |
|
843 |
|
844 #if ENABLE(DASHBOARD_SUPPORT) |
|
845 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions() |
|
846 { |
|
847 DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ()); |
|
848 return emptyList; |
|
849 } |
|
850 |
|
851 const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions() |
|
852 { |
|
853 DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, noneList, ()); |
|
854 static bool noneListInitialized = false; |
|
855 |
|
856 if (!noneListInitialized) { |
|
857 StyleDashboardRegion region; |
|
858 region.label = ""; |
|
859 region.offset.m_top = Length(); |
|
860 region.offset.m_right = Length(); |
|
861 region.offset.m_bottom = Length(); |
|
862 region.offset.m_left = Length(); |
|
863 region.type = StyleDashboardRegion::None; |
|
864 noneList.append(region); |
|
865 noneListInitialized = true; |
|
866 } |
|
867 return noneList; |
|
868 } |
|
869 #endif |
|
870 |
|
871 void RenderStyle::adjustAnimations() |
|
872 { |
|
873 AnimationList* animationList = rareNonInheritedData->m_animations.get(); |
|
874 if (!animationList) |
|
875 return; |
|
876 |
|
877 // Get rid of empty animations and anything beyond them |
|
878 for (size_t i = 0; i < animationList->size(); ++i) { |
|
879 if (animationList->animation(i)->isEmpty()) { |
|
880 animationList->resize(i); |
|
881 break; |
|
882 } |
|
883 } |
|
884 |
|
885 if (animationList->isEmpty()) { |
|
886 clearAnimations(); |
|
887 return; |
|
888 } |
|
889 |
|
890 // Repeat patterns into layers that don't have some properties set. |
|
891 animationList->fillUnsetProperties(); |
|
892 } |
|
893 |
|
894 void RenderStyle::adjustTransitions() |
|
895 { |
|
896 AnimationList* transitionList = rareNonInheritedData->m_transitions.get(); |
|
897 if (!transitionList) |
|
898 return; |
|
899 |
|
900 // Get rid of empty transitions and anything beyond them |
|
901 for (size_t i = 0; i < transitionList->size(); ++i) { |
|
902 if (transitionList->animation(i)->isEmpty()) { |
|
903 transitionList->resize(i); |
|
904 break; |
|
905 } |
|
906 } |
|
907 |
|
908 if (transitionList->isEmpty()) { |
|
909 clearTransitions(); |
|
910 return; |
|
911 } |
|
912 |
|
913 // Repeat patterns into layers that don't have some properties set. |
|
914 transitionList->fillUnsetProperties(); |
|
915 |
|
916 // Make sure there are no duplicate properties. This is an O(n^2) algorithm |
|
917 // but the lists tend to be very short, so it is probably ok |
|
918 for (size_t i = 0; i < transitionList->size(); ++i) { |
|
919 for (size_t j = i+1; j < transitionList->size(); ++j) { |
|
920 if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) { |
|
921 // toss i |
|
922 transitionList->remove(i); |
|
923 j = i; |
|
924 } |
|
925 } |
|
926 } |
|
927 } |
|
928 |
|
929 AnimationList* RenderStyle::accessAnimations() |
|
930 { |
|
931 if (!rareNonInheritedData.access()->m_animations) |
|
932 rareNonInheritedData.access()->m_animations.set(new AnimationList()); |
|
933 return rareNonInheritedData->m_animations.get(); |
|
934 } |
|
935 |
|
936 AnimationList* RenderStyle::accessTransitions() |
|
937 { |
|
938 if (!rareNonInheritedData.access()->m_transitions) |
|
939 rareNonInheritedData.access()->m_transitions.set(new AnimationList()); |
|
940 return rareNonInheritedData->m_transitions.get(); |
|
941 } |
|
942 |
|
943 const Animation* RenderStyle::transitionForProperty(int property) const |
|
944 { |
|
945 if (transitions()) { |
|
946 for (size_t i = 0; i < transitions()->size(); ++i) { |
|
947 const Animation* p = transitions()->animation(i); |
|
948 if (p->property() == cAnimateAll || p->property() == property) { |
|
949 return p; |
|
950 } |
|
951 } |
|
952 } |
|
953 return 0; |
|
954 } |
|
955 |
|
956 void RenderStyle::setBlendedFontSize(int size) |
|
957 { |
|
958 FontSelector* currentFontSelector = font().fontSelector(); |
|
959 FontDescription desc(fontDescription()); |
|
960 desc.setSpecifiedSize(size); |
|
961 desc.setComputedSize(size); |
|
962 setFontDescription(desc); |
|
963 font().update(currentFontSelector); |
|
964 } |
|
965 |
|
966 void RenderStyle::getBoxShadowExtent(int &top, int &right, int &bottom, int &left) const |
|
967 { |
|
968 top = 0; |
|
969 right = 0; |
|
970 bottom = 0; |
|
971 left = 0; |
|
972 |
|
973 for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) { |
|
974 if (boxShadow->style() == Inset) |
|
975 continue; |
|
976 int blurAndSpread = boxShadow->blur() + boxShadow->spread(); |
|
977 |
|
978 top = min(top, boxShadow->y() - blurAndSpread); |
|
979 right = max(right, boxShadow->x() + blurAndSpread); |
|
980 bottom = max(bottom, boxShadow->y() + blurAndSpread); |
|
981 left = min(left, boxShadow->x() - blurAndSpread); |
|
982 } |
|
983 } |
|
984 |
|
985 void RenderStyle::getBoxShadowHorizontalExtent(int &left, int &right) const |
|
986 { |
|
987 left = 0; |
|
988 right = 0; |
|
989 |
|
990 for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) { |
|
991 if (boxShadow->style() == Inset) |
|
992 continue; |
|
993 int blurAndSpread = boxShadow->blur() + boxShadow->spread(); |
|
994 |
|
995 left = min(left, boxShadow->x() - blurAndSpread); |
|
996 right = max(right, boxShadow->x() + blurAndSpread); |
|
997 } |
|
998 } |
|
999 |
|
1000 void RenderStyle::getBoxShadowVerticalExtent(int &top, int &bottom) const |
|
1001 { |
|
1002 top = 0; |
|
1003 bottom = 0; |
|
1004 |
|
1005 for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) { |
|
1006 if (boxShadow->style() == Inset) |
|
1007 continue; |
|
1008 int blurAndSpread = boxShadow->blur() + boxShadow->spread(); |
|
1009 |
|
1010 top = min(top, boxShadow->y() - blurAndSpread); |
|
1011 bottom = max(bottom, boxShadow->y() + blurAndSpread); |
|
1012 } |
|
1013 } |
|
1014 |
|
1015 static EBorderStyle borderStyleForColorProperty(const RenderStyle* style, int colorProperty) |
|
1016 { |
|
1017 EBorderStyle borderStyle; |
|
1018 switch (colorProperty) { |
|
1019 case CSSPropertyBorderLeftColor: |
|
1020 borderStyle = style->borderLeftStyle(); |
|
1021 break; |
|
1022 case CSSPropertyBorderRightColor: |
|
1023 borderStyle = style->borderRightStyle(); |
|
1024 break; |
|
1025 case CSSPropertyBorderTopColor: |
|
1026 borderStyle = style->borderTopStyle(); |
|
1027 break; |
|
1028 case CSSPropertyBorderBottomColor: |
|
1029 borderStyle = style->borderBottomStyle(); |
|
1030 break; |
|
1031 default: |
|
1032 borderStyle = BNONE; |
|
1033 break; |
|
1034 } |
|
1035 return borderStyle; |
|
1036 } |
|
1037 |
|
1038 const Color RenderStyle::colorIncludingFallback(int colorProperty, EBorderStyle borderStyle) const |
|
1039 { |
|
1040 Color result; |
|
1041 switch (colorProperty) { |
|
1042 case CSSPropertyBackgroundColor: |
|
1043 return backgroundColor(); // Background color doesn't fall back. |
|
1044 case CSSPropertyBorderLeftColor: |
|
1045 result = borderLeftColor(); |
|
1046 borderStyle = borderLeftStyle(); |
|
1047 break; |
|
1048 case CSSPropertyBorderRightColor: |
|
1049 result = borderRightColor(); |
|
1050 borderStyle = borderRightStyle(); |
|
1051 break; |
|
1052 case CSSPropertyBorderTopColor: |
|
1053 result = borderTopColor(); |
|
1054 borderStyle = borderTopStyle(); |
|
1055 break; |
|
1056 case CSSPropertyBorderBottomColor: |
|
1057 result = borderBottomColor(); |
|
1058 borderStyle = borderBottomStyle(); |
|
1059 break; |
|
1060 case CSSPropertyColor: |
|
1061 result = color(); |
|
1062 break; |
|
1063 case CSSPropertyOutlineColor: |
|
1064 result = outlineColor(); |
|
1065 break; |
|
1066 case CSSPropertyWebkitColumnRuleColor: |
|
1067 result = columnRuleColor(); |
|
1068 break; |
|
1069 case CSSPropertyWebkitTextFillColor: |
|
1070 result = textFillColor(); |
|
1071 break; |
|
1072 case CSSPropertyWebkitTextStrokeColor: |
|
1073 result = textStrokeColor(); |
|
1074 break; |
|
1075 default: |
|
1076 ASSERT_NOT_REACHED(); |
|
1077 break; |
|
1078 } |
|
1079 |
|
1080 if (!result.isValid()) { |
|
1081 if ((colorProperty == CSSPropertyBorderLeftColor || colorProperty == CSSPropertyBorderRightColor |
|
1082 || colorProperty == CSSPropertyBorderTopColor || colorProperty == CSSPropertyBorderBottomColor) |
|
1083 && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE)) |
|
1084 result.setRGB(238, 238, 238); |
|
1085 else |
|
1086 result = color(); |
|
1087 } |
|
1088 |
|
1089 return result; |
|
1090 } |
|
1091 |
|
1092 const Color RenderStyle::visitedDependentColor(int colorProperty) const |
|
1093 { |
|
1094 EBorderStyle borderStyle = borderStyleForColorProperty(this, colorProperty); |
|
1095 Color unvisitedColor = colorIncludingFallback(colorProperty, borderStyle); |
|
1096 if (insideLink() != InsideVisitedLink) |
|
1097 return unvisitedColor; |
|
1098 |
|
1099 RenderStyle* visitedStyle = getCachedPseudoStyle(VISITED_LINK); |
|
1100 if (!visitedStyle) |
|
1101 return unvisitedColor; |
|
1102 Color visitedColor = visitedStyle->colorIncludingFallback(colorProperty, borderStyle); |
|
1103 |
|
1104 // Take the alpha from the unvisited color, but get the RGB values from the visited color. |
|
1105 return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha()); |
|
1106 } |
|
1107 |
|
1108 } // namespace WebCore |