2 * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
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.
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.
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.
23 #include "RenderStyle.h"
25 #include "CSSPropertyNames.h"
26 #include "CSSStyleSelector.h"
27 #include "FontSelector.h"
28 #include "RenderArena.h"
29 #include "RenderObject.h"
30 #include "StyleImage.h"
31 #include <wtf/StdLibExtras.h>
38 inline RenderStyle* defaultStyle()
40 static RenderStyle* s_defaultStyle = RenderStyle::createDefaultStyle().releaseRef();
41 return s_defaultStyle;
44 PassRefPtr<RenderStyle> RenderStyle::create()
46 return adoptRef(new RenderStyle());
49 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle()
51 return adoptRef(new RenderStyle(true));
54 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other)
56 return adoptRef(new RenderStyle(*other));
59 ALWAYS_INLINE RenderStyle::RenderStyle()
60 : m_affectedByAttributeSelectors(false)
62 , m_affectedByEmpty(false)
64 , m_childrenAffectedByFirstChildRules(false)
65 , m_childrenAffectedByLastChildRules(false)
66 , m_childrenAffectedByDirectAdjacentRules(false)
67 , m_childrenAffectedByForwardPositionalRules(false)
68 , m_childrenAffectedByBackwardPositionalRules(false)
69 , m_firstChildState(false)
70 , m_lastChildState(false)
72 , m_box(defaultStyle()->m_box)
73 , visual(defaultStyle()->visual)
74 , m_background(defaultStyle()->m_background)
75 , surround(defaultStyle()->surround)
76 , rareNonInheritedData(defaultStyle()->rareNonInheritedData)
77 , rareInheritedData(defaultStyle()->rareInheritedData)
78 , inherited(defaultStyle()->inherited)
80 , m_svgStyle(defaultStyle()->m_svgStyle)
83 setBitDefaults(); // Would it be faster to copy this from the default style?
86 ALWAYS_INLINE RenderStyle::RenderStyle(bool)
87 : m_affectedByAttributeSelectors(false)
89 , m_affectedByEmpty(false)
91 , m_childrenAffectedByFirstChildRules(false)
92 , m_childrenAffectedByLastChildRules(false)
93 , m_childrenAffectedByDirectAdjacentRules(false)
94 , m_childrenAffectedByForwardPositionalRules(false)
95 , m_childrenAffectedByBackwardPositionalRules(false)
96 , m_firstChildState(false)
97 , m_lastChildState(false)
106 rareNonInheritedData.init();
107 rareNonInheritedData.access()->flexibleBox.init();
108 rareNonInheritedData.access()->marquee.init();
109 rareNonInheritedData.access()->m_multiCol.init();
110 rareNonInheritedData.access()->m_transform.init();
111 rareInheritedData.init();
119 ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o)
120 : RefCounted<RenderStyle>()
121 , m_affectedByAttributeSelectors(false)
123 , m_affectedByEmpty(false)
124 , m_emptyState(false)
125 , m_childrenAffectedByFirstChildRules(false)
126 , m_childrenAffectedByLastChildRules(false)
127 , m_childrenAffectedByDirectAdjacentRules(false)
128 , m_childrenAffectedByForwardPositionalRules(false)
129 , m_childrenAffectedByBackwardPositionalRules(false)
130 , m_firstChildState(false)
131 , m_lastChildState(false)
135 , m_background(o.m_background)
136 , surround(o.surround)
137 , rareNonInheritedData(o.rareNonInheritedData)
138 , rareInheritedData(o.rareInheritedData)
139 , inherited(o.inherited)
141 , m_svgStyle(o.m_svgStyle)
143 , inherited_flags(o.inherited_flags)
144 , noninherited_flags(o.noninherited_flags)
148 void RenderStyle::inheritFrom(const RenderStyle* inheritParent)
150 rareInheritedData = inheritParent->rareInheritedData;
151 inherited = inheritParent->inherited;
152 inherited_flags = inheritParent->inherited_flags;
154 if (m_svgStyle != inheritParent->m_svgStyle)
155 m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get());
159 RenderStyle::~RenderStyle()
163 bool RenderStyle::operator==(const RenderStyle& o) const
165 // compare everything except the pseudoStyle pointer
166 return inherited_flags == o.inherited_flags &&
167 noninherited_flags == o.noninherited_flags &&
169 visual == o.visual &&
170 m_background == o.m_background &&
171 surround == o.surround &&
172 rareNonInheritedData == o.rareNonInheritedData &&
173 rareInheritedData == o.rareInheritedData &&
174 inherited == o.inherited
176 && m_svgStyle == o.m_svgStyle
181 bool RenderStyle::isStyleAvailable() const
183 return this != CSSStyleSelector::styleNotYetAvailable();
186 static inline int pseudoBit(PseudoId pseudo)
188 return 1 << (pseudo - 1);
191 bool RenderStyle::hasAnyPublicPseudoStyles() const
193 return PUBLIC_PSEUDOID_MASK & noninherited_flags._pseudoBits;
196 bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const
198 ASSERT(pseudo > NOPSEUDO);
199 ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
200 return pseudoBit(pseudo) & noninherited_flags._pseudoBits;
203 void RenderStyle::setHasPseudoStyle(PseudoId pseudo)
205 ASSERT(pseudo > NOPSEUDO);
206 ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
207 noninherited_flags._pseudoBits |= pseudoBit(pseudo);
210 RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const
212 ASSERT(styleType() != VISITED_LINK);
214 if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size())
217 if (styleType() != NOPSEUDO) {
218 if (pid == VISITED_LINK)
219 return m_cachedPseudoStyles->at(0)->styleType() == VISITED_LINK ? m_cachedPseudoStyles->at(0).get() : 0;
223 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
224 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
225 if (pseudoStyle->styleType() == pid)
232 RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo)
237 RenderStyle* result = pseudo.get();
239 if (!m_cachedPseudoStyles)
240 m_cachedPseudoStyles.set(new PseudoStyleCache);
242 m_cachedPseudoStyles->append(pseudo);
247 bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const
249 return inherited_flags != other->inherited_flags ||
250 inherited != other->inherited ||
252 m_svgStyle->inheritedNotEqual(other->m_svgStyle.get()) ||
254 rareInheritedData != other->rareInheritedData;
257 static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b)
259 // If any unit types are different, then we can't guarantee
260 // that this was just a movement.
261 if (a.left().type() != b.left().type() ||
262 a.right().type() != b.right().type() ||
263 a.top().type() != b.top().type() ||
264 a.bottom().type() != b.bottom().type())
267 // Only one unit can be non-auto in the horizontal direction and
268 // in the vertical direction. Otherwise the adjustment of values
269 // is changing the size of the box.
270 if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto())
272 if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto())
275 // One of the units is fixed or percent in both directions and stayed
276 // that way in the new style. Therefore all we are doing is moving.
281 compares two styles. The result gives an idea of the action that
282 needs to be taken when replacing the old style with a new one.
284 CbLayout: The containing block of the object needs a relayout.
285 Layout: the RenderObject needs a relayout after the style change
286 Visible: The change is visible, but no relayout is needed
287 NonVisible: The object does need neither repaint nor relayout after
291 A lot can be optimised here based on the display type, lots of
292 optimisations are unimplemented, and currently result in the
293 worst case result causing a relayout of the containing block.
295 StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
297 changedContextSensitiveProperties = ContextSensitivePropertyNone;
300 if (m_svgStyle != other->m_svgStyle)
301 return m_svgStyle->diff(other->m_svgStyle.get());
304 if (m_box->width() != other->m_box->width() ||
305 m_box->minWidth() != other->m_box->minWidth() ||
306 m_box->maxWidth() != other->m_box->maxWidth() ||
307 m_box->height() != other->m_box->height() ||
308 m_box->minHeight() != other->m_box->minHeight() ||
309 m_box->maxHeight() != other->m_box->maxHeight())
310 return StyleDifferenceLayout;
312 if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align)
313 return StyleDifferenceLayout;
315 if (m_box->boxSizing() != other->m_box->boxSizing())
316 return StyleDifferenceLayout;
318 if (surround->margin != other->surround->margin)
319 return StyleDifferenceLayout;
321 if (surround->padding != other->surround->padding)
322 return StyleDifferenceLayout;
324 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
325 if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance ||
326 rareNonInheritedData->marginTopCollapse != other->rareNonInheritedData->marginTopCollapse ||
327 rareNonInheritedData->marginBottomCollapse != other->rareNonInheritedData->marginBottomCollapse ||
328 rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp ||
329 rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow)
330 return StyleDifferenceLayout;
332 if (rareNonInheritedData->flexibleBox.get() != other->rareNonInheritedData->flexibleBox.get() &&
333 *rareNonInheritedData->flexibleBox.get() != *other->rareNonInheritedData->flexibleBox.get())
334 return StyleDifferenceLayout;
336 // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
337 if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get()))
338 return StyleDifferenceLayout;
340 if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get()))
341 return StyleDifferenceLayout;
343 if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() &&
344 *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get())
345 return StyleDifferenceLayout;
347 if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() &&
348 *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) {
349 #if USE(ACCELERATED_COMPOSITING)
350 changedContextSensitiveProperties |= ContextSensitivePropertyTransform;
351 // Don't return; keep looking for another change
353 return StyleDifferenceLayout;
357 #if !USE(ACCELERATED_COMPOSITING)
358 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
359 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D ||
360 rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility ||
361 rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective ||
362 rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX ||
363 rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
364 return StyleDifferenceLayout;
368 #if ENABLE(DASHBOARD_SUPPORT)
369 // If regions change, trigger a relayout to re-calc regions.
370 if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions)
371 return StyleDifferenceLayout;
375 if (rareInheritedData.get() != other->rareInheritedData.get()) {
376 if (rareInheritedData->highlight != other->rareInheritedData->highlight ||
377 rareInheritedData->indent != other->rareInheritedData->indent ||
378 rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom ||
379 rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust ||
380 rareInheritedData->wordBreak != other->rareInheritedData->wordBreak ||
381 rareInheritedData->wordWrap != other->rareInheritedData->wordWrap ||
382 rareInheritedData->nbspMode != other->rareInheritedData->nbspMode ||
383 rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak ||
384 rareInheritedData->textSecurity != other->rareInheritedData->textSecurity ||
385 rareInheritedData->hyphens != other->rareInheritedData->hyphens ||
386 rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString ||
387 rareInheritedData->hyphenationLocale != other->rareInheritedData->hyphenationLocale)
388 return StyleDifferenceLayout;
390 if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get()))
391 return StyleDifferenceLayout;
393 if (textStrokeWidth() != other->textStrokeWidth())
394 return StyleDifferenceLayout;
397 if (inherited->line_height != other->inherited->line_height ||
398 inherited->list_style_image != other->inherited->list_style_image ||
399 inherited->font != other->inherited->font ||
400 inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing ||
401 inherited->vertical_border_spacing != other->inherited->vertical_border_spacing ||
402 inherited_flags._box_direction != other->inherited_flags._box_direction ||
403 inherited_flags._visuallyOrdered != other->inherited_flags._visuallyOrdered ||
404 noninherited_flags._position != other->noninherited_flags._position ||
405 noninherited_flags._floating != other->noninherited_flags._floating ||
406 noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay)
407 return StyleDifferenceLayout;
410 if (((int)noninherited_flags._effectiveDisplay) >= TABLE) {
411 if (inherited_flags._border_collapse != other->inherited_flags._border_collapse ||
412 inherited_flags._empty_cells != other->inherited_flags._empty_cells ||
413 inherited_flags._caption_side != other->inherited_flags._caption_side ||
414 noninherited_flags._table_layout != other->noninherited_flags._table_layout)
415 return StyleDifferenceLayout;
417 // In the collapsing border model, 'hidden' suppresses other borders, while 'none'
418 // does not, so these style differences can be width differences.
419 if (inherited_flags._border_collapse &&
420 ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE) ||
421 (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN) ||
422 (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE) ||
423 (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN) ||
424 (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE) ||
425 (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN) ||
426 (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE) ||
427 (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN)))
428 return StyleDifferenceLayout;
431 if (noninherited_flags._effectiveDisplay == LIST_ITEM) {
432 if (inherited_flags._list_style_type != other->inherited_flags._list_style_type ||
433 inherited_flags._list_style_position != other->inherited_flags._list_style_position)
434 return StyleDifferenceLayout;
437 if (inherited_flags._text_align != other->inherited_flags._text_align ||
438 inherited_flags._text_transform != other->inherited_flags._text_transform ||
439 inherited_flags._direction != other->inherited_flags._direction ||
440 inherited_flags._white_space != other->inherited_flags._white_space ||
441 noninherited_flags._clear != other->noninherited_flags._clear)
442 return StyleDifferenceLayout;
444 // Check block flow direction.
445 if (inherited_flags._blockFlow != other->inherited_flags._blockFlow)
446 return StyleDifferenceLayout;
448 // Overflow returns a layout hint.
449 if (noninherited_flags._overflowX != other->noninherited_flags._overflowX ||
450 noninherited_flags._overflowY != other->noninherited_flags._overflowY)
451 return StyleDifferenceLayout;
453 // If our border widths change, then we need to layout. Other changes to borders
454 // only necessitate a repaint.
455 if (borderLeftWidth() != other->borderLeftWidth() ||
456 borderTopWidth() != other->borderTopWidth() ||
457 borderBottomWidth() != other->borderBottomWidth() ||
458 borderRightWidth() != other->borderRightWidth())
459 return StyleDifferenceLayout;
461 // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree.
462 const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get();
463 const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get();
464 if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB)))
465 return StyleDifferenceLayout;
466 if (rareNonInheritedData->m_counterIncrement != other->rareNonInheritedData->m_counterIncrement ||
467 rareNonInheritedData->m_counterReset != other->rareNonInheritedData->m_counterReset)
468 return StyleDifferenceLayout;
470 if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) ||
471 (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) {
472 // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
473 return StyleDifferenceLayout;
476 if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE))
477 return StyleDifferenceLayout;
479 // Make sure these left/top/right/bottom checks stay below all layout checks and above
480 // all visible checks.
481 if (position() != StaticPosition) {
482 if (surround->offset != other->surround->offset) {
483 // Optimize for the case where a positioned layer is moving but not changing size.
484 if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset))
485 return StyleDifferenceLayoutPositionedMovementOnly;
487 // FIXME: We will need to do a bit of work in RenderObject/Box::setStyle before we
488 // can stop doing a layout when relative positioned objects move. In particular, we'll need
489 // to update scrolling positions and figure out how to do a repaint properly of the updated layer.
490 //if (other->position() == RelativePosition)
491 // return RepaintLayer;
493 return StyleDifferenceLayout;
494 } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() ||
495 visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)
496 return StyleDifferenceRepaintLayer;
499 if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) {
500 #if USE(ACCELERATED_COMPOSITING)
501 changedContextSensitiveProperties |= ContextSensitivePropertyOpacity;
502 // Don't return; keep looking for another change.
504 return StyleDifferenceRepaintLayer;
508 if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask ||
509 rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage)
510 return StyleDifferenceRepaintLayer;
512 if (inherited->color != other->inherited->color ||
513 inherited_flags._visibility != other->inherited_flags._visibility ||
514 inherited_flags._text_decorations != other->inherited_flags._text_decorations ||
515 inherited_flags._force_backgrounds_to_white != other->inherited_flags._force_backgrounds_to_white ||
516 inherited_flags._insideLink != other->inherited_flags._insideLink ||
517 surround->border != other->surround->border ||
518 *m_background.get() != *other->m_background.get() ||
519 visual->textDecoration != other->visual->textDecoration ||
520 rareInheritedData->userModify != other->rareInheritedData->userModify ||
521 rareInheritedData->userSelect != other->rareInheritedData->userSelect ||
522 rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag ||
523 rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit ||
524 rareInheritedData->textFillColor != other->rareInheritedData->textFillColor ||
525 rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor)
526 return StyleDifferenceRepaint;
528 #if USE(ACCELERATED_COMPOSITING)
529 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
530 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D ||
531 rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility ||
532 rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective ||
533 rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX ||
534 rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
535 return StyleDifferenceRecompositeLayer;
539 // Cursors are not checked, since they will be set appropriately in response to mouse events,
540 // so they don't need to cause any repaint or layout.
542 // 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
543 // the resulting transition properly.
544 return StyleDifferenceEqual;
547 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left)
549 StyleVisualData* data = visual.access();
550 data->clip.m_top = top;
551 data->clip.m_right = right;
552 data->clip.m_bottom = bottom;
553 data->clip.m_left = left;
556 void RenderStyle::addCursor(PassRefPtr<StyleImage> image, const IntPoint& hotSpot)
558 if (!rareInheritedData.access()->cursorData)
559 rareInheritedData.access()->cursorData = CursorList::create();
560 rareInheritedData.access()->cursorData->append(CursorData(image, hotSpot));
563 void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
565 rareInheritedData.access()->cursorData = other;
568 void RenderStyle::clearCursorList()
570 if (rareInheritedData->cursorData)
571 rareInheritedData.access()->cursorData = 0;
574 void RenderStyle::clearContent()
576 if (rareNonInheritedData->m_content)
577 rareNonInheritedData->m_content->clear();
580 ContentData* RenderStyle::prepareToSetContent(StringImpl* string, bool add)
582 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
583 ContentData* lastContent = content.get();
584 while (lastContent && lastContent->next())
585 lastContent = lastContent->next();
587 if (string && add && lastContent && lastContent->isText()) {
588 // Augment the existing string and share the existing ContentData node.
589 String newText = lastContent->text();
590 newText.append(string);
591 lastContent->setText(newText.impl());
595 bool reuseContent = !add;
596 OwnPtr<ContentData> newContentData;
597 if (reuseContent && content) {
599 newContentData = content.release();
601 newContentData = adoptPtr(new ContentData);
603 ContentData* result = newContentData.get();
605 if (lastContent && !reuseContent)
606 lastContent->setNext(newContentData.release());
608 content = newContentData.release();
613 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add)
617 prepareToSetContent(0, add)->setImage(image);
620 void RenderStyle::setContent(PassRefPtr<StringImpl> string, bool add)
624 if (ContentData* data = prepareToSetContent(string.get(), add))
625 data->setText(string);
628 void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add)
632 prepareToSetContent(0, add)->setCounter(counter);
635 void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const
637 // transform-origin brackets the transform with translate operations.
638 // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant
640 bool applyTransformOrigin = false;
641 unsigned s = rareNonInheritedData->m_transform->m_operations.operations().size();
643 if (applyOrigin == IncludeTransformOrigin) {
644 for (i = 0; i < s; i++) {
645 TransformOperation::OperationType type = rareNonInheritedData->m_transform->m_operations.operations()[i]->getOperationType();
646 if (type != TransformOperation::TRANSLATE_X &&
647 type != TransformOperation::TRANSLATE_Y &&
648 type != TransformOperation::TRANSLATE &&
649 type != TransformOperation::TRANSLATE_Z &&
650 type != TransformOperation::TRANSLATE_3D
652 applyTransformOrigin = true;
658 if (applyTransformOrigin) {
659 transform.translate3d(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height()), transformOriginZ());
662 for (i = 0; i < s; i++)
663 rareNonInheritedData->m_transform->m_operations.operations()[i]->apply(transform, borderBoxSize);
665 if (applyTransformOrigin) {
666 transform.translate3d(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()), -transformOriginZ());
670 void RenderStyle::setTextShadow(ShadowData* val, bool add)
672 ASSERT(!val || (!val->spread() && val->style() == Normal));
674 StyleRareInheritedData* rareData = rareInheritedData.access();
676 delete rareData->textShadow;
677 rareData->textShadow = val;
681 val->setNext(rareData->textShadow);
682 rareData->textShadow = val;
685 void RenderStyle::setBoxShadow(ShadowData* shadowData, bool add)
687 StyleRareNonInheritedData* rareData = rareNonInheritedData.access();
689 rareData->m_boxShadow.set(shadowData);
693 shadowData->setNext(rareData->m_boxShadow.leakPtr());
694 rareData->m_boxShadow.set(shadowData);
697 static void constrainCornerRadiiForRect(const IntRect& r, IntSize& topLeft, IntSize& topRight, IntSize& bottomLeft, IntSize& bottomRight)
699 // Constrain corner radii using CSS3 rules:
700 // http://www.w3.org/TR/css3-background/#the-border-radius
706 radiiSum = static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()); // Casts to avoid integer overflow.
707 if (radiiSum > static_cast<unsigned>(r.width()))
708 factor = min(static_cast<float>(r.width()) / radiiSum, factor);
711 radiiSum = static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width());
712 if (radiiSum > static_cast<unsigned>(r.width()))
713 factor = min(static_cast<float>(r.width()) / radiiSum, factor);
716 radiiSum = static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height());
717 if (radiiSum > static_cast<unsigned>(r.height()))
718 factor = min(static_cast<float>(r.height()) / radiiSum, factor);
721 radiiSum = static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height());
722 if (radiiSum > static_cast<unsigned>(r.height()))
723 factor = min(static_cast<float>(r.height()) / radiiSum, factor);
725 // Scale all radii by f if necessary.
727 // If either radius on a corner becomes zero, reset both radii on that corner.
728 topLeft.scale(factor);
729 if (!topLeft.width() || !topLeft.height())
731 topRight.scale(factor);
732 if (!topRight.width() || !topRight.height())
733 topRight = IntSize();
734 bottomLeft.scale(factor);
735 if (!bottomLeft.width() || !bottomLeft.height())
736 bottomLeft = IntSize();
737 bottomRight.scale(factor);
738 if (!bottomRight.width() || !bottomRight.height())
739 bottomRight = IntSize();
743 void RenderStyle::getBorderRadiiForRect(const IntRect& r, IntSize& topLeft, IntSize& topRight, IntSize& bottomLeft, IntSize& bottomRight) const
745 topLeft = IntSize(surround->border.topLeft().width().calcValue(r.width()), surround->border.topLeft().height().calcValue(r.height()));
746 topRight = IntSize(surround->border.topRight().width().calcValue(r.width()), surround->border.topRight().height().calcValue(r.height()));
748 bottomLeft = IntSize(surround->border.bottomLeft().width().calcValue(r.width()), surround->border.bottomLeft().height().calcValue(r.height()));
749 bottomRight = IntSize(surround->border.bottomRight().width().calcValue(r.width()), surround->border.bottomRight().height().calcValue(r.height()));
751 constrainCornerRadiiForRect(r, topLeft, topRight, bottomLeft, bottomRight);
754 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
756 innerTopLeft = IntSize(surround->border.topLeft().width().calcValue(innerRect.width()), surround->border.topLeft().height().calcValue(innerRect.height()));
757 innerTopRight = IntSize(surround->border.topRight().width().calcValue(innerRect.width()), surround->border.topRight().height().calcValue(innerRect.height()));
758 innerBottomLeft = IntSize(surround->border.bottomLeft().width().calcValue(innerRect.width()), surround->border.bottomLeft().height().calcValue(innerRect.height()));
759 innerBottomRight = IntSize(surround->border.bottomRight().width().calcValue(innerRect.width()), surround->border.bottomRight().height().calcValue(innerRect.height()));
762 innerTopLeft.setWidth(max(0, innerTopLeft.width() - leftWidth));
763 innerTopLeft.setHeight(max(0, innerTopLeft.height() - topWidth));
765 innerTopRight.setWidth(max(0, innerTopRight.width() - rightWidth));
766 innerTopRight.setHeight(max(0, innerTopRight.height() - topWidth));
768 innerBottomLeft.setWidth(max(0, innerBottomLeft.width() - leftWidth));
769 innerBottomLeft.setHeight(max(0, innerBottomLeft.height() - bottomWidth));
771 innerBottomRight.setWidth(max(0, innerBottomRight.width() - rightWidth));
772 innerBottomRight.setHeight(max(0, innerBottomRight.height() - bottomWidth));
774 constrainCornerRadiiForRect(innerRect, innerTopLeft, innerTopRight, innerBottomLeft, innerBottomRight);
777 const CounterDirectiveMap* RenderStyle::counterDirectives() const
779 return rareNonInheritedData->m_counterDirectives.get();
782 CounterDirectiveMap& RenderStyle::accessCounterDirectives()
784 OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives;
786 map.set(new CounterDirectiveMap);
790 const AtomicString& RenderStyle::hyphenString() const
792 ASSERT(hyphens() == HyphensAuto);
794 const AtomicString& hyphenationString = rareInheritedData.get()->hyphenationString;
795 if (!hyphenationString.isNull())
796 return hyphenationString;
798 // FIXME: This should depend on locale.
799 DEFINE_STATIC_LOCAL(AtomicString, hyphenMinusString, (&hyphen, 1));
800 return hyphenMinusString;
803 #if ENABLE(DASHBOARD_SUPPORT)
804 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
806 DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ());
810 const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions()
812 DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, noneList, ());
813 static bool noneListInitialized = false;
815 if (!noneListInitialized) {
816 StyleDashboardRegion region;
818 region.offset.m_top = Length();
819 region.offset.m_right = Length();
820 region.offset.m_bottom = Length();
821 region.offset.m_left = Length();
822 region.type = StyleDashboardRegion::None;
823 noneList.append(region);
824 noneListInitialized = true;
830 void RenderStyle::adjustAnimations()
832 AnimationList* animationList = rareNonInheritedData->m_animations.get();
836 // Get rid of empty animations and anything beyond them
837 for (size_t i = 0; i < animationList->size(); ++i) {
838 if (animationList->animation(i)->isEmpty()) {
839 animationList->resize(i);
844 if (animationList->isEmpty()) {
849 // Repeat patterns into layers that don't have some properties set.
850 animationList->fillUnsetProperties();
853 void RenderStyle::adjustTransitions()
855 AnimationList* transitionList = rareNonInheritedData->m_transitions.get();
859 // Get rid of empty transitions and anything beyond them
860 for (size_t i = 0; i < transitionList->size(); ++i) {
861 if (transitionList->animation(i)->isEmpty()) {
862 transitionList->resize(i);
867 if (transitionList->isEmpty()) {
872 // Repeat patterns into layers that don't have some properties set.
873 transitionList->fillUnsetProperties();
875 // Make sure there are no duplicate properties. This is an O(n^2) algorithm
876 // but the lists tend to be very short, so it is probably ok
877 for (size_t i = 0; i < transitionList->size(); ++i) {
878 for (size_t j = i+1; j < transitionList->size(); ++j) {
879 if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) {
881 transitionList->remove(i);
888 AnimationList* RenderStyle::accessAnimations()
890 if (!rareNonInheritedData.access()->m_animations)
891 rareNonInheritedData.access()->m_animations.set(new AnimationList());
892 return rareNonInheritedData->m_animations.get();
895 AnimationList* RenderStyle::accessTransitions()
897 if (!rareNonInheritedData.access()->m_transitions)
898 rareNonInheritedData.access()->m_transitions.set(new AnimationList());
899 return rareNonInheritedData->m_transitions.get();
902 const Animation* RenderStyle::transitionForProperty(int property) const
905 for (size_t i = 0; i < transitions()->size(); ++i) {
906 const Animation* p = transitions()->animation(i);
907 if (p->property() == cAnimateAll || p->property() == property) {
915 void RenderStyle::setBlendedFontSize(int size)
917 FontSelector* currentFontSelector = font().fontSelector();
918 FontDescription desc(fontDescription());
919 desc.setSpecifiedSize(size);
920 desc.setComputedSize(size);
921 setFontDescription(desc);
922 font().update(currentFontSelector);
925 void RenderStyle::getBoxShadowExtent(int &top, int &right, int &bottom, int &left) const
932 for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) {
933 if (boxShadow->style() == Inset)
935 int blurAndSpread = boxShadow->blur() + boxShadow->spread();
937 top = min(top, boxShadow->y() - blurAndSpread);
938 right = max(right, boxShadow->x() + blurAndSpread);
939 bottom = max(bottom, boxShadow->y() + blurAndSpread);
940 left = min(left, boxShadow->x() - blurAndSpread);
944 void RenderStyle::getBoxShadowHorizontalExtent(int &left, int &right) const
949 for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) {
950 if (boxShadow->style() == Inset)
952 int blurAndSpread = boxShadow->blur() + boxShadow->spread();
954 left = min(left, boxShadow->x() - blurAndSpread);
955 right = max(right, boxShadow->x() + blurAndSpread);
959 void RenderStyle::getBoxShadowVerticalExtent(int &top, int &bottom) const
964 for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) {
965 if (boxShadow->style() == Inset)
967 int blurAndSpread = boxShadow->blur() + boxShadow->spread();
969 top = min(top, boxShadow->y() - blurAndSpread);
970 bottom = max(bottom, boxShadow->y() + blurAndSpread);
974 static EBorderStyle borderStyleForColorProperty(const RenderStyle* style, int colorProperty)
976 EBorderStyle borderStyle;
977 switch (colorProperty) {
978 case CSSPropertyBorderLeftColor:
979 borderStyle = style->borderLeftStyle();
981 case CSSPropertyBorderRightColor:
982 borderStyle = style->borderRightStyle();
984 case CSSPropertyBorderTopColor:
985 borderStyle = style->borderTopStyle();
987 case CSSPropertyBorderBottomColor:
988 borderStyle = style->borderBottomStyle();
997 const Color RenderStyle::colorIncludingFallback(int colorProperty, EBorderStyle borderStyle) const
1000 switch (colorProperty) {
1001 case CSSPropertyBackgroundColor:
1002 return backgroundColor(); // Background color doesn't fall back.
1003 case CSSPropertyBorderLeftColor:
1004 result = borderLeftColor();
1005 borderStyle = borderLeftStyle();
1007 case CSSPropertyBorderRightColor:
1008 result = borderRightColor();
1009 borderStyle = borderRightStyle();
1011 case CSSPropertyBorderTopColor:
1012 result = borderTopColor();
1013 borderStyle = borderTopStyle();
1015 case CSSPropertyBorderBottomColor:
1016 result = borderBottomColor();
1017 borderStyle = borderBottomStyle();
1019 case CSSPropertyColor:
1022 case CSSPropertyOutlineColor:
1023 result = outlineColor();
1025 case CSSPropertyWebkitColumnRuleColor:
1026 result = columnRuleColor();
1028 case CSSPropertyWebkitTextFillColor:
1029 result = textFillColor();
1031 case CSSPropertyWebkitTextStrokeColor:
1032 result = textStrokeColor();
1035 ASSERT_NOT_REACHED();
1039 if (!result.isValid()) {
1040 if ((colorProperty == CSSPropertyBorderLeftColor || colorProperty == CSSPropertyBorderRightColor
1041 || colorProperty == CSSPropertyBorderTopColor || colorProperty == CSSPropertyBorderBottomColor)
1042 && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE))
1043 result.setRGB(238, 238, 238);
1051 const Color RenderStyle::visitedDependentColor(int colorProperty) const
1053 EBorderStyle borderStyle = borderStyleForColorProperty(this, colorProperty);
1054 Color unvisitedColor = colorIncludingFallback(colorProperty, borderStyle);
1055 if (insideLink() != InsideVisitedLink)
1056 return unvisitedColor;
1058 RenderStyle* visitedStyle = getCachedPseudoStyle(VISITED_LINK);
1060 return unvisitedColor;
1061 Color visitedColor = visitedStyle->colorIncludingFallback(colorProperty, borderStyle);
1063 // Take the alpha from the unvisited color, but get the RGB values from the visited color.
1064 return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha());
1067 Length RenderStyle::logicalWidth() const
1069 if (isVerticalBlockFlow())
1074 Length RenderStyle::logicalHeight() const
1076 if (isVerticalBlockFlow())
1081 Length RenderStyle::logicalMinWidth() const
1083 if (isVerticalBlockFlow())
1088 Length RenderStyle::logicalMaxWidth() const
1090 if (isVerticalBlockFlow())
1095 Length RenderStyle::logicalMinHeight() const
1097 if (isVerticalBlockFlow())
1102 Length RenderStyle::logicalMaxHeight() const
1104 if (isVerticalBlockFlow())
1109 unsigned short RenderStyle::borderBeforeWidth() const
1111 switch (blockFlow()) {
1112 case TopToBottomBlockFlow:
1113 return borderTopWidth();
1114 case BottomToTopBlockFlow:
1115 return borderBottomWidth();
1116 case LeftToRightBlockFlow:
1117 return borderLeftWidth();
1118 case RightToLeftBlockFlow:
1119 return borderRightWidth();
1121 ASSERT_NOT_REACHED();
1122 return borderTopWidth();
1125 unsigned short RenderStyle::borderAfterWidth() const
1127 switch (blockFlow()) {
1128 case TopToBottomBlockFlow:
1129 return borderBottomWidth();
1130 case BottomToTopBlockFlow:
1131 return borderTopWidth();
1132 case LeftToRightBlockFlow:
1133 return borderRightWidth();
1134 case RightToLeftBlockFlow:
1135 return borderLeftWidth();
1137 ASSERT_NOT_REACHED();
1138 return borderBottomWidth();
1141 unsigned short RenderStyle::borderStartWidth() const
1143 if (isVerticalBlockFlow())
1144 return direction() == LTR ? borderLeftWidth() : borderRightWidth();
1145 return direction() == LTR ? borderTopWidth() : borderBottomWidth();
1148 unsigned short RenderStyle::borderEndWidth() const
1150 if (isVerticalBlockFlow())
1151 return direction() == LTR ? borderRightWidth() : borderLeftWidth();
1152 return direction() == LTR ? borderBottomWidth() : borderTopWidth();
1155 Length RenderStyle::marginBefore() const
1157 switch (blockFlow()) {
1158 case TopToBottomBlockFlow:
1160 case BottomToTopBlockFlow:
1161 return marginBottom();
1162 case LeftToRightBlockFlow:
1163 return marginLeft();
1164 case RightToLeftBlockFlow:
1165 return marginRight();
1167 ASSERT_NOT_REACHED();
1171 Length RenderStyle::marginAfter() const
1173 switch (blockFlow()) {
1174 case TopToBottomBlockFlow:
1175 return marginBottom();
1176 case BottomToTopBlockFlow:
1178 case LeftToRightBlockFlow:
1179 return marginRight();
1180 case RightToLeftBlockFlow:
1181 return marginLeft();
1183 ASSERT_NOT_REACHED();
1184 return marginBottom();
1187 Length RenderStyle::marginStart() const
1189 if (isVerticalBlockFlow())
1190 return direction() == LTR ? marginLeft() : marginRight();
1191 return direction() == LTR ? marginTop() : marginBottom();
1194 Length RenderStyle::marginEnd() const
1196 if (isVerticalBlockFlow())
1197 return direction() == LTR ? marginRight() : marginLeft();
1198 return direction() == LTR ? marginBottom() : marginTop();
1201 Length RenderStyle::paddingBefore() const
1203 switch (blockFlow()) {
1204 case TopToBottomBlockFlow:
1205 return paddingTop();
1206 case BottomToTopBlockFlow:
1207 return paddingBottom();
1208 case LeftToRightBlockFlow:
1209 return paddingLeft();
1210 case RightToLeftBlockFlow:
1211 return paddingRight();
1213 ASSERT_NOT_REACHED();
1214 return paddingTop();
1217 Length RenderStyle::paddingAfter() const
1219 switch (blockFlow()) {
1220 case TopToBottomBlockFlow:
1221 return paddingBottom();
1222 case BottomToTopBlockFlow:
1223 return paddingTop();
1224 case LeftToRightBlockFlow:
1225 return paddingRight();
1226 case RightToLeftBlockFlow:
1227 return paddingLeft();
1229 ASSERT_NOT_REACHED();
1230 return paddingBottom();
1233 Length RenderStyle::paddingStart() const
1235 if (isVerticalBlockFlow())
1236 return direction() == LTR ? paddingLeft() : paddingRight();
1237 return direction() == LTR ? paddingTop() : paddingBottom();
1240 Length RenderStyle::paddingEnd() const
1242 if (isVerticalBlockFlow())
1243 return direction() == LTR ? paddingRight() : paddingLeft();
1244 return direction() == LTR ? paddingBottom() : paddingTop();
1247 } // namespace WebCore