1 /* 2 * Copyright (C) 1999 Antti Koivisto (koivisto (at) 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 "ContentData.h" 26 #include "CursorList.h" 27 #include "CSSPropertyNames.h" 28 #include "CSSStyleSelector.h" 29 #include "FontSelector.h" 30 #include "QuotesData.h" 31 #include "RenderArena.h" 32 #include "RenderObject.h" 33 #include "ScaleTransformOperation.h" 34 #include "ShadowData.h" 35 #include "StyleImage.h" 36 #include <wtf/StdLibExtras.h> 37 #include <algorithm> 38 39 using namespace std; 40 41 namespace WebCore { 42 43 inline RenderStyle* defaultStyle() 44 { 45 static RenderStyle* s_defaultStyle = RenderStyle::createDefaultStyle().releaseRef(); 46 return s_defaultStyle; 47 } 48 49 PassRefPtr<RenderStyle> RenderStyle::create() 50 { 51 return adoptRef(new RenderStyle()); 52 } 53 54 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle() 55 { 56 return adoptRef(new RenderStyle(true)); 57 } 58 59 PassRefPtr<RenderStyle> RenderStyle::createAnonymousStyle(const RenderStyle* parentStyle) 60 { 61 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 62 newStyle->inheritFrom(parentStyle); 63 newStyle->inheritUnicodeBidiFrom(parentStyle); 64 return newStyle; 65 } 66 67 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other) 68 { 69 return adoptRef(new RenderStyle(*other)); 70 } 71 72 ALWAYS_INLINE RenderStyle::RenderStyle() 73 : m_affectedByAttributeSelectors(false) 74 , m_unique(false) 75 , m_affectedByEmpty(false) 76 , m_emptyState(false) 77 , m_childrenAffectedByFirstChildRules(false) 78 , m_childrenAffectedByLastChildRules(false) 79 , m_childrenAffectedByDirectAdjacentRules(false) 80 , m_childrenAffectedByForwardPositionalRules(false) 81 , m_childrenAffectedByBackwardPositionalRules(false) 82 , m_firstChildState(false) 83 , m_lastChildState(false) 84 , m_childIndex(0) 85 , m_box(defaultStyle()->m_box) 86 , visual(defaultStyle()->visual) 87 , m_background(defaultStyle()->m_background) 88 , surround(defaultStyle()->surround) 89 , rareNonInheritedData(defaultStyle()->rareNonInheritedData) 90 , rareInheritedData(defaultStyle()->rareInheritedData) 91 , inherited(defaultStyle()->inherited) 92 #if ENABLE(SVG) 93 , m_svgStyle(defaultStyle()->m_svgStyle) 94 #endif 95 { 96 setBitDefaults(); // Would it be faster to copy this from the default style? 97 } 98 99 ALWAYS_INLINE RenderStyle::RenderStyle(bool) 100 : m_affectedByAttributeSelectors(false) 101 , m_unique(false) 102 , m_affectedByEmpty(false) 103 , m_emptyState(false) 104 , m_childrenAffectedByFirstChildRules(false) 105 , m_childrenAffectedByLastChildRules(false) 106 , m_childrenAffectedByDirectAdjacentRules(false) 107 , m_childrenAffectedByForwardPositionalRules(false) 108 , m_childrenAffectedByBackwardPositionalRules(false) 109 , m_firstChildState(false) 110 , m_lastChildState(false) 111 , m_childIndex(0) 112 { 113 setBitDefaults(); 114 115 m_box.init(); 116 visual.init(); 117 m_background.init(); 118 surround.init(); 119 rareNonInheritedData.init(); 120 rareNonInheritedData.access()->flexibleBox.init(); 121 rareNonInheritedData.access()->marquee.init(); 122 rareNonInheritedData.access()->m_multiCol.init(); 123 rareNonInheritedData.access()->m_transform.init(); 124 rareInheritedData.init(); 125 inherited.init(); 126 127 #if ENABLE(SVG) 128 m_svgStyle.init(); 129 #endif 130 } 131 132 ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o) 133 : RefCounted<RenderStyle>() 134 , m_affectedByAttributeSelectors(false) 135 , m_unique(false) 136 , m_affectedByEmpty(false) 137 , m_emptyState(false) 138 , m_childrenAffectedByFirstChildRules(false) 139 , m_childrenAffectedByLastChildRules(false) 140 , m_childrenAffectedByDirectAdjacentRules(false) 141 , m_childrenAffectedByForwardPositionalRules(false) 142 , m_childrenAffectedByBackwardPositionalRules(false) 143 , m_firstChildState(false) 144 , m_lastChildState(false) 145 , m_childIndex(0) 146 , m_box(o.m_box) 147 , visual(o.visual) 148 , m_background(o.m_background) 149 , surround(o.surround) 150 , rareNonInheritedData(o.rareNonInheritedData) 151 , rareInheritedData(o.rareInheritedData) 152 , inherited(o.inherited) 153 #if ENABLE(SVG) 154 , m_svgStyle(o.m_svgStyle) 155 #endif 156 , inherited_flags(o.inherited_flags) 157 , noninherited_flags(o.noninherited_flags) 158 { 159 } 160 161 void RenderStyle::inheritFrom(const RenderStyle* inheritParent) 162 { 163 rareInheritedData = inheritParent->rareInheritedData; 164 inherited = inheritParent->inherited; 165 inherited_flags = inheritParent->inherited_flags; 166 #if ENABLE(SVG) 167 if (m_svgStyle != inheritParent->m_svgStyle) 168 m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get()); 169 #endif 170 } 171 172 RenderStyle::~RenderStyle() 173 { 174 } 175 176 bool RenderStyle::operator==(const RenderStyle& o) const 177 { 178 // compare everything except the pseudoStyle pointer 179 return inherited_flags == o.inherited_flags 180 && noninherited_flags == o.noninherited_flags 181 && m_box == o.m_box 182 && visual == o.visual 183 && m_background == o.m_background 184 && surround == o.surround 185 && rareNonInheritedData == o.rareNonInheritedData 186 && rareInheritedData == o.rareInheritedData 187 && inherited == o.inherited 188 #if ENABLE(SVG) 189 && m_svgStyle == o.m_svgStyle 190 #endif 191 ; 192 } 193 194 bool RenderStyle::isStyleAvailable() const 195 { 196 return this != CSSStyleSelector::styleNotYetAvailable(); 197 } 198 199 static inline int pseudoBit(PseudoId pseudo) 200 { 201 return 1 << (pseudo - 1); 202 } 203 204 bool RenderStyle::hasAnyPublicPseudoStyles() const 205 { 206 return PUBLIC_PSEUDOID_MASK & noninherited_flags._pseudoBits; 207 } 208 209 bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const 210 { 211 ASSERT(pseudo > NOPSEUDO); 212 ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID); 213 return pseudoBit(pseudo) & noninherited_flags._pseudoBits; 214 } 215 216 void RenderStyle::setHasPseudoStyle(PseudoId pseudo) 217 { 218 ASSERT(pseudo > NOPSEUDO); 219 ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID); 220 noninherited_flags._pseudoBits |= pseudoBit(pseudo); 221 } 222 223 RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const 224 { 225 ASSERT(styleType() != VISITED_LINK); 226 227 if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size()) 228 return 0; 229 230 if (styleType() != NOPSEUDO) { 231 if (pid == VISITED_LINK) 232 return m_cachedPseudoStyles->at(0)->styleType() == VISITED_LINK ? m_cachedPseudoStyles->at(0).get() : 0; 233 return 0; 234 } 235 236 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) { 237 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get(); 238 if (pseudoStyle->styleType() == pid) 239 return pseudoStyle; 240 } 241 242 return 0; 243 } 244 245 RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo) 246 { 247 if (!pseudo) 248 return 0; 249 250 RenderStyle* result = pseudo.get(); 251 252 if (!m_cachedPseudoStyles) 253 m_cachedPseudoStyles.set(new PseudoStyleCache); 254 255 m_cachedPseudoStyles->append(pseudo); 256 257 return result; 258 } 259 260 void RenderStyle::removeCachedPseudoStyle(PseudoId pid) 261 { 262 if (!m_cachedPseudoStyles) 263 return; 264 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) { 265 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get(); 266 if (pseudoStyle->styleType() == pid) { 267 m_cachedPseudoStyles->remove(i); 268 return; 269 } 270 } 271 } 272 273 bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const 274 { 275 return inherited_flags != other->inherited_flags 276 || inherited != other->inherited 277 #if ENABLE(SVG) 278 || m_svgStyle->inheritedNotEqual(other->m_svgStyle.get()) 279 #endif 280 || rareInheritedData != other->rareInheritedData; 281 } 282 283 static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b) 284 { 285 // If any unit types are different, then we can't guarantee 286 // that this was just a movement. 287 if (a.left().type() != b.left().type() 288 || a.right().type() != b.right().type() 289 || a.top().type() != b.top().type() 290 || a.bottom().type() != b.bottom().type()) 291 return false; 292 293 // Only one unit can be non-auto in the horizontal direction and 294 // in the vertical direction. Otherwise the adjustment of values 295 // is changing the size of the box. 296 if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto()) 297 return false; 298 if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto()) 299 return false; 300 301 // One of the units is fixed or percent in both directions and stayed 302 // that way in the new style. Therefore all we are doing is moving. 303 return true; 304 } 305 306 StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const 307 { 308 changedContextSensitiveProperties = ContextSensitivePropertyNone; 309 310 #if ENABLE(SVG) 311 StyleDifference svgChange = StyleDifferenceEqual; 312 if (m_svgStyle != other->m_svgStyle) { 313 svgChange = m_svgStyle->diff(other->m_svgStyle.get()); 314 if (svgChange == StyleDifferenceLayout) 315 return svgChange; 316 } 317 #endif 318 319 if (m_box->width() != other->m_box->width() 320 || m_box->minWidth() != other->m_box->minWidth() 321 || m_box->maxWidth() != other->m_box->maxWidth() 322 || m_box->height() != other->m_box->height() 323 || m_box->minHeight() != other->m_box->minHeight() 324 || m_box->maxHeight() != other->m_box->maxHeight()) 325 return StyleDifferenceLayout; 326 327 if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align) 328 return StyleDifferenceLayout; 329 330 if (m_box->boxSizing() != other->m_box->boxSizing()) 331 return StyleDifferenceLayout; 332 333 if (surround->margin != other->surround->margin) 334 return StyleDifferenceLayout; 335 336 if (surround->padding != other->surround->padding) 337 return StyleDifferenceLayout; 338 339 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { 340 if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance 341 || rareNonInheritedData->marginBeforeCollapse != other->rareNonInheritedData->marginBeforeCollapse 342 || rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse 343 || rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp 344 || rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow) 345 return StyleDifferenceLayout; 346 347 if (rareNonInheritedData->flexibleBox.get() != other->rareNonInheritedData->flexibleBox.get() 348 && *rareNonInheritedData->flexibleBox.get() != *other->rareNonInheritedData->flexibleBox.get()) 349 return StyleDifferenceLayout; 350 351 // FIXME: We should add an optimized form of layout that just recomputes visual overflow. 352 if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get())) 353 return StyleDifferenceLayout; 354 355 if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get())) 356 return StyleDifferenceLayout; 357 358 if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() 359 && *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get()) 360 return StyleDifferenceLayout; 361 362 if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() 363 && *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) { 364 #if USE(ACCELERATED_COMPOSITING) 365 changedContextSensitiveProperties |= ContextSensitivePropertyTransform; 366 // Don't return; keep looking for another change 367 #else 368 return StyleDifferenceLayout; 369 #endif 370 } 371 372 #if !USE(ACCELERATED_COMPOSITING) 373 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { 374 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D 375 || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility 376 || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective 377 || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX 378 || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) 379 return StyleDifferenceLayout; 380 } 381 #endif 382 383 #if ENABLE(DASHBOARD_SUPPORT) 384 // If regions change, trigger a relayout to re-calc regions. 385 if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions) 386 return StyleDifferenceLayout; 387 #endif 388 } 389 390 if (rareInheritedData.get() != other->rareInheritedData.get()) { 391 if (rareInheritedData->highlight != other->rareInheritedData->highlight 392 || rareInheritedData->indent != other->rareInheritedData->indent 393 || rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom 394 || rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust 395 || rareInheritedData->wordBreak != other->rareInheritedData->wordBreak 396 || rareInheritedData->wordWrap != other->rareInheritedData->wordWrap 397 || rareInheritedData->nbspMode != other->rareInheritedData->nbspMode 398 || rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak 399 || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity 400 || rareInheritedData->hyphens != other->rareInheritedData->hyphens 401 || rareInheritedData->hyphenationLimitBefore != other->rareInheritedData->hyphenationLimitBefore 402 || rareInheritedData->hyphenationLimitAfter != other->rareInheritedData->hyphenationLimitAfter 403 || rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString 404 || rareInheritedData->locale != other->rareInheritedData->locale 405 || rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark 406 || rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition 407 || rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark 408 || rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain) 409 return StyleDifferenceLayout; 410 411 if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get())) 412 return StyleDifferenceLayout; 413 414 if (textStrokeWidth() != other->textStrokeWidth()) 415 return StyleDifferenceLayout; 416 } 417 418 if (inherited->line_height != other->inherited->line_height 419 || inherited->list_style_image != other->inherited->list_style_image 420 || inherited->font != other->inherited->font 421 || inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing 422 || inherited->vertical_border_spacing != other->inherited->vertical_border_spacing 423 || inherited_flags._box_direction != other->inherited_flags._box_direction 424 || inherited_flags._visuallyOrdered != other->inherited_flags._visuallyOrdered 425 || noninherited_flags._position != other->noninherited_flags._position 426 || noninherited_flags._floating != other->noninherited_flags._floating 427 || noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay) 428 return StyleDifferenceLayout; 429 430 431 if (((int)noninherited_flags._effectiveDisplay) >= TABLE) { 432 if (inherited_flags._border_collapse != other->inherited_flags._border_collapse 433 || inherited_flags._empty_cells != other->inherited_flags._empty_cells 434 || inherited_flags._caption_side != other->inherited_flags._caption_side 435 || noninherited_flags._table_layout != other->noninherited_flags._table_layout) 436 return StyleDifferenceLayout; 437 438 // In the collapsing border model, 'hidden' suppresses other borders, while 'none' 439 // does not, so these style differences can be width differences. 440 if (inherited_flags._border_collapse 441 && ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE) 442 || (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN) 443 || (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE) 444 || (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN) 445 || (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE) 446 || (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN) 447 || (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE) 448 || (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN))) 449 return StyleDifferenceLayout; 450 } 451 452 if (noninherited_flags._effectiveDisplay == LIST_ITEM) { 453 if (inherited_flags._list_style_type != other->inherited_flags._list_style_type 454 || inherited_flags._list_style_position != other->inherited_flags._list_style_position) 455 return StyleDifferenceLayout; 456 } 457 458 if (inherited_flags._text_align != other->inherited_flags._text_align 459 || inherited_flags._text_transform != other->inherited_flags._text_transform 460 || inherited_flags._direction != other->inherited_flags._direction 461 || inherited_flags._white_space != other->inherited_flags._white_space 462 || noninherited_flags._clear != other->noninherited_flags._clear 463 || noninherited_flags._unicodeBidi != other->noninherited_flags._unicodeBidi) 464 return StyleDifferenceLayout; 465 466 // Check block flow direction. 467 if (inherited_flags.m_writingMode != other->inherited_flags.m_writingMode) 468 return StyleDifferenceLayout; 469 470 // Check text combine mode. 471 if (rareNonInheritedData->m_textCombine != other->rareNonInheritedData->m_textCombine) 472 return StyleDifferenceLayout; 473 474 // Overflow returns a layout hint. 475 if (noninherited_flags._overflowX != other->noninherited_flags._overflowX 476 || noninherited_flags._overflowY != other->noninherited_flags._overflowY) 477 return StyleDifferenceLayout; 478 479 // If our border widths change, then we need to layout. Other changes to borders 480 // only necessitate a repaint. 481 if (borderLeftWidth() != other->borderLeftWidth() 482 || borderTopWidth() != other->borderTopWidth() 483 || borderBottomWidth() != other->borderBottomWidth() 484 || borderRightWidth() != other->borderRightWidth()) 485 return StyleDifferenceLayout; 486 487 // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree. 488 const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get(); 489 const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get(); 490 if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB))) 491 return StyleDifferenceLayout; 492 if (rareNonInheritedData->m_counterIncrement != other->rareNonInheritedData->m_counterIncrement 493 || rareNonInheritedData->m_counterReset != other->rareNonInheritedData->m_counterReset) 494 return StyleDifferenceLayout; 495 496 if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE)) 497 return StyleDifferenceLayout; 498 499 if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) 500 || (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) { 501 // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet. 502 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need 503 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). 504 // In addition we need to solve the floating object issue when layers come and go. Right now 505 // a full layout is necessary to keep floating object lists sane. 506 return StyleDifferenceLayout; 507 } 508 509 #if ENABLE(SVG) 510 // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes. 511 // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint, 512 // but have to return StyleDifferenceLayout, that's why this if branch comes after all branches 513 // that are relevant for SVG and might return StyleDifferenceLayout. 514 if (svgChange != StyleDifferenceEqual) 515 return svgChange; 516 #endif 517 518 // Make sure these left/top/right/bottom checks stay below all layout checks and above 519 // all visible checks. 520 if (position() != StaticPosition) { 521 if (surround->offset != other->surround->offset) { 522 // Optimize for the case where a positioned layer is moving but not changing size. 523 if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset)) 524 return StyleDifferenceLayoutPositionedMovementOnly; 525 526 // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet. 527 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need 528 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). 529 return StyleDifferenceLayout; 530 } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() 531 || visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip) 532 return StyleDifferenceRepaintLayer; 533 } 534 535 if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) { 536 #if USE(ACCELERATED_COMPOSITING) 537 changedContextSensitiveProperties |= ContextSensitivePropertyOpacity; 538 // Don't return; keep looking for another change. 539 #else 540 return StyleDifferenceRepaintLayer; 541 #endif 542 } 543 544 if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask 545 || rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage) 546 return StyleDifferenceRepaintLayer; 547 548 if (inherited->color != other->inherited->color 549 || inherited_flags._visibility != other->inherited_flags._visibility 550 || inherited_flags._text_decorations != other->inherited_flags._text_decorations 551 || inherited_flags._force_backgrounds_to_white != other->inherited_flags._force_backgrounds_to_white 552 || inherited_flags._insideLink != other->inherited_flags._insideLink 553 || surround->border != other->surround->border 554 || *m_background.get() != *other->m_background.get() 555 || visual->textDecoration != other->visual->textDecoration 556 || rareInheritedData->userModify != other->rareInheritedData->userModify 557 || rareInheritedData->userSelect != other->rareInheritedData->userSelect 558 || rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag 559 || rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit 560 || rareInheritedData->textFillColor != other->rareInheritedData->textFillColor 561 || rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor 562 || rareInheritedData->textEmphasisColor != other->rareInheritedData->textEmphasisColor 563 || rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill) 564 return StyleDifferenceRepaint; 565 566 #if USE(ACCELERATED_COMPOSITING) 567 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { 568 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D 569 || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility 570 || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective 571 || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX 572 || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) 573 return StyleDifferenceRecompositeLayer; 574 } 575 #endif 576 577 // Cursors are not checked, since they will be set appropriately in response to mouse events, 578 // so they don't need to cause any repaint or layout. 579 580 // 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 581 // the resulting transition properly. 582 return StyleDifferenceEqual; 583 } 584 585 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left) 586 { 587 StyleVisualData* data = visual.access(); 588 data->clip.m_top = top; 589 data->clip.m_right = right; 590 data->clip.m_bottom = bottom; 591 data->clip.m_left = left; 592 } 593 594 void RenderStyle::addCursor(PassRefPtr<StyleImage> image, const IntPoint& hotSpot) 595 { 596 if (!rareInheritedData.access()->cursorData) 597 rareInheritedData.access()->cursorData = CursorList::create(); 598 rareInheritedData.access()->cursorData->append(CursorData(image, hotSpot)); 599 } 600 601 void RenderStyle::setCursorList(PassRefPtr<CursorList> other) 602 { 603 rareInheritedData.access()->cursorData = other; 604 } 605 606 void RenderStyle::setQuotes(PassRefPtr<QuotesData> q) 607 { 608 if (*rareInheritedData->quotes.get() == *q.get()) 609 return; 610 rareInheritedData.access()->quotes = q; 611 } 612 613 void RenderStyle::clearCursorList() 614 { 615 if (rareInheritedData->cursorData) 616 rareInheritedData.access()->cursorData = 0; 617 } 618 619 void RenderStyle::clearContent() 620 { 621 if (rareNonInheritedData->m_content) 622 rareNonInheritedData->m_content->clear(); 623 } 624 625 ContentData* RenderStyle::prepareToSetContent(StringImpl* string, bool add) 626 { 627 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; 628 ContentData* lastContent = content.get(); 629 while (lastContent && lastContent->next()) 630 lastContent = lastContent->next(); 631 632 if (string && add && lastContent && lastContent->isText()) { 633 // Augment the existing string and share the existing ContentData node. 634 String newText = lastContent->text(); 635 newText.append(string); 636 lastContent->setText(newText.impl()); 637 return 0; 638 } 639 640 bool reuseContent = !add; 641 OwnPtr<ContentData> newContentData; 642 if (reuseContent && content) { 643 content->clear(); 644 newContentData = content.release(); 645 } else 646 newContentData = adoptPtr(new ContentData); 647 648 ContentData* result = newContentData.get(); 649 650 if (lastContent && !reuseContent) 651 lastContent->setNext(newContentData.release()); 652 else 653 content = newContentData.release(); 654 655 return result; 656 } 657 658 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add) 659 { 660 if (!image) 661 return; 662 prepareToSetContent(0, add)->setImage(image); 663 } 664 665 void RenderStyle::setContent(PassRefPtr<StringImpl> string, bool add) 666 { 667 if (!string) 668 return; 669 if (ContentData* data = prepareToSetContent(string.get(), add)) 670 data->setText(string); 671 } 672 673 void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add) 674 { 675 if (!counter) 676 return; 677 prepareToSetContent(0, add)->setCounter(counter); 678 } 679 680 void RenderStyle::setContent(QuoteType quote, bool add) 681 { 682 prepareToSetContent(0, add)->setQuote(quote); 683 } 684 685 void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const 686 { 687 // transform-origin brackets the transform with translate operations. 688 // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant 689 // in that case. 690 bool applyTransformOrigin = false; 691 unsigned s = rareNonInheritedData->m_transform->m_operations.operations().size(); 692 unsigned i; 693 if (applyOrigin == IncludeTransformOrigin) { 694 for (i = 0; i < s; i++) { 695 TransformOperation::OperationType type = rareNonInheritedData->m_transform->m_operations.operations()[i]->getOperationType(); 696 if (type != TransformOperation::TRANSLATE_X 697 && type != TransformOperation::TRANSLATE_Y 698 && type != TransformOperation::TRANSLATE 699 && type != TransformOperation::TRANSLATE_Z 700 && type != TransformOperation::TRANSLATE_3D 701 ) { 702 applyTransformOrigin = true; 703 break; 704 } 705 } 706 } 707 708 if (applyTransformOrigin) { 709 transform.translate3d(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height()), transformOriginZ()); 710 } 711 712 for (i = 0; i < s; i++) 713 rareNonInheritedData->m_transform->m_operations.operations()[i]->apply(transform, borderBoxSize); 714 715 if (applyTransformOrigin) { 716 transform.translate3d(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()), -transformOriginZ()); 717 } 718 } 719 720 void RenderStyle::setPageScaleTransform(float scale) 721 { 722 if (scale == 1) 723 return; 724 TransformOperations transform; 725 transform.operations().append(ScaleTransformOperation::create(scale, scale, ScaleTransformOperation::SCALE)); 726 setTransform(transform); 727 setTransformOriginX(Length(0, Fixed)); 728 setTransformOriginY(Length(0, Fixed)); 729 } 730 731 void RenderStyle::setTextShadow(ShadowData* val, bool add) 732 { 733 ASSERT(!val || (!val->spread() && val->style() == Normal)); 734 735 StyleRareInheritedData* rareData = rareInheritedData.access(); 736 if (!add) { 737 delete rareData->textShadow; 738 rareData->textShadow = val; 739 return; 740 } 741 742 val->setNext(rareData->textShadow); 743 rareData->textShadow = val; 744 } 745 746 void RenderStyle::setBoxShadow(ShadowData* shadowData, bool add) 747 { 748 StyleRareNonInheritedData* rareData = rareNonInheritedData.access(); 749 if (!add) { 750 rareData->m_boxShadow.set(shadowData); 751 return; 752 } 753 754 shadowData->setNext(rareData->m_boxShadow.leakPtr()); 755 rareData->m_boxShadow.set(shadowData); 756 } 757 758 static RoundedIntRect::Radii calcRadiiFor(const BorderData& border, int width, int height) 759 { 760 return RoundedIntRect::Radii(IntSize(border.topLeft().width().calcValue(width), 761 border.topLeft().height().calcValue(height)), 762 IntSize(border.topRight().width().calcValue(width), 763 border.topRight().height().calcValue(height)), 764 IntSize(border.bottomLeft().width().calcValue(width), 765 border.bottomLeft().height().calcValue(height)), 766 IntSize(border.bottomRight().width().calcValue(width), 767 border.bottomRight().height().calcValue(height))); 768 } 769 770 static float calcConstraintScaleFor(const IntRect& rect, const RoundedIntRect::Radii& radii) 771 { 772 // Constrain corner radii using CSS3 rules: 773 // http://www.w3.org/TR/css3-background/#the-border-radius 774 775 float factor = 1; 776 unsigned radiiSum; 777 778 // top 779 radiiSum = static_cast<unsigned>(radii.topLeft().width()) + static_cast<unsigned>(radii.topRight().width()); // Casts to avoid integer overflow. 780 if (radiiSum > static_cast<unsigned>(rect.width())) 781 factor = min(static_cast<float>(rect.width()) / radiiSum, factor); 782 783 // bottom 784 radiiSum = static_cast<unsigned>(radii.bottomLeft().width()) + static_cast<unsigned>(radii.bottomRight().width()); 785 if (radiiSum > static_cast<unsigned>(rect.width())) 786 factor = min(static_cast<float>(rect.width()) / radiiSum, factor); 787 788 // left 789 radiiSum = static_cast<unsigned>(radii.topLeft().height()) + static_cast<unsigned>(radii.bottomLeft().height()); 790 if (radiiSum > static_cast<unsigned>(rect.height())) 791 factor = min(static_cast<float>(rect.height()) / radiiSum, factor); 792 793 // right 794 radiiSum = static_cast<unsigned>(radii.topRight().height()) + static_cast<unsigned>(radii.bottomRight().height()); 795 if (radiiSum > static_cast<unsigned>(rect.height())) 796 factor = min(static_cast<float>(rect.height()) / radiiSum, factor); 797 798 ASSERT(factor <= 1); 799 return factor; 800 } 801 802 RoundedIntRect RenderStyle::getRoundedBorderFor(const IntRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const 803 { 804 RoundedIntRect roundedRect(borderRect); 805 if (hasBorderRadius()) { 806 RoundedIntRect::Radii radii = calcRadiiFor(surround->border, borderRect.width(), borderRect.height()); 807 radii.scale(calcConstraintScaleFor(borderRect, radii)); 808 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); 809 } 810 return roundedRect; 811 } 812 813 RoundedIntRect RenderStyle::getRoundedInnerBorderFor(const IntRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const 814 { 815 bool horizontal = isHorizontalWritingMode(); 816 817 int leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0; 818 int rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0; 819 int topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0; 820 int bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0; 821 822 return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge); 823 } 824 825 RoundedIntRect RenderStyle::getRoundedInnerBorderFor(const IntRect& borderRect, 826 int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const 827 { 828 IntRect innerRect(borderRect.x() + leftWidth, 829 borderRect.y() + topWidth, 830 borderRect.width() - leftWidth - rightWidth, 831 borderRect.height() - topWidth - bottomWidth); 832 833 RoundedIntRect roundedRect(innerRect); 834 835 if (hasBorderRadius()) { 836 RoundedIntRect::Radii radii = getRoundedBorderFor(borderRect).radii(); 837 radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth); 838 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); 839 } 840 return roundedRect; 841 } 842 843 const CounterDirectiveMap* RenderStyle::counterDirectives() const 844 { 845 return rareNonInheritedData->m_counterDirectives.get(); 846 } 847 848 CounterDirectiveMap& RenderStyle::accessCounterDirectives() 849 { 850 OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives; 851 if (!map) 852 map.set(new CounterDirectiveMap); 853 return *map.get(); 854 } 855 856 const AtomicString& RenderStyle::hyphenString() const 857 { 858 ASSERT(hyphens() != HyphensNone); 859 860 const AtomicString& hyphenationString = rareInheritedData.get()->hyphenationString; 861 if (!hyphenationString.isNull()) 862 return hyphenationString; 863 864 // FIXME: This should depend on locale. 865 DEFINE_STATIC_LOCAL(AtomicString, hyphenMinusString, (&hyphenMinus, 1)); 866 DEFINE_STATIC_LOCAL(AtomicString, hyphenString, (&hyphen, 1)); 867 return font().primaryFontHasGlyphForCharacter(hyphen) ? hyphenString : hyphenMinusString; 868 } 869 870 const AtomicString& RenderStyle::textEmphasisMarkString() const 871 { 872 switch (textEmphasisMark()) { 873 case TextEmphasisMarkNone: 874 return nullAtom; 875 case TextEmphasisMarkCustom: 876 return textEmphasisCustomMark(); 877 case TextEmphasisMarkDot: { 878 DEFINE_STATIC_LOCAL(AtomicString, filledDotString, (&bullet, 1)); 879 DEFINE_STATIC_LOCAL(AtomicString, openDotString, (&whiteBullet, 1)); 880 return textEmphasisFill() == TextEmphasisFillFilled ? filledDotString : openDotString; 881 } 882 case TextEmphasisMarkCircle: { 883 DEFINE_STATIC_LOCAL(AtomicString, filledCircleString, (&blackCircle, 1)); 884 DEFINE_STATIC_LOCAL(AtomicString, openCircleString, (&whiteCircle, 1)); 885 return textEmphasisFill() == TextEmphasisFillFilled ? filledCircleString : openCircleString; 886 } 887 case TextEmphasisMarkDoubleCircle: { 888 DEFINE_STATIC_LOCAL(AtomicString, filledDoubleCircleString, (&fisheye, 1)); 889 DEFINE_STATIC_LOCAL(AtomicString, openDoubleCircleString, (&bullseye, 1)); 890 return textEmphasisFill() == TextEmphasisFillFilled ? filledDoubleCircleString : openDoubleCircleString; 891 } 892 case TextEmphasisMarkTriangle: { 893 DEFINE_STATIC_LOCAL(AtomicString, filledTriangleString, (&blackUpPointingTriangle, 1)); 894 DEFINE_STATIC_LOCAL(AtomicString, openTriangleString, (&whiteUpPointingTriangle, 1)); 895 return textEmphasisFill() == TextEmphasisFillFilled ? filledTriangleString : openTriangleString; 896 } 897 case TextEmphasisMarkSesame: { 898 DEFINE_STATIC_LOCAL(AtomicString, filledSesameString, (&sesameDot, 1)); 899 DEFINE_STATIC_LOCAL(AtomicString, openSesameString, (&whiteSesameDot, 1)); 900 return textEmphasisFill() == TextEmphasisFillFilled ? filledSesameString : openSesameString; 901 } 902 case TextEmphasisMarkAuto: 903 ASSERT_NOT_REACHED(); 904 return nullAtom; 905 } 906 907 ASSERT_NOT_REACHED(); 908 return nullAtom; 909 } 910 911 #if ENABLE(DASHBOARD_SUPPORT) 912 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions() 913 { 914 DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ()); 915 return emptyList; 916 } 917 918 const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions() 919 { 920 DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, noneList, ()); 921 static bool noneListInitialized = false; 922 923 if (!noneListInitialized) { 924 StyleDashboardRegion region; 925 region.label = ""; 926 region.offset.m_top = Length(); 927 region.offset.m_right = Length(); 928 region.offset.m_bottom = Length(); 929 region.offset.m_left = Length(); 930 region.type = StyleDashboardRegion::None; 931 noneList.append(region); 932 noneListInitialized = true; 933 } 934 return noneList; 935 } 936 #endif 937 938 void RenderStyle::adjustAnimations() 939 { 940 AnimationList* animationList = rareNonInheritedData->m_animations.get(); 941 if (!animationList) 942 return; 943 944 // Get rid of empty animations and anything beyond them 945 for (size_t i = 0; i < animationList->size(); ++i) { 946 if (animationList->animation(i)->isEmpty()) { 947 animationList->resize(i); 948 break; 949 } 950 } 951 952 if (animationList->isEmpty()) { 953 clearAnimations(); 954 return; 955 } 956 957 // Repeat patterns into layers that don't have some properties set. 958 animationList->fillUnsetProperties(); 959 } 960 961 void RenderStyle::adjustTransitions() 962 { 963 AnimationList* transitionList = rareNonInheritedData->m_transitions.get(); 964 if (!transitionList) 965 return; 966 967 // Get rid of empty transitions and anything beyond them 968 for (size_t i = 0; i < transitionList->size(); ++i) { 969 if (transitionList->animation(i)->isEmpty()) { 970 transitionList->resize(i); 971 break; 972 } 973 } 974 975 if (transitionList->isEmpty()) { 976 clearTransitions(); 977 return; 978 } 979 980 // Repeat patterns into layers that don't have some properties set. 981 transitionList->fillUnsetProperties(); 982 983 // Make sure there are no duplicate properties. This is an O(n^2) algorithm 984 // but the lists tend to be very short, so it is probably ok 985 for (size_t i = 0; i < transitionList->size(); ++i) { 986 for (size_t j = i+1; j < transitionList->size(); ++j) { 987 if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) { 988 // toss i 989 transitionList->remove(i); 990 j = i; 991 } 992 } 993 } 994 } 995 996 AnimationList* RenderStyle::accessAnimations() 997 { 998 if (!rareNonInheritedData.access()->m_animations) 999 rareNonInheritedData.access()->m_animations.set(new AnimationList()); 1000 return rareNonInheritedData->m_animations.get(); 1001 } 1002 1003 AnimationList* RenderStyle::accessTransitions() 1004 { 1005 if (!rareNonInheritedData.access()->m_transitions) 1006 rareNonInheritedData.access()->m_transitions.set(new AnimationList()); 1007 return rareNonInheritedData->m_transitions.get(); 1008 } 1009 1010 const Animation* RenderStyle::transitionForProperty(int property) const 1011 { 1012 if (transitions()) { 1013 for (size_t i = 0; i < transitions()->size(); ++i) { 1014 const Animation* p = transitions()->animation(i); 1015 if (p->property() == cAnimateAll || p->property() == property) { 1016 return p; 1017 } 1018 } 1019 } 1020 return 0; 1021 } 1022 1023 void RenderStyle::setBlendedFontSize(int size) 1024 { 1025 FontSelector* currentFontSelector = font().fontSelector(); 1026 FontDescription desc(fontDescription()); 1027 desc.setSpecifiedSize(size); 1028 desc.setComputedSize(size); 1029 setFontDescription(desc); 1030 font().update(currentFontSelector); 1031 } 1032 1033 void RenderStyle::getShadowExtent(const ShadowData* shadow, int &top, int &right, int &bottom, int &left) const 1034 { 1035 top = 0; 1036 right = 0; 1037 bottom = 0; 1038 left = 0; 1039 1040 for ( ; shadow; shadow = shadow->next()) { 1041 if (shadow->style() == Inset) 1042 continue; 1043 int blurAndSpread = shadow->blur() + shadow->spread(); 1044 1045 top = min(top, shadow->y() - blurAndSpread); 1046 right = max(right, shadow->x() + blurAndSpread); 1047 bottom = max(bottom, shadow->y() + blurAndSpread); 1048 left = min(left, shadow->x() - blurAndSpread); 1049 } 1050 } 1051 1052 void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, int &left, int &right) const 1053 { 1054 left = 0; 1055 right = 0; 1056 1057 for ( ; shadow; shadow = shadow->next()) { 1058 if (shadow->style() == Inset) 1059 continue; 1060 int blurAndSpread = shadow->blur() + shadow->spread(); 1061 1062 left = min(left, shadow->x() - blurAndSpread); 1063 right = max(right, shadow->x() + blurAndSpread); 1064 } 1065 } 1066 1067 void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, int &top, int &bottom) const 1068 { 1069 top = 0; 1070 bottom = 0; 1071 1072 for ( ; shadow; shadow = shadow->next()) { 1073 if (shadow->style() == Inset) 1074 continue; 1075 int blurAndSpread = shadow->blur() + shadow->spread(); 1076 1077 top = min(top, shadow->y() - blurAndSpread); 1078 bottom = max(bottom, shadow->y() + blurAndSpread); 1079 } 1080 } 1081 1082 static EBorderStyle borderStyleForColorProperty(const RenderStyle* style, int colorProperty) 1083 { 1084 EBorderStyle borderStyle; 1085 switch (colorProperty) { 1086 case CSSPropertyBorderLeftColor: 1087 borderStyle = style->borderLeftStyle(); 1088 break; 1089 case CSSPropertyBorderRightColor: 1090 borderStyle = style->borderRightStyle(); 1091 break; 1092 case CSSPropertyBorderTopColor: 1093 borderStyle = style->borderTopStyle(); 1094 break; 1095 case CSSPropertyBorderBottomColor: 1096 borderStyle = style->borderBottomStyle(); 1097 break; 1098 default: 1099 borderStyle = BNONE; 1100 break; 1101 } 1102 return borderStyle; 1103 } 1104 1105 const Color RenderStyle::colorIncludingFallback(int colorProperty, EBorderStyle borderStyle) const 1106 { 1107 Color result; 1108 switch (colorProperty) { 1109 case CSSPropertyBackgroundColor: 1110 return backgroundColor(); // Background color doesn't fall back. 1111 case CSSPropertyBorderLeftColor: 1112 result = borderLeftColor(); 1113 borderStyle = borderLeftStyle(); 1114 break; 1115 case CSSPropertyBorderRightColor: 1116 result = borderRightColor(); 1117 borderStyle = borderRightStyle(); 1118 break; 1119 case CSSPropertyBorderTopColor: 1120 result = borderTopColor(); 1121 borderStyle = borderTopStyle(); 1122 break; 1123 case CSSPropertyBorderBottomColor: 1124 result = borderBottomColor(); 1125 borderStyle = borderBottomStyle(); 1126 break; 1127 case CSSPropertyColor: 1128 result = color(); 1129 break; 1130 case CSSPropertyOutlineColor: 1131 result = outlineColor(); 1132 break; 1133 case CSSPropertyWebkitColumnRuleColor: 1134 result = columnRuleColor(); 1135 break; 1136 case CSSPropertyWebkitTextEmphasisColor: 1137 result = textEmphasisColor(); 1138 break; 1139 case CSSPropertyWebkitTextFillColor: 1140 result = textFillColor(); 1141 break; 1142 case CSSPropertyWebkitTextStrokeColor: 1143 result = textStrokeColor(); 1144 break; 1145 default: 1146 ASSERT_NOT_REACHED(); 1147 break; 1148 } 1149 1150 if (!result.isValid()) { 1151 if ((colorProperty == CSSPropertyBorderLeftColor || colorProperty == CSSPropertyBorderRightColor 1152 || colorProperty == CSSPropertyBorderTopColor || colorProperty == CSSPropertyBorderBottomColor) 1153 && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE)) 1154 result.setRGB(238, 238, 238); 1155 else 1156 result = color(); 1157 } 1158 1159 return result; 1160 } 1161 1162 const Color RenderStyle::visitedDependentColor(int colorProperty) const 1163 { 1164 EBorderStyle borderStyle = borderStyleForColorProperty(this, colorProperty); 1165 Color unvisitedColor = colorIncludingFallback(colorProperty, borderStyle); 1166 if (insideLink() != InsideVisitedLink) 1167 return unvisitedColor; 1168 1169 RenderStyle* visitedStyle = getCachedPseudoStyle(VISITED_LINK); 1170 if (!visitedStyle) 1171 return unvisitedColor; 1172 Color visitedColor = visitedStyle->colorIncludingFallback(colorProperty, borderStyle); 1173 1174 // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just 1175 // assume that if the background color is transparent that it wasn't set. Note that it's weird that 1176 // we're returning unvisited info for a visited link, but given our restriction that the alpha values 1177 // have to match, it makes more sense to return the unvisited background color if specified than it 1178 // does to return black. This behavior matches what Firefox 4 does as well. 1179 if (colorProperty == CSSPropertyBackgroundColor && visitedColor == Color::transparent) 1180 return unvisitedColor; 1181 1182 // Take the alpha from the unvisited color, but get the RGB values from the visited color. 1183 return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha()); 1184 } 1185 1186 Length RenderStyle::logicalWidth() const 1187 { 1188 if (isHorizontalWritingMode()) 1189 return width(); 1190 return height(); 1191 } 1192 1193 Length RenderStyle::logicalHeight() const 1194 { 1195 if (isHorizontalWritingMode()) 1196 return height(); 1197 return width(); 1198 } 1199 1200 Length RenderStyle::logicalMinWidth() const 1201 { 1202 if (isHorizontalWritingMode()) 1203 return minWidth(); 1204 return minHeight(); 1205 } 1206 1207 Length RenderStyle::logicalMaxWidth() const 1208 { 1209 if (isHorizontalWritingMode()) 1210 return maxWidth(); 1211 return maxHeight(); 1212 } 1213 1214 Length RenderStyle::logicalMinHeight() const 1215 { 1216 if (isHorizontalWritingMode()) 1217 return minHeight(); 1218 return minWidth(); 1219 } 1220 1221 Length RenderStyle::logicalMaxHeight() const 1222 { 1223 if (isHorizontalWritingMode()) 1224 return maxHeight(); 1225 return maxWidth(); 1226 } 1227 1228 const BorderValue& RenderStyle::borderBefore() const 1229 { 1230 switch (writingMode()) { 1231 case TopToBottomWritingMode: 1232 return borderTop(); 1233 case BottomToTopWritingMode: 1234 return borderBottom(); 1235 case LeftToRightWritingMode: 1236 return borderLeft(); 1237 case RightToLeftWritingMode: 1238 return borderRight(); 1239 } 1240 ASSERT_NOT_REACHED(); 1241 return borderTop(); 1242 } 1243 1244 const BorderValue& RenderStyle::borderAfter() const 1245 { 1246 switch (writingMode()) { 1247 case TopToBottomWritingMode: 1248 return borderBottom(); 1249 case BottomToTopWritingMode: 1250 return borderTop(); 1251 case LeftToRightWritingMode: 1252 return borderRight(); 1253 case RightToLeftWritingMode: 1254 return borderLeft(); 1255 } 1256 ASSERT_NOT_REACHED(); 1257 return borderBottom(); 1258 } 1259 1260 const BorderValue& RenderStyle::borderStart() const 1261 { 1262 if (isHorizontalWritingMode()) 1263 return isLeftToRightDirection() ? borderLeft() : borderRight(); 1264 return isLeftToRightDirection() ? borderTop() : borderBottom(); 1265 } 1266 1267 const BorderValue& RenderStyle::borderEnd() const 1268 { 1269 if (isHorizontalWritingMode()) 1270 return isLeftToRightDirection() ? borderRight() : borderLeft(); 1271 return isLeftToRightDirection() ? borderBottom() : borderTop(); 1272 } 1273 1274 unsigned short RenderStyle::borderBeforeWidth() const 1275 { 1276 switch (writingMode()) { 1277 case TopToBottomWritingMode: 1278 return borderTopWidth(); 1279 case BottomToTopWritingMode: 1280 return borderBottomWidth(); 1281 case LeftToRightWritingMode: 1282 return borderLeftWidth(); 1283 case RightToLeftWritingMode: 1284 return borderRightWidth(); 1285 } 1286 ASSERT_NOT_REACHED(); 1287 return borderTopWidth(); 1288 } 1289 1290 unsigned short RenderStyle::borderAfterWidth() const 1291 { 1292 switch (writingMode()) { 1293 case TopToBottomWritingMode: 1294 return borderBottomWidth(); 1295 case BottomToTopWritingMode: 1296 return borderTopWidth(); 1297 case LeftToRightWritingMode: 1298 return borderRightWidth(); 1299 case RightToLeftWritingMode: 1300 return borderLeftWidth(); 1301 } 1302 ASSERT_NOT_REACHED(); 1303 return borderBottomWidth(); 1304 } 1305 1306 unsigned short RenderStyle::borderStartWidth() const 1307 { 1308 if (isHorizontalWritingMode()) 1309 return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth(); 1310 return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth(); 1311 } 1312 1313 unsigned short RenderStyle::borderEndWidth() const 1314 { 1315 if (isHorizontalWritingMode()) 1316 return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth(); 1317 return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth(); 1318 } 1319 1320 Length RenderStyle::marginBefore() const 1321 { 1322 switch (writingMode()) { 1323 case TopToBottomWritingMode: 1324 return marginTop(); 1325 case BottomToTopWritingMode: 1326 return marginBottom(); 1327 case LeftToRightWritingMode: 1328 return marginLeft(); 1329 case RightToLeftWritingMode: 1330 return marginRight(); 1331 } 1332 ASSERT_NOT_REACHED(); 1333 return marginTop(); 1334 } 1335 1336 Length RenderStyle::marginAfter() const 1337 { 1338 switch (writingMode()) { 1339 case TopToBottomWritingMode: 1340 return marginBottom(); 1341 case BottomToTopWritingMode: 1342 return marginTop(); 1343 case LeftToRightWritingMode: 1344 return marginRight(); 1345 case RightToLeftWritingMode: 1346 return marginLeft(); 1347 } 1348 ASSERT_NOT_REACHED(); 1349 return marginBottom(); 1350 } 1351 1352 Length RenderStyle::marginBeforeUsing(const RenderStyle* otherStyle) const 1353 { 1354 switch (otherStyle->writingMode()) { 1355 case TopToBottomWritingMode: 1356 return marginTop(); 1357 case BottomToTopWritingMode: 1358 return marginBottom(); 1359 case LeftToRightWritingMode: 1360 return marginLeft(); 1361 case RightToLeftWritingMode: 1362 return marginRight(); 1363 } 1364 ASSERT_NOT_REACHED(); 1365 return marginTop(); 1366 } 1367 1368 Length RenderStyle::marginAfterUsing(const RenderStyle* otherStyle) const 1369 { 1370 switch (otherStyle->writingMode()) { 1371 case TopToBottomWritingMode: 1372 return marginBottom(); 1373 case BottomToTopWritingMode: 1374 return marginTop(); 1375 case LeftToRightWritingMode: 1376 return marginRight(); 1377 case RightToLeftWritingMode: 1378 return marginLeft(); 1379 } 1380 ASSERT_NOT_REACHED(); 1381 return marginBottom(); 1382 } 1383 1384 Length RenderStyle::marginStart() const 1385 { 1386 if (isHorizontalWritingMode()) 1387 return isLeftToRightDirection() ? marginLeft() : marginRight(); 1388 return isLeftToRightDirection() ? marginTop() : marginBottom(); 1389 } 1390 1391 Length RenderStyle::marginEnd() const 1392 { 1393 if (isHorizontalWritingMode()) 1394 return isLeftToRightDirection() ? marginRight() : marginLeft(); 1395 return isLeftToRightDirection() ? marginBottom() : marginTop(); 1396 } 1397 1398 Length RenderStyle::marginStartUsing(const RenderStyle* otherStyle) const 1399 { 1400 if (otherStyle->isHorizontalWritingMode()) 1401 return otherStyle->isLeftToRightDirection() ? marginLeft() : marginRight(); 1402 return otherStyle->isLeftToRightDirection() ? marginTop() : marginBottom(); 1403 } 1404 1405 Length RenderStyle::marginEndUsing(const RenderStyle* otherStyle) const 1406 { 1407 if (otherStyle->isHorizontalWritingMode()) 1408 return otherStyle->isLeftToRightDirection() ? marginRight() : marginLeft(); 1409 return otherStyle->isLeftToRightDirection() ? marginBottom() : marginTop(); 1410 } 1411 1412 void RenderStyle::setMarginStart(Length margin) 1413 { 1414 if (isHorizontalWritingMode()) { 1415 if (isLeftToRightDirection()) 1416 setMarginLeft(margin); 1417 else 1418 setMarginRight(margin); 1419 } else { 1420 if (isLeftToRightDirection()) 1421 setMarginTop(margin); 1422 else 1423 setMarginBottom(margin); 1424 } 1425 } 1426 1427 void RenderStyle::setMarginEnd(Length margin) 1428 { 1429 if (isHorizontalWritingMode()) { 1430 if (isLeftToRightDirection()) 1431 setMarginRight(margin); 1432 else 1433 setMarginLeft(margin); 1434 } else { 1435 if (isLeftToRightDirection()) 1436 setMarginBottom(margin); 1437 else 1438 setMarginTop(margin); 1439 } 1440 } 1441 1442 Length RenderStyle::paddingBefore() const 1443 { 1444 switch (writingMode()) { 1445 case TopToBottomWritingMode: 1446 return paddingTop(); 1447 case BottomToTopWritingMode: 1448 return paddingBottom(); 1449 case LeftToRightWritingMode: 1450 return paddingLeft(); 1451 case RightToLeftWritingMode: 1452 return paddingRight(); 1453 } 1454 ASSERT_NOT_REACHED(); 1455 return paddingTop(); 1456 } 1457 1458 Length RenderStyle::paddingAfter() const 1459 { 1460 switch (writingMode()) { 1461 case TopToBottomWritingMode: 1462 return paddingBottom(); 1463 case BottomToTopWritingMode: 1464 return paddingTop(); 1465 case LeftToRightWritingMode: 1466 return paddingRight(); 1467 case RightToLeftWritingMode: 1468 return paddingLeft(); 1469 } 1470 ASSERT_NOT_REACHED(); 1471 return paddingBottom(); 1472 } 1473 1474 Length RenderStyle::paddingStart() const 1475 { 1476 if (isHorizontalWritingMode()) 1477 return isLeftToRightDirection() ? paddingLeft() : paddingRight(); 1478 return isLeftToRightDirection() ? paddingTop() : paddingBottom(); 1479 } 1480 1481 Length RenderStyle::paddingEnd() const 1482 { 1483 if (isHorizontalWritingMode()) 1484 return isLeftToRightDirection() ? paddingRight() : paddingLeft(); 1485 return isLeftToRightDirection() ? paddingBottom() : paddingTop(); 1486 } 1487 1488 TextEmphasisMark RenderStyle::textEmphasisMark() const 1489 { 1490 TextEmphasisMark mark = static_cast<TextEmphasisMark>(rareInheritedData->textEmphasisMark); 1491 if (mark != TextEmphasisMarkAuto) 1492 return mark; 1493 1494 if (isHorizontalWritingMode()) 1495 return TextEmphasisMarkDot; 1496 1497 return TextEmphasisMarkSesame; 1498 } 1499 1500 } // namespace WebCore 1501