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 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #include "config.h" 24 #include "core/rendering/style/RenderStyle.h" 25 26 #include <algorithm> 27 #include "RuntimeEnabledFeatures.h" 28 #include "core/css/resolver/StyleResolver.h" 29 #include "core/rendering/RenderTheme.h" 30 #include "core/rendering/TextAutosizer.h" 31 #include "core/rendering/style/ContentData.h" 32 #include "core/rendering/style/CursorList.h" 33 #include "core/rendering/style/QuotesData.h" 34 #include "core/rendering/style/ShadowList.h" 35 #include "core/rendering/style/StyleImage.h" 36 #include "core/rendering/style/StyleInheritedData.h" 37 #include "platform/fonts/Font.h" 38 #include "platform/fonts/FontSelector.h" 39 #include "wtf/MathExtras.h" 40 41 using namespace std; 42 43 namespace WebCore { 44 45 struct SameSizeAsBorderValue { 46 RGBA32 m_color; 47 unsigned m_width; 48 }; 49 50 COMPILE_ASSERT(sizeof(BorderValue) == sizeof(SameSizeAsBorderValue), BorderValue_should_not_grow); 51 52 struct SameSizeAsRenderStyle : public RefCounted<SameSizeAsRenderStyle> { 53 void* dataRefs[7]; 54 void* ownPtrs[1]; 55 void* dataRefSvgStyle; 56 57 struct InheritedFlags { 58 unsigned m_bitfields[2]; 59 } inherited_flags; 60 61 struct NonInheritedFlags { 62 unsigned m_bitfields[2]; 63 } noninherited_flags; 64 }; 65 66 COMPILE_ASSERT(sizeof(RenderStyle) == sizeof(SameSizeAsRenderStyle), RenderStyle_should_stay_small); 67 68 inline RenderStyle* defaultStyle() 69 { 70 DEFINE_STATIC_REF(RenderStyle, s_defaultStyle, (RenderStyle::createDefaultStyle())); 71 return s_defaultStyle; 72 } 73 74 PassRefPtr<RenderStyle> RenderStyle::create() 75 { 76 return adoptRef(new RenderStyle()); 77 } 78 79 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle() 80 { 81 return adoptRef(new RenderStyle(DefaultStyle)); 82 } 83 84 PassRefPtr<RenderStyle> RenderStyle::createAnonymousStyleWithDisplay(const RenderStyle* parentStyle, EDisplay display) 85 { 86 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 87 newStyle->inheritFrom(parentStyle); 88 newStyle->inheritUnicodeBidiFrom(parentStyle); 89 newStyle->setDisplay(display); 90 return newStyle; 91 } 92 93 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other) 94 { 95 return adoptRef(new RenderStyle(*other)); 96 } 97 98 ALWAYS_INLINE RenderStyle::RenderStyle() 99 : m_box(defaultStyle()->m_box) 100 , visual(defaultStyle()->visual) 101 , m_background(defaultStyle()->m_background) 102 , surround(defaultStyle()->surround) 103 , rareNonInheritedData(defaultStyle()->rareNonInheritedData) 104 , rareInheritedData(defaultStyle()->rareInheritedData) 105 , inherited(defaultStyle()->inherited) 106 , m_svgStyle(defaultStyle()->m_svgStyle) 107 { 108 setBitDefaults(); // Would it be faster to copy this from the default style? 109 COMPILE_ASSERT((sizeof(InheritedFlags) <= 8), InheritedFlags_does_not_grow); 110 COMPILE_ASSERT((sizeof(NonInheritedFlags) <= 8), NonInheritedFlags_does_not_grow); 111 } 112 113 ALWAYS_INLINE RenderStyle::RenderStyle(DefaultStyleTag) 114 { 115 setBitDefaults(); 116 117 m_box.init(); 118 visual.init(); 119 m_background.init(); 120 surround.init(); 121 rareNonInheritedData.init(); 122 rareNonInheritedData.access()->m_deprecatedFlexibleBox.init(); 123 rareNonInheritedData.access()->m_flexibleBox.init(); 124 rareNonInheritedData.access()->m_marquee.init(); 125 rareNonInheritedData.access()->m_multiCol.init(); 126 rareNonInheritedData.access()->m_transform.init(); 127 rareNonInheritedData.access()->m_filter.init(); 128 rareNonInheritedData.access()->m_grid.init(); 129 rareNonInheritedData.access()->m_gridItem.init(); 130 rareInheritedData.init(); 131 inherited.init(); 132 m_svgStyle.init(); 133 } 134 135 ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o) 136 : RefCounted<RenderStyle>() 137 , m_box(o.m_box) 138 , visual(o.visual) 139 , m_background(o.m_background) 140 , surround(o.surround) 141 , rareNonInheritedData(o.rareNonInheritedData) 142 , rareInheritedData(o.rareInheritedData) 143 , inherited(o.inherited) 144 , m_svgStyle(o.m_svgStyle) 145 , inherited_flags(o.inherited_flags) 146 , noninherited_flags(o.noninherited_flags) 147 { 148 } 149 150 static StyleRecalcChange comparePseudoStyles(const RenderStyle* oldStyle, const RenderStyle* newStyle) 151 { 152 // If the pseudoStyles have changed, we want any StyleRecalcChange that is not NoChange 153 // because setStyle will do the right thing with anything else. 154 if (!oldStyle->hasAnyPublicPseudoStyles()) 155 return NoChange; 156 for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < FIRST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) { 157 if (!oldStyle->hasPseudoStyle(pseudoId)) 158 continue; 159 RenderStyle* newPseudoStyle = newStyle->getCachedPseudoStyle(pseudoId); 160 if (!newPseudoStyle) 161 return NoInherit; 162 RenderStyle* oldPseudoStyle = oldStyle->getCachedPseudoStyle(pseudoId); 163 if (oldPseudoStyle && *oldPseudoStyle != *newPseudoStyle) 164 return NoInherit; 165 } 166 return NoChange; 167 } 168 169 StyleRecalcChange RenderStyle::compare(const RenderStyle* oldStyle, const RenderStyle* newStyle) 170 { 171 if ((!oldStyle && newStyle) || (oldStyle && !newStyle)) 172 return Reattach; 173 174 if (!oldStyle && !newStyle) 175 return NoChange; 176 177 if (oldStyle->display() != newStyle->display() 178 || oldStyle->hasPseudoStyle(FIRST_LETTER) != newStyle->hasPseudoStyle(FIRST_LETTER) 179 || oldStyle->columnSpan() != newStyle->columnSpan() 180 || oldStyle->specifiesAutoColumns() != newStyle->specifiesAutoColumns() 181 || !oldStyle->contentDataEquivalent(newStyle) 182 || oldStyle->hasTextCombine() != newStyle->hasTextCombine() 183 || oldStyle->flowThread() != newStyle->flowThread() 184 || oldStyle->regionThread() != newStyle->regionThread()) 185 return Reattach; 186 187 if (*oldStyle == *newStyle) 188 return comparePseudoStyles(oldStyle, newStyle); 189 190 if (oldStyle->inheritedNotEqual(newStyle) 191 || oldStyle->hasExplicitlyInheritedProperties() 192 || newStyle->hasExplicitlyInheritedProperties()) 193 return Inherit; 194 195 return NoInherit; 196 } 197 198 void RenderStyle::inheritFrom(const RenderStyle* inheritParent, IsAtShadowBoundary isAtShadowBoundary) 199 { 200 if (isAtShadowBoundary == AtShadowBoundary) { 201 // Even if surrounding content is user-editable, shadow DOM should act as a single unit, and not necessarily be editable 202 EUserModify currentUserModify = userModify(); 203 rareInheritedData = inheritParent->rareInheritedData; 204 setUserModify(currentUserModify); 205 } else 206 rareInheritedData = inheritParent->rareInheritedData; 207 inherited = inheritParent->inherited; 208 inherited_flags = inheritParent->inherited_flags; 209 if (m_svgStyle != inheritParent->m_svgStyle) 210 m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get()); 211 } 212 213 void RenderStyle::copyNonInheritedFrom(const RenderStyle* other) 214 { 215 m_box = other->m_box; 216 visual = other->visual; 217 m_background = other->m_background; 218 surround = other->surround; 219 rareNonInheritedData = other->rareNonInheritedData; 220 // The flags are copied one-by-one because noninherited_flags contains a bunch of stuff other than real style data. 221 noninherited_flags._effectiveDisplay = other->noninherited_flags._effectiveDisplay; 222 noninherited_flags._originalDisplay = other->noninherited_flags._originalDisplay; 223 noninherited_flags._overflowX = other->noninherited_flags._overflowX; 224 noninherited_flags._overflowY = other->noninherited_flags._overflowY; 225 noninherited_flags._vertical_align = other->noninherited_flags._vertical_align; 226 noninherited_flags._clear = other->noninherited_flags._clear; 227 noninherited_flags._position = other->noninherited_flags._position; 228 noninherited_flags._floating = other->noninherited_flags._floating; 229 noninherited_flags._table_layout = other->noninherited_flags._table_layout; 230 noninherited_flags._unicodeBidi = other->noninherited_flags._unicodeBidi; 231 noninherited_flags._page_break_before = other->noninherited_flags._page_break_before; 232 noninherited_flags._page_break_after = other->noninherited_flags._page_break_after; 233 noninherited_flags._page_break_inside = other->noninherited_flags._page_break_inside; 234 noninherited_flags.explicitInheritance = other->noninherited_flags.explicitInheritance; 235 noninherited_flags.currentColor = other->noninherited_flags.currentColor; 236 if (m_svgStyle != other->m_svgStyle) 237 m_svgStyle.access()->copyNonInheritedFrom(other->m_svgStyle.get()); 238 ASSERT(zoom() == initialZoom()); 239 } 240 241 bool RenderStyle::operator==(const RenderStyle& o) const 242 { 243 // compare everything except the pseudoStyle pointer 244 return inherited_flags == o.inherited_flags 245 && noninherited_flags == o.noninherited_flags 246 && m_box == o.m_box 247 && visual == o.visual 248 && m_background == o.m_background 249 && surround == o.surround 250 && rareNonInheritedData == o.rareNonInheritedData 251 && rareInheritedData == o.rareInheritedData 252 && inherited == o.inherited 253 && m_svgStyle == o.m_svgStyle; 254 } 255 256 bool RenderStyle::isStyleAvailable() const 257 { 258 return this != StyleResolver::styleNotYetAvailable(); 259 } 260 261 bool RenderStyle::hasUniquePseudoStyle() const 262 { 263 if (!m_cachedPseudoStyles || styleType() != NOPSEUDO) 264 return false; 265 266 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) { 267 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get(); 268 if (pseudoStyle->unique()) 269 return true; 270 } 271 272 return false; 273 } 274 275 RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const 276 { 277 if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size()) 278 return 0; 279 280 if (styleType() != NOPSEUDO) 281 return 0; 282 283 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) { 284 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get(); 285 if (pseudoStyle->styleType() == pid) 286 return pseudoStyle; 287 } 288 289 return 0; 290 } 291 292 RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo) 293 { 294 if (!pseudo) 295 return 0; 296 297 ASSERT(pseudo->styleType() > NOPSEUDO); 298 299 RenderStyle* result = pseudo.get(); 300 301 if (!m_cachedPseudoStyles) 302 m_cachedPseudoStyles = adoptPtr(new PseudoStyleCache); 303 304 m_cachedPseudoStyles->append(pseudo); 305 306 return result; 307 } 308 309 void RenderStyle::removeCachedPseudoStyle(PseudoId pid) 310 { 311 if (!m_cachedPseudoStyles) 312 return; 313 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) { 314 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get(); 315 if (pseudoStyle->styleType() == pid) { 316 m_cachedPseudoStyles->remove(i); 317 return; 318 } 319 } 320 } 321 322 bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const 323 { 324 return inherited_flags != other->inherited_flags 325 || inherited != other->inherited 326 || m_svgStyle->inheritedNotEqual(other->m_svgStyle.get()) 327 || rareInheritedData != other->rareInheritedData; 328 } 329 330 bool RenderStyle::inheritedDataShared(const RenderStyle* other) const 331 { 332 // This is a fast check that only looks if the data structures are shared. 333 return inherited_flags == other->inherited_flags 334 && inherited.get() == other->inherited.get() 335 && m_svgStyle.get() == other->m_svgStyle.get() 336 && rareInheritedData.get() == other->rareInheritedData.get(); 337 } 338 339 static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b, const Length& width) 340 { 341 // If any unit types are different, then we can't guarantee 342 // that this was just a movement. 343 if (a.left().type() != b.left().type() 344 || a.right().type() != b.right().type() 345 || a.top().type() != b.top().type() 346 || a.bottom().type() != b.bottom().type()) 347 return false; 348 349 // Only one unit can be non-auto in the horizontal direction and 350 // in the vertical direction. Otherwise the adjustment of values 351 // is changing the size of the box. 352 if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto()) 353 return false; 354 if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto()) 355 return false; 356 // If our width is auto and left or right is specified then this 357 // is not just a movement - we need to resize to our container. 358 if ((!a.left().isIntrinsicOrAuto() || !a.right().isIntrinsicOrAuto()) && width.isIntrinsicOrAuto()) 359 return false; 360 361 // One of the units is fixed or percent in both directions and stayed 362 // that way in the new style. Therefore all we are doing is moving. 363 return true; 364 } 365 366 StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const 367 { 368 changedContextSensitiveProperties = ContextSensitivePropertyNone; 369 370 StyleDifference svgChange = StyleDifferenceEqual; 371 if (m_svgStyle != other->m_svgStyle) { 372 svgChange = m_svgStyle->diff(other->m_svgStyle.get()); 373 if (svgChange == StyleDifferenceLayout) 374 return svgChange; 375 } 376 377 if (m_box->width() != other->m_box->width() 378 || m_box->minWidth() != other->m_box->minWidth() 379 || m_box->maxWidth() != other->m_box->maxWidth() 380 || m_box->height() != other->m_box->height() 381 || m_box->minHeight() != other->m_box->minHeight() 382 || m_box->maxHeight() != other->m_box->maxHeight()) 383 return StyleDifferenceLayout; 384 385 if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align) 386 return StyleDifferenceLayout; 387 388 if (m_box->boxSizing() != other->m_box->boxSizing()) 389 return StyleDifferenceLayout; 390 391 if (surround->margin != other->surround->margin) 392 return StyleDifferenceLayout; 393 394 if (surround->padding != other->surround->padding) 395 return StyleDifferenceLayout; 396 397 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { 398 if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance 399 || rareNonInheritedData->marginBeforeCollapse != other->rareNonInheritedData->marginBeforeCollapse 400 || rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse 401 || rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp 402 || rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow) 403 return StyleDifferenceLayout; 404 405 if (rareNonInheritedData->m_regionFragment != other->rareNonInheritedData->m_regionFragment) 406 return StyleDifferenceLayout; 407 408 if (rareNonInheritedData->m_wrapFlow != other->rareNonInheritedData->m_wrapFlow 409 || rareNonInheritedData->m_wrapThrough != other->rareNonInheritedData->m_wrapThrough 410 || rareNonInheritedData->m_shapeMargin != other->rareNonInheritedData->m_shapeMargin 411 || rareNonInheritedData->m_shapePadding != other->rareNonInheritedData->m_shapePadding) 412 return StyleDifferenceLayout; 413 414 if (rareNonInheritedData->m_deprecatedFlexibleBox.get() != other->rareNonInheritedData->m_deprecatedFlexibleBox.get() 415 && *rareNonInheritedData->m_deprecatedFlexibleBox.get() != *other->rareNonInheritedData->m_deprecatedFlexibleBox.get()) 416 return StyleDifferenceLayout; 417 418 if (rareNonInheritedData->m_flexibleBox.get() != other->rareNonInheritedData->m_flexibleBox.get() 419 && *rareNonInheritedData->m_flexibleBox.get() != *other->rareNonInheritedData->m_flexibleBox.get()) 420 return StyleDifferenceLayout; 421 if (rareNonInheritedData->m_order != other->rareNonInheritedData->m_order 422 || rareNonInheritedData->m_alignContent != other->rareNonInheritedData->m_alignContent 423 || rareNonInheritedData->m_alignItems != other->rareNonInheritedData->m_alignItems 424 || rareNonInheritedData->m_alignSelf != other->rareNonInheritedData->m_alignSelf 425 || rareNonInheritedData->m_justifyContent != other->rareNonInheritedData->m_justifyContent) 426 return StyleDifferenceLayout; 427 428 // FIXME: We should add an optimized form of layout that just recomputes visual overflow. 429 if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get())) 430 return StyleDifferenceLayout; 431 432 if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get())) 433 return StyleDifferenceLayout; 434 435 if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() 436 && *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get()) 437 return StyleDifferenceLayout; 438 439 if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() 440 && *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) { 441 // Don't return early here; instead take note of the type of 442 // change, and deal with it when looking at compositing. 443 changedContextSensitiveProperties |= ContextSensitivePropertyTransform; 444 } 445 446 if (rareNonInheritedData->m_grid.get() != other->rareNonInheritedData->m_grid.get() 447 || rareNonInheritedData->m_gridItem.get() != other->rareNonInheritedData->m_gridItem.get()) 448 return StyleDifferenceLayout; 449 450 if (rareNonInheritedData->m_shapeInside != other->rareNonInheritedData->m_shapeInside) 451 return StyleDifferenceLayout; 452 } 453 454 if (rareInheritedData.get() != other->rareInheritedData.get()) { 455 if (rareInheritedData->highlight != other->rareInheritedData->highlight 456 || rareInheritedData->indent != other->rareInheritedData->indent 457 || rareInheritedData->m_textAlignLast != other->rareInheritedData->m_textAlignLast 458 || rareInheritedData->m_textIndentLine != other->rareInheritedData->m_textIndentLine 459 || rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom 460 || rareInheritedData->wordBreak != other->rareInheritedData->wordBreak 461 || rareInheritedData->overflowWrap != other->rareInheritedData->overflowWrap 462 || rareInheritedData->lineBreak != other->rareInheritedData->lineBreak 463 || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity 464 || rareInheritedData->hyphens != other->rareInheritedData->hyphens 465 || rareInheritedData->hyphenationLimitBefore != other->rareInheritedData->hyphenationLimitBefore 466 || rareInheritedData->hyphenationLimitAfter != other->rareInheritedData->hyphenationLimitAfter 467 || rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString 468 || rareInheritedData->locale != other->rareInheritedData->locale 469 || rareInheritedData->m_rubyPosition != other->rareInheritedData->m_rubyPosition 470 || rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark 471 || rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition 472 || rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark 473 || rareInheritedData->m_textAlignLast != other->rareInheritedData->m_textAlignLast 474 || rareInheritedData->m_textJustify != other->rareInheritedData->m_textJustify 475 || rareInheritedData->m_textOrientation != other->rareInheritedData->m_textOrientation 476 || rareInheritedData->m_tabSize != other->rareInheritedData->m_tabSize 477 || rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain 478 || rareInheritedData->m_lineGrid != other->rareInheritedData->m_lineGrid 479 || rareInheritedData->m_lineSnap != other->rareInheritedData->m_lineSnap 480 || rareInheritedData->m_lineAlign != other->rareInheritedData->m_lineAlign 481 || rareInheritedData->listStyleImage != other->rareInheritedData->listStyleImage) 482 return StyleDifferenceLayout; 483 484 if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get())) 485 return StyleDifferenceLayout; 486 487 if (textStrokeWidth() != other->textStrokeWidth()) 488 return StyleDifferenceLayout; 489 } 490 491 if (visual->m_textAutosizingMultiplier != other->visual->m_textAutosizingMultiplier) 492 return StyleDifferenceLayout; 493 494 if (inherited->line_height != other->inherited->line_height 495 || inherited->font != other->inherited->font 496 || inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing 497 || inherited->vertical_border_spacing != other->inherited->vertical_border_spacing 498 || inherited_flags._box_direction != other->inherited_flags._box_direction 499 || inherited_flags.m_rtlOrdering != other->inherited_flags.m_rtlOrdering 500 || noninherited_flags._position != other->noninherited_flags._position 501 || noninherited_flags._floating != other->noninherited_flags._floating 502 || noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay) 503 return StyleDifferenceLayout; 504 505 506 if (((int)noninherited_flags._effectiveDisplay) >= TABLE) { 507 if (inherited_flags._border_collapse != other->inherited_flags._border_collapse 508 || inherited_flags._empty_cells != other->inherited_flags._empty_cells 509 || inherited_flags._caption_side != other->inherited_flags._caption_side 510 || noninherited_flags._table_layout != other->noninherited_flags._table_layout) 511 return StyleDifferenceLayout; 512 513 // In the collapsing border model, 'hidden' suppresses other borders, while 'none' 514 // does not, so these style differences can be width differences. 515 if (inherited_flags._border_collapse 516 && ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE) 517 || (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN) 518 || (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE) 519 || (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN) 520 || (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE) 521 || (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN) 522 || (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE) 523 || (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN))) 524 return StyleDifferenceLayout; 525 } 526 527 if (noninherited_flags._effectiveDisplay == LIST_ITEM) { 528 if (inherited_flags._list_style_type != other->inherited_flags._list_style_type 529 || inherited_flags._list_style_position != other->inherited_flags._list_style_position) 530 return StyleDifferenceLayout; 531 } 532 533 if (inherited_flags._text_align != other->inherited_flags._text_align 534 || inherited_flags._text_transform != other->inherited_flags._text_transform 535 || inherited_flags._direction != other->inherited_flags._direction 536 || inherited_flags._white_space != other->inherited_flags._white_space 537 || noninherited_flags._clear != other->noninherited_flags._clear 538 || noninherited_flags._unicodeBidi != other->noninherited_flags._unicodeBidi) 539 return StyleDifferenceLayout; 540 541 // Check block flow direction. 542 if (inherited_flags.m_writingMode != other->inherited_flags.m_writingMode) 543 return StyleDifferenceLayout; 544 545 // Check text combine mode. 546 if (rareNonInheritedData->m_textCombine != other->rareNonInheritedData->m_textCombine) 547 return StyleDifferenceLayout; 548 549 // Overflow returns a layout hint. 550 if (noninherited_flags._overflowX != other->noninherited_flags._overflowX 551 || noninherited_flags._overflowY != other->noninherited_flags._overflowY) 552 return StyleDifferenceLayout; 553 554 // If our border widths change, then we need to layout. Other changes to borders 555 // only necessitate a repaint. 556 if (borderLeftWidth() != other->borderLeftWidth() 557 || borderTopWidth() != other->borderTopWidth() 558 || borderBottomWidth() != other->borderBottomWidth() 559 || borderRightWidth() != other->borderRightWidth()) 560 return StyleDifferenceLayout; 561 562 // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree. 563 const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get(); 564 const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get(); 565 if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB))) 566 return StyleDifferenceLayout; 567 568 if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE)) 569 return StyleDifferenceLayout; 570 571 if (rareNonInheritedData->hasOpacity() != other->rareNonInheritedData->hasOpacity()) { 572 // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet. 573 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need 574 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). 575 // In addition we need to solve the floating object issue when layers come and go. Right now 576 // a full layout is necessary to keep floating object lists sane. 577 return StyleDifferenceLayout; 578 } 579 580 if (rareNonInheritedData->hasFilters() != other->rareNonInheritedData->hasFilters()) 581 return StyleDifferenceLayout; 582 583 if (!QuotesData::equals(rareInheritedData->quotes.get(), other->rareInheritedData->quotes.get())) 584 return StyleDifferenceLayout; 585 586 // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes. 587 // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint, 588 // but have to return StyleDifferenceLayout, that's why this if branch comes after all branches 589 // that are relevant for SVG and might return StyleDifferenceLayout. 590 if (svgChange != StyleDifferenceEqual) 591 return svgChange; 592 593 // Make sure these left/top/right/bottom checks stay below all layout checks and above 594 // all visible checks. 595 if (position() != StaticPosition && surround->offset != other->surround->offset) { 596 // Optimize for the case where a positioned layer is moving but not changing size. 597 if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset, m_box->width()) && repaintOnlyDiff(other, changedContextSensitiveProperties) == StyleDifferenceEqual) 598 return StyleDifferenceLayoutPositionedMovementOnly; 599 600 // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet. 601 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need 602 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). 603 return StyleDifferenceLayout; 604 } 605 return repaintOnlyDiff(other, changedContextSensitiveProperties); 606 } 607 608 StyleDifference RenderStyle::repaintOnlyDiff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const 609 { 610 if (position() != StaticPosition && (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() 611 || visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)) 612 return StyleDifferenceRepaintLayer; 613 614 if (RuntimeEnabledFeatures::cssCompositingEnabled() && rareNonInheritedData->m_effectiveBlendMode != other->rareNonInheritedData->m_effectiveBlendMode) 615 return StyleDifferenceRepaintLayer; 616 617 if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) { 618 // Don't return early here; instead take note of the type of change, 619 // and deal with it when looking at compositing. 620 changedContextSensitiveProperties |= ContextSensitivePropertyOpacity; 621 } 622 623 if (rareNonInheritedData->m_filter.get() != other->rareNonInheritedData->m_filter.get() 624 && *rareNonInheritedData->m_filter.get() != *other->rareNonInheritedData->m_filter.get()) { 625 // Don't return early here; instead take note of the type of change, 626 // and deal with it when looking at compositing. 627 changedContextSensitiveProperties |= ContextSensitivePropertyFilter; 628 } 629 630 if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask 631 || rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage) 632 return StyleDifferenceRepaintLayer; 633 634 if (inherited_flags._visibility != other->inherited_flags._visibility 635 || inherited_flags.m_printColorAdjust != other->inherited_flags.m_printColorAdjust 636 || inherited_flags._insideLink != other->inherited_flags._insideLink 637 || surround->border != other->surround->border 638 || *m_background.get() != *other->m_background.get() 639 || rareInheritedData->userModify != other->rareInheritedData->userModify 640 || rareInheritedData->userSelect != other->rareInheritedData->userSelect 641 || rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag 642 || rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit 643 || rareNonInheritedData->m_objectFit != other->rareNonInheritedData->m_objectFit 644 || rareNonInheritedData->m_objectPosition != other->rareNonInheritedData->m_objectPosition 645 || rareInheritedData->m_imageRendering != other->rareInheritedData->m_imageRendering) 646 return StyleDifferenceRepaint; 647 648 // FIXME: The current spec is being reworked to remove dependencies between exclusions and affected 649 // content. There's a proposal to use floats instead. In that case, wrap-shape should actually relayout 650 // the parent container. For sure, I will have to revisit this code, but for now I've added this in order 651 // to avoid having diff() == StyleDifferenceEqual where wrap-shapes actually differ. 652 // Tracking bug: https://bugs.webkit.org/show_bug.cgi?id=62991 653 if (rareNonInheritedData->m_shapeOutside != other->rareNonInheritedData->m_shapeOutside) 654 return StyleDifferenceRepaint; 655 656 if (rareNonInheritedData->m_clipPath != other->rareNonInheritedData->m_clipPath) 657 return StyleDifferenceRepaint; 658 659 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { 660 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D 661 || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility 662 || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective 663 || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX 664 || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) 665 return StyleDifferenceRecompositeLayer; 666 } 667 668 if (inherited->color != other->inherited->color 669 || inherited_flags._text_decorations != other->inherited_flags._text_decorations 670 || visual->textDecoration != other->visual->textDecoration 671 || rareNonInheritedData->m_textDecorationStyle != other->rareNonInheritedData->m_textDecorationStyle 672 || rareNonInheritedData->m_textDecorationColor != other->rareNonInheritedData->m_textDecorationColor 673 || rareInheritedData->textFillColor != other->rareInheritedData->textFillColor 674 || rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor 675 || rareInheritedData->textEmphasisColor != other->rareInheritedData->textEmphasisColor 676 || rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill) 677 return StyleDifferenceRepaintIfTextOrColorChange; 678 679 // Cursors are not checked, since they will be set appropriately in response to mouse events, 680 // so they don't need to cause any repaint or layout. 681 682 // 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 683 // the resulting transition properly. 684 return StyleDifferenceEqual; 685 } 686 687 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left) 688 { 689 StyleVisualData* data = visual.access(); 690 data->clip.m_top = top; 691 data->clip.m_right = right; 692 data->clip.m_bottom = bottom; 693 data->clip.m_left = left; 694 } 695 696 void RenderStyle::addCursor(PassRefPtr<StyleImage> image, const IntPoint& hotSpot) 697 { 698 if (!rareInheritedData.access()->cursorData) 699 rareInheritedData.access()->cursorData = CursorList::create(); 700 rareInheritedData.access()->cursorData->append(CursorData(image, hotSpot)); 701 } 702 703 void RenderStyle::setCursorList(PassRefPtr<CursorList> other) 704 { 705 rareInheritedData.access()->cursorData = other; 706 } 707 708 void RenderStyle::setQuotes(PassRefPtr<QuotesData> q) 709 { 710 if (QuotesData::equals(rareInheritedData->quotes.get(), q.get())) 711 return; 712 rareInheritedData.access()->quotes = q; 713 } 714 715 void RenderStyle::clearCursorList() 716 { 717 if (rareInheritedData->cursorData) 718 rareInheritedData.access()->cursorData = 0; 719 } 720 721 void RenderStyle::addCallbackSelector(const String& selector) 722 { 723 if (!rareNonInheritedData->m_callbackSelectors.contains(selector)) 724 rareNonInheritedData.access()->m_callbackSelectors.append(selector); 725 } 726 727 void RenderStyle::clearContent() 728 { 729 if (rareNonInheritedData->m_content) 730 rareNonInheritedData.access()->m_content = nullptr; 731 } 732 733 void RenderStyle::appendContent(PassOwnPtr<ContentData> contentData) 734 { 735 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; 736 ContentData* lastContent = content.get(); 737 while (lastContent && lastContent->next()) 738 lastContent = lastContent->next(); 739 740 if (lastContent) 741 lastContent->setNext(contentData); 742 else 743 content = contentData; 744 } 745 746 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add) 747 { 748 if (!image) 749 return; 750 751 if (add) { 752 appendContent(ContentData::create(image)); 753 return; 754 } 755 756 rareNonInheritedData.access()->m_content = ContentData::create(image); 757 } 758 759 void RenderStyle::setContent(const String& string, bool add) 760 { 761 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; 762 if (add) { 763 ContentData* lastContent = content.get(); 764 while (lastContent && lastContent->next()) 765 lastContent = lastContent->next(); 766 767 if (lastContent) { 768 // We attempt to merge with the last ContentData if possible. 769 if (lastContent->isText()) { 770 TextContentData* textContent = static_cast<TextContentData*>(lastContent); 771 textContent->setText(textContent->text() + string); 772 } else 773 lastContent->setNext(ContentData::create(string)); 774 775 return; 776 } 777 } 778 779 content = ContentData::create(string); 780 } 781 782 void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add) 783 { 784 if (!counter) 785 return; 786 787 if (add) { 788 appendContent(ContentData::create(counter)); 789 return; 790 } 791 792 rareNonInheritedData.access()->m_content = ContentData::create(counter); 793 } 794 795 void RenderStyle::setContent(QuoteType quote, bool add) 796 { 797 if (add) { 798 appendContent(ContentData::create(quote)); 799 return; 800 } 801 802 rareNonInheritedData.access()->m_content = ContentData::create(quote); 803 } 804 805 blink::WebBlendMode RenderStyle::blendMode() const 806 { 807 if (RuntimeEnabledFeatures::cssCompositingEnabled()) 808 return static_cast<blink::WebBlendMode>(rareNonInheritedData->m_effectiveBlendMode); 809 return blink::WebBlendModeNormal; 810 } 811 812 void RenderStyle::setBlendMode(blink::WebBlendMode v) 813 { 814 if (RuntimeEnabledFeatures::cssCompositingEnabled()) 815 rareNonInheritedData.access()->m_effectiveBlendMode = v; 816 } 817 818 bool RenderStyle::hasBlendMode() const 819 { 820 if (RuntimeEnabledFeatures::cssCompositingEnabled()) 821 return static_cast<blink::WebBlendMode>(rareNonInheritedData->m_effectiveBlendMode) != blink::WebBlendModeNormal; 822 return false; 823 } 824 825 EIsolation RenderStyle::isolation() const 826 { 827 if (RuntimeEnabledFeatures::cssCompositingEnabled()) 828 return static_cast<EIsolation>(rareNonInheritedData->m_isolation); 829 return IsolationAuto; 830 } 831 832 void RenderStyle::setIsolation(EIsolation v) 833 { 834 if (RuntimeEnabledFeatures::cssCompositingEnabled()) 835 rareNonInheritedData.access()->m_isolation = v; 836 } 837 838 bool RenderStyle::hasIsolation() const 839 { 840 if (RuntimeEnabledFeatures::cssCompositingEnabled()) 841 return rareNonInheritedData->m_isolation != IsolationAuto; 842 return false; 843 } 844 845 inline bool requireTransformOrigin(const Vector<RefPtr<TransformOperation> >& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin) 846 { 847 // transform-origin brackets the transform with translate operations. 848 // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant 849 // in that case. 850 if (applyOrigin != RenderStyle::IncludeTransformOrigin) 851 return false; 852 853 unsigned size = transformOperations.size(); 854 for (unsigned i = 0; i < size; ++i) { 855 TransformOperation::OperationType type = transformOperations[i]->type(); 856 if (type != TransformOperation::TranslateX 857 && type != TransformOperation::TranslateY 858 && type != TransformOperation::Translate 859 && type != TransformOperation::TranslateZ 860 && type != TransformOperation::Translate3D) 861 return true; 862 } 863 864 return false; 865 } 866 867 void RenderStyle::applyTransform(TransformationMatrix& transform, const LayoutSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const 868 { 869 applyTransform(transform, FloatRect(FloatPoint(), borderBoxSize), applyOrigin); 870 } 871 872 void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin) const 873 { 874 const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations(); 875 bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin); 876 877 float offsetX = transformOriginX().type() == Percent ? boundingBox.x() : 0; 878 float offsetY = transformOriginY().type() == Percent ? boundingBox.y() : 0; 879 880 if (applyTransformOrigin) { 881 transform.translate3d(floatValueForLength(transformOriginX(), boundingBox.width(), 0) + offsetX, 882 floatValueForLength(transformOriginY(), boundingBox.height(), 0) + offsetY, 883 transformOriginZ()); 884 } 885 886 unsigned size = transformOperations.size(); 887 for (unsigned i = 0; i < size; ++i) 888 transformOperations[i]->apply(transform, boundingBox.size()); 889 890 if (applyTransformOrigin) { 891 transform.translate3d(-floatValueForLength(transformOriginX(), boundingBox.width(), 0) - offsetX, 892 -floatValueForLength(transformOriginY(), boundingBox.height(), 0) - offsetY, 893 -transformOriginZ()); 894 } 895 } 896 897 void RenderStyle::setTextShadow(PassRefPtr<ShadowList> s) 898 { 899 rareInheritedData.access()->textShadow = s; 900 } 901 902 void RenderStyle::setBoxShadow(PassRefPtr<ShadowList> s) 903 { 904 rareNonInheritedData.access()->m_boxShadow = s; 905 } 906 907 static RoundedRect::Radii calcRadiiFor(const BorderData& border, IntSize size, RenderView* renderView) 908 { 909 return RoundedRect::Radii( 910 IntSize(valueForLength(border.topLeft().width(), size.width(), renderView), 911 valueForLength(border.topLeft().height(), size.height(), renderView)), 912 IntSize(valueForLength(border.topRight().width(), size.width(), renderView), 913 valueForLength(border.topRight().height(), size.height(), renderView)), 914 IntSize(valueForLength(border.bottomLeft().width(), size.width(), renderView), 915 valueForLength(border.bottomLeft().height(), size.height(), renderView)), 916 IntSize(valueForLength(border.bottomRight().width(), size.width(), renderView), 917 valueForLength(border.bottomRight().height(), size.height(), renderView))); 918 } 919 920 static float calcConstraintScaleFor(const IntRect& rect, const RoundedRect::Radii& radii) 921 { 922 // Constrain corner radii using CSS3 rules: 923 // http://www.w3.org/TR/css3-background/#the-border-radius 924 925 float factor = 1; 926 unsigned radiiSum; 927 928 // top 929 radiiSum = static_cast<unsigned>(radii.topLeft().width()) + static_cast<unsigned>(radii.topRight().width()); // Casts to avoid integer overflow. 930 if (radiiSum > static_cast<unsigned>(rect.width())) 931 factor = min(static_cast<float>(rect.width()) / radiiSum, factor); 932 933 // bottom 934 radiiSum = static_cast<unsigned>(radii.bottomLeft().width()) + static_cast<unsigned>(radii.bottomRight().width()); 935 if (radiiSum > static_cast<unsigned>(rect.width())) 936 factor = min(static_cast<float>(rect.width()) / radiiSum, factor); 937 938 // left 939 radiiSum = static_cast<unsigned>(radii.topLeft().height()) + static_cast<unsigned>(radii.bottomLeft().height()); 940 if (radiiSum > static_cast<unsigned>(rect.height())) 941 factor = min(static_cast<float>(rect.height()) / radiiSum, factor); 942 943 // right 944 radiiSum = static_cast<unsigned>(radii.topRight().height()) + static_cast<unsigned>(radii.bottomRight().height()); 945 if (radiiSum > static_cast<unsigned>(rect.height())) 946 factor = min(static_cast<float>(rect.height()) / radiiSum, factor); 947 948 ASSERT(factor <= 1); 949 return factor; 950 } 951 952 StyleImage* RenderStyle::listStyleImage() const { return rareInheritedData->listStyleImage.get(); } 953 void RenderStyle::setListStyleImage(PassRefPtr<StyleImage> v) 954 { 955 if (rareInheritedData->listStyleImage != v) 956 rareInheritedData.access()->listStyleImage = v; 957 } 958 959 Color RenderStyle::color() const { return inherited->color; } 960 Color RenderStyle::visitedLinkColor() const { return inherited->visitedLinkColor; } 961 void RenderStyle::setColor(const Color& v) { SET_VAR(inherited, color, v); } 962 void RenderStyle::setVisitedLinkColor(const Color& v) { SET_VAR(inherited, visitedLinkColor, v); } 963 964 short RenderStyle::horizontalBorderSpacing() const { return inherited->horizontal_border_spacing; } 965 short RenderStyle::verticalBorderSpacing() const { return inherited->vertical_border_spacing; } 966 void RenderStyle::setHorizontalBorderSpacing(short v) { SET_VAR(inherited, horizontal_border_spacing, v); } 967 void RenderStyle::setVerticalBorderSpacing(short v) { SET_VAR(inherited, vertical_border_spacing, v); } 968 969 RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, RenderView* renderView, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const 970 { 971 IntRect snappedBorderRect(pixelSnappedIntRect(borderRect)); 972 RoundedRect roundedRect(snappedBorderRect); 973 if (hasBorderRadius()) { 974 RoundedRect::Radii radii = calcRadiiFor(surround->border, snappedBorderRect.size(), renderView); 975 radii.scale(calcConstraintScaleFor(snappedBorderRect, radii)); 976 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); 977 } 978 return roundedRect; 979 } 980 981 RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const 982 { 983 bool horizontal = isHorizontalWritingMode(); 984 985 int leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0; 986 int rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0; 987 int topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0; 988 int bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0; 989 990 return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge); 991 } 992 993 RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect, 994 int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const 995 { 996 LayoutRect innerRect(borderRect.x() + leftWidth, 997 borderRect.y() + topWidth, 998 borderRect.width() - leftWidth - rightWidth, 999 borderRect.height() - topWidth - bottomWidth); 1000 1001 RoundedRect roundedRect(pixelSnappedIntRect(innerRect)); 1002 1003 if (hasBorderRadius()) { 1004 RoundedRect::Radii radii = getRoundedBorderFor(borderRect).radii(); 1005 radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth); 1006 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); 1007 } 1008 return roundedRect; 1009 } 1010 1011 static bool allLayersAreFixed(const FillLayer* layer) 1012 { 1013 bool allFixed = true; 1014 1015 for (const FillLayer* currLayer = layer; currLayer; currLayer = currLayer->next()) 1016 allFixed &= (currLayer->image() && currLayer->attachment() == FixedBackgroundAttachment); 1017 1018 return layer && allFixed; 1019 } 1020 1021 bool RenderStyle::hasEntirelyFixedBackground() const 1022 { 1023 return allLayersAreFixed(backgroundLayers()); 1024 } 1025 1026 const CounterDirectiveMap* RenderStyle::counterDirectives() const 1027 { 1028 return rareNonInheritedData->m_counterDirectives.get(); 1029 } 1030 1031 CounterDirectiveMap& RenderStyle::accessCounterDirectives() 1032 { 1033 OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives; 1034 if (!map) 1035 map = adoptPtr(new CounterDirectiveMap); 1036 return *map; 1037 } 1038 1039 const CounterDirectives RenderStyle::getCounterDirectives(const AtomicString& identifier) const 1040 { 1041 if (const CounterDirectiveMap* directives = counterDirectives()) 1042 return directives->get(identifier); 1043 return CounterDirectives(); 1044 } 1045 1046 const AtomicString& RenderStyle::hyphenString() const 1047 { 1048 const AtomicString& hyphenationString = rareInheritedData.get()->hyphenationString; 1049 if (!hyphenationString.isNull()) 1050 return hyphenationString; 1051 1052 // FIXME: This should depend on locale. 1053 DEFINE_STATIC_LOCAL(AtomicString, hyphenMinusString, (&hyphenMinus, 1)); 1054 DEFINE_STATIC_LOCAL(AtomicString, hyphenString, (&hyphen, 1)); 1055 return font().primaryFontHasGlyphForCharacter(hyphen) ? hyphenString : hyphenMinusString; 1056 } 1057 1058 const AtomicString& RenderStyle::textEmphasisMarkString() const 1059 { 1060 switch (textEmphasisMark()) { 1061 case TextEmphasisMarkNone: 1062 return nullAtom; 1063 case TextEmphasisMarkCustom: 1064 return textEmphasisCustomMark(); 1065 case TextEmphasisMarkDot: { 1066 DEFINE_STATIC_LOCAL(AtomicString, filledDotString, (&bullet, 1)); 1067 DEFINE_STATIC_LOCAL(AtomicString, openDotString, (&whiteBullet, 1)); 1068 return textEmphasisFill() == TextEmphasisFillFilled ? filledDotString : openDotString; 1069 } 1070 case TextEmphasisMarkCircle: { 1071 DEFINE_STATIC_LOCAL(AtomicString, filledCircleString, (&blackCircle, 1)); 1072 DEFINE_STATIC_LOCAL(AtomicString, openCircleString, (&whiteCircle, 1)); 1073 return textEmphasisFill() == TextEmphasisFillFilled ? filledCircleString : openCircleString; 1074 } 1075 case TextEmphasisMarkDoubleCircle: { 1076 DEFINE_STATIC_LOCAL(AtomicString, filledDoubleCircleString, (&fisheye, 1)); 1077 DEFINE_STATIC_LOCAL(AtomicString, openDoubleCircleString, (&bullseye, 1)); 1078 return textEmphasisFill() == TextEmphasisFillFilled ? filledDoubleCircleString : openDoubleCircleString; 1079 } 1080 case TextEmphasisMarkTriangle: { 1081 DEFINE_STATIC_LOCAL(AtomicString, filledTriangleString, (&blackUpPointingTriangle, 1)); 1082 DEFINE_STATIC_LOCAL(AtomicString, openTriangleString, (&whiteUpPointingTriangle, 1)); 1083 return textEmphasisFill() == TextEmphasisFillFilled ? filledTriangleString : openTriangleString; 1084 } 1085 case TextEmphasisMarkSesame: { 1086 DEFINE_STATIC_LOCAL(AtomicString, filledSesameString, (&sesameDot, 1)); 1087 DEFINE_STATIC_LOCAL(AtomicString, openSesameString, (&whiteSesameDot, 1)); 1088 return textEmphasisFill() == TextEmphasisFillFilled ? filledSesameString : openSesameString; 1089 } 1090 case TextEmphasisMarkAuto: 1091 ASSERT_NOT_REACHED(); 1092 return nullAtom; 1093 } 1094 1095 ASSERT_NOT_REACHED(); 1096 return nullAtom; 1097 } 1098 1099 void RenderStyle::adjustAnimations() 1100 { 1101 CSSAnimationDataList* animationList = rareNonInheritedData->m_animations.get(); 1102 if (!animationList) 1103 return; 1104 1105 // Get rid of empty animations and anything beyond them 1106 for (size_t i = 0; i < animationList->size(); ++i) { 1107 if (animationList->animation(i)->isEmpty()) { 1108 animationList->resize(i); 1109 break; 1110 } 1111 } 1112 1113 if (animationList->isEmpty()) { 1114 clearAnimations(); 1115 return; 1116 } 1117 1118 // Repeat patterns into layers that don't have some properties set. 1119 animationList->fillUnsetProperties(); 1120 } 1121 1122 void RenderStyle::adjustTransitions() 1123 { 1124 CSSAnimationDataList* transitionList = rareNonInheritedData->m_transitions.get(); 1125 if (!transitionList) 1126 return; 1127 1128 // Get rid of empty transitions and anything beyond them 1129 for (size_t i = 0; i < transitionList->size(); ++i) { 1130 if (transitionList->animation(i)->isEmpty()) { 1131 transitionList->resize(i); 1132 break; 1133 } 1134 } 1135 1136 if (transitionList->isEmpty()) { 1137 clearTransitions(); 1138 return; 1139 } 1140 1141 // Repeat patterns into layers that don't have some properties set. 1142 transitionList->fillUnsetProperties(); 1143 1144 // Make sure there are no duplicate properties. This is an O(n^2) algorithm 1145 // but the lists tend to be very short, so it is probably ok 1146 for (size_t i = 0; i < transitionList->size(); ++i) { 1147 for (size_t j = i+1; j < transitionList->size(); ++j) { 1148 if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) { 1149 // toss i 1150 transitionList->remove(i); 1151 j = i; 1152 } 1153 } 1154 } 1155 } 1156 1157 CSSAnimationDataList* RenderStyle::accessAnimations() 1158 { 1159 if (!rareNonInheritedData.access()->m_animations) 1160 rareNonInheritedData.access()->m_animations = adoptPtr(new CSSAnimationDataList()); 1161 return rareNonInheritedData->m_animations.get(); 1162 } 1163 1164 CSSAnimationDataList* RenderStyle::accessTransitions() 1165 { 1166 if (!rareNonInheritedData.access()->m_transitions) 1167 rareNonInheritedData.access()->m_transitions = adoptPtr(new CSSAnimationDataList()); 1168 return rareNonInheritedData->m_transitions.get(); 1169 } 1170 1171 const CSSAnimationData* RenderStyle::transitionForProperty(CSSPropertyID property) const 1172 { 1173 if (transitions()) { 1174 for (size_t i = 0; i < transitions()->size(); ++i) { 1175 const CSSAnimationData* p = transitions()->animation(i); 1176 if (p->animationMode() == CSSAnimationData::AnimateAll || p->property() == property) { 1177 return p; 1178 } 1179 } 1180 } 1181 return 0; 1182 } 1183 1184 const Font& RenderStyle::font() const { return inherited->font; } 1185 const FontMetrics& RenderStyle::fontMetrics() const { return inherited->font.fontMetrics(); } 1186 const FontDescription& RenderStyle::fontDescription() const { return inherited->font.fontDescription(); } 1187 float RenderStyle::specifiedFontSize() const { return fontDescription().specifiedSize(); } 1188 float RenderStyle::computedFontSize() const { return fontDescription().computedSize(); } 1189 int RenderStyle::fontSize() const { return inherited->font.pixelSize(); } 1190 1191 float RenderStyle::wordSpacing() const { return inherited->font.wordSpacing(); } 1192 float RenderStyle::letterSpacing() const { return inherited->font.letterSpacing(); } 1193 1194 bool RenderStyle::setFontDescription(const FontDescription& v) 1195 { 1196 if (inherited->font.fontDescription() != v) { 1197 inherited.access()->font = Font(v, inherited->font.letterSpacing(), inherited->font.wordSpacing()); 1198 return true; 1199 } 1200 return false; 1201 } 1202 1203 Length RenderStyle::specifiedLineHeight() const { return inherited->line_height; } 1204 Length RenderStyle::lineHeight() const 1205 { 1206 const Length& lh = inherited->line_height; 1207 // Unlike fontDescription().computedSize() and hence fontSize(), this is 1208 // recalculated on demand as we only store the specified line height. 1209 // FIXME: Should consider scaling the fixed part of any calc expressions 1210 // too, though this involves messily poking into CalcExpressionLength. 1211 float multiplier = textAutosizingMultiplier(); 1212 if (multiplier > 1 && lh.isFixed()) 1213 return Length(TextAutosizer::computeAutosizedFontSize(lh.value(), multiplier), Fixed); 1214 1215 return lh; 1216 } 1217 void RenderStyle::setLineHeight(Length specifiedLineHeight) { SET_VAR(inherited, line_height, specifiedLineHeight); } 1218 1219 int RenderStyle::computedLineHeight(RenderView* renderView) const 1220 { 1221 const Length& lh = lineHeight(); 1222 1223 // Negative value means the line height is not set. Use the font's built-in spacing. 1224 if (lh.isNegative()) 1225 return fontMetrics().lineSpacing(); 1226 1227 if (lh.isPercent()) 1228 return minimumValueForLength(lh, fontSize()); 1229 1230 if (lh.isViewportPercentage()) 1231 return valueForLength(lh, 0, renderView); 1232 1233 return lh.value(); 1234 } 1235 1236 void RenderStyle::setWordSpacing(float v) { inherited.access()->font.setWordSpacing(v); } 1237 void RenderStyle::setLetterSpacing(float v) { inherited.access()->font.setLetterSpacing(v); } 1238 1239 void RenderStyle::setFontSize(float size) 1240 { 1241 // size must be specifiedSize if Text Autosizing is enabled, but computedSize if text 1242 // zoom is enabled (if neither is enabled it's irrelevant as they're probably the same). 1243 1244 ASSERT(std::isfinite(size)); 1245 if (!std::isfinite(size) || size < 0) 1246 size = 0; 1247 else 1248 size = min(maximumAllowedFontSize, size); 1249 1250 FontSelector* currentFontSelector = font().fontSelector(); 1251 FontDescription desc(fontDescription()); 1252 desc.setSpecifiedSize(size); 1253 desc.setComputedSize(size); 1254 1255 float multiplier = textAutosizingMultiplier(); 1256 if (multiplier > 1) { 1257 float autosizedFontSize = TextAutosizer::computeAutosizedFontSize(size, multiplier); 1258 desc.setComputedSize(min(maximumAllowedFontSize, autosizedFontSize)); 1259 } 1260 1261 setFontDescription(desc); 1262 font().update(currentFontSelector); 1263 } 1264 1265 void RenderStyle::getShadowExtent(const ShadowList* shadowList, LayoutUnit &top, LayoutUnit &right, LayoutUnit &bottom, LayoutUnit &left) const 1266 { 1267 top = 0; 1268 right = 0; 1269 bottom = 0; 1270 left = 0; 1271 1272 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0; 1273 for (size_t i = 0; i < shadowCount; ++i) { 1274 const ShadowData& shadow = shadowList->shadows()[i]; 1275 if (shadow.style() == Inset) 1276 continue; 1277 int blurAndSpread = shadow.blur() + shadow.spread(); 1278 1279 top = min<LayoutUnit>(top, shadow.y() - blurAndSpread); 1280 right = max<LayoutUnit>(right, shadow.x() + blurAndSpread); 1281 bottom = max<LayoutUnit>(bottom, shadow.y() + blurAndSpread); 1282 left = min<LayoutUnit>(left, shadow.x() - blurAndSpread); 1283 } 1284 } 1285 1286 LayoutBoxExtent RenderStyle::getShadowInsetExtent(const ShadowList* shadowList) const 1287 { 1288 LayoutUnit top = 0; 1289 LayoutUnit right = 0; 1290 LayoutUnit bottom = 0; 1291 LayoutUnit left = 0; 1292 1293 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0; 1294 for (size_t i = 0; i < shadowCount; ++i) { 1295 const ShadowData& shadow = shadowList->shadows()[i]; 1296 if (shadow.style() == Normal) 1297 continue; 1298 int blurAndSpread = shadow.blur() + shadow.spread(); 1299 top = max<LayoutUnit>(top, shadow.y() + blurAndSpread); 1300 right = min<LayoutUnit>(right, shadow.x() - blurAndSpread); 1301 bottom = min<LayoutUnit>(bottom, shadow.y() - blurAndSpread); 1302 left = max<LayoutUnit>(left, shadow.x() + blurAndSpread); 1303 } 1304 1305 return LayoutBoxExtent(top, right, bottom, left); 1306 } 1307 1308 void RenderStyle::getShadowHorizontalExtent(const ShadowList* shadowList, LayoutUnit &left, LayoutUnit &right) const 1309 { 1310 left = 0; 1311 right = 0; 1312 1313 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0; 1314 for (size_t i = 0; i < shadowCount; ++i) { 1315 const ShadowData& shadow = shadowList->shadows()[i]; 1316 if (shadow.style() == Inset) 1317 continue; 1318 int blurAndSpread = shadow.blur() + shadow.spread(); 1319 1320 left = min<LayoutUnit>(left, shadow.x() - blurAndSpread); 1321 right = max<LayoutUnit>(right, shadow.x() + blurAndSpread); 1322 } 1323 } 1324 1325 void RenderStyle::getShadowVerticalExtent(const ShadowList* shadowList, LayoutUnit &top, LayoutUnit &bottom) const 1326 { 1327 top = 0; 1328 bottom = 0; 1329 1330 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0; 1331 for (size_t i = 0; i < shadowCount; ++i) { 1332 const ShadowData& shadow = shadowList->shadows()[i]; 1333 if (shadow.style() == Inset) 1334 continue; 1335 int blurAndSpread = shadow.blur() + shadow.spread(); 1336 1337 top = min<LayoutUnit>(top, shadow.y() - blurAndSpread); 1338 bottom = max<LayoutUnit>(bottom, shadow.y() + blurAndSpread); 1339 } 1340 } 1341 1342 Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) const 1343 { 1344 Color result; 1345 EBorderStyle borderStyle = BNONE; 1346 switch (colorProperty) { 1347 case CSSPropertyBackgroundColor: 1348 return visitedLink ? visitedLinkBackgroundColor() : backgroundColor(); // Background color doesn't fall back. 1349 case CSSPropertyBorderLeftColor: 1350 result = visitedLink ? visitedLinkBorderLeftColor() : borderLeftColor(); 1351 borderStyle = borderLeftStyle(); 1352 break; 1353 case CSSPropertyBorderRightColor: 1354 result = visitedLink ? visitedLinkBorderRightColor() : borderRightColor(); 1355 borderStyle = borderRightStyle(); 1356 break; 1357 case CSSPropertyBorderTopColor: 1358 result = visitedLink ? visitedLinkBorderTopColor() : borderTopColor(); 1359 borderStyle = borderTopStyle(); 1360 break; 1361 case CSSPropertyBorderBottomColor: 1362 result = visitedLink ? visitedLinkBorderBottomColor() : borderBottomColor(); 1363 borderStyle = borderBottomStyle(); 1364 break; 1365 case CSSPropertyColor: 1366 result = visitedLink ? visitedLinkColor() : color(); 1367 break; 1368 case CSSPropertyOutlineColor: 1369 result = visitedLink ? visitedLinkOutlineColor() : outlineColor(); 1370 break; 1371 case CSSPropertyWebkitColumnRuleColor: 1372 result = visitedLink ? visitedLinkColumnRuleColor() : columnRuleColor(); 1373 break; 1374 case CSSPropertyTextDecorationColor: 1375 // Text decoration color fallback is handled in RenderObject::decorationColor. 1376 return visitedLink ? visitedLinkTextDecorationColor() : textDecorationColor(); 1377 case CSSPropertyWebkitTextEmphasisColor: 1378 result = visitedLink ? visitedLinkTextEmphasisColor() : textEmphasisColor(); 1379 break; 1380 case CSSPropertyWebkitTextFillColor: 1381 result = visitedLink ? visitedLinkTextFillColor() : textFillColor(); 1382 break; 1383 case CSSPropertyWebkitTextStrokeColor: 1384 result = visitedLink ? visitedLinkTextStrokeColor() : textStrokeColor(); 1385 break; 1386 case CSSPropertyFloodColor: 1387 result = floodColor(); 1388 break; 1389 case CSSPropertyLightingColor: 1390 result = lightingColor(); 1391 break; 1392 case CSSPropertyStopColor: 1393 result = stopColor(); 1394 break; 1395 case CSSPropertyWebkitTapHighlightColor: 1396 result = tapHighlightColor(); 1397 break; 1398 default: 1399 ASSERT_NOT_REACHED(); 1400 break; 1401 } 1402 1403 if (!result.isValid()) { 1404 if (!visitedLink && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE)) 1405 result.setRGB(238, 238, 238); 1406 else 1407 result = visitedLink ? visitedLinkColor() : color(); 1408 } 1409 return result; 1410 } 1411 1412 Color RenderStyle::visitedDependentColor(int colorProperty) const 1413 { 1414 Color unvisitedColor = colorIncludingFallback(colorProperty, false); 1415 if (insideLink() != InsideVisitedLink) 1416 return unvisitedColor; 1417 1418 Color visitedColor = colorIncludingFallback(colorProperty, true); 1419 1420 // Text decoration color validity is preserved (checked in RenderObject::decorationColor). 1421 if (colorProperty == CSSPropertyTextDecorationColor) 1422 return visitedColor; 1423 1424 // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just 1425 // assume that if the background color is transparent that it wasn't set. Note that it's weird that 1426 // we're returning unvisited info for a visited link, but given our restriction that the alpha values 1427 // have to match, it makes more sense to return the unvisited background color if specified than it 1428 // does to return black. This behavior matches what Firefox 4 does as well. 1429 if (colorProperty == CSSPropertyBackgroundColor && visitedColor == Color::transparent) 1430 return unvisitedColor; 1431 1432 // Take the alpha from the unvisited color, but get the RGB values from the visited color. 1433 return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha()); 1434 } 1435 1436 const BorderValue& RenderStyle::borderBefore() const 1437 { 1438 switch (writingMode()) { 1439 case TopToBottomWritingMode: 1440 return borderTop(); 1441 case BottomToTopWritingMode: 1442 return borderBottom(); 1443 case LeftToRightWritingMode: 1444 return borderLeft(); 1445 case RightToLeftWritingMode: 1446 return borderRight(); 1447 } 1448 ASSERT_NOT_REACHED(); 1449 return borderTop(); 1450 } 1451 1452 const BorderValue& RenderStyle::borderAfter() const 1453 { 1454 switch (writingMode()) { 1455 case TopToBottomWritingMode: 1456 return borderBottom(); 1457 case BottomToTopWritingMode: 1458 return borderTop(); 1459 case LeftToRightWritingMode: 1460 return borderRight(); 1461 case RightToLeftWritingMode: 1462 return borderLeft(); 1463 } 1464 ASSERT_NOT_REACHED(); 1465 return borderBottom(); 1466 } 1467 1468 const BorderValue& RenderStyle::borderStart() const 1469 { 1470 if (isHorizontalWritingMode()) 1471 return isLeftToRightDirection() ? borderLeft() : borderRight(); 1472 return isLeftToRightDirection() ? borderTop() : borderBottom(); 1473 } 1474 1475 const BorderValue& RenderStyle::borderEnd() const 1476 { 1477 if (isHorizontalWritingMode()) 1478 return isLeftToRightDirection() ? borderRight() : borderLeft(); 1479 return isLeftToRightDirection() ? borderBottom() : borderTop(); 1480 } 1481 1482 unsigned short RenderStyle::borderBeforeWidth() const 1483 { 1484 switch (writingMode()) { 1485 case TopToBottomWritingMode: 1486 return borderTopWidth(); 1487 case BottomToTopWritingMode: 1488 return borderBottomWidth(); 1489 case LeftToRightWritingMode: 1490 return borderLeftWidth(); 1491 case RightToLeftWritingMode: 1492 return borderRightWidth(); 1493 } 1494 ASSERT_NOT_REACHED(); 1495 return borderTopWidth(); 1496 } 1497 1498 unsigned short RenderStyle::borderAfterWidth() const 1499 { 1500 switch (writingMode()) { 1501 case TopToBottomWritingMode: 1502 return borderBottomWidth(); 1503 case BottomToTopWritingMode: 1504 return borderTopWidth(); 1505 case LeftToRightWritingMode: 1506 return borderRightWidth(); 1507 case RightToLeftWritingMode: 1508 return borderLeftWidth(); 1509 } 1510 ASSERT_NOT_REACHED(); 1511 return borderBottomWidth(); 1512 } 1513 1514 unsigned short RenderStyle::borderStartWidth() const 1515 { 1516 if (isHorizontalWritingMode()) 1517 return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth(); 1518 return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth(); 1519 } 1520 1521 unsigned short RenderStyle::borderEndWidth() const 1522 { 1523 if (isHorizontalWritingMode()) 1524 return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth(); 1525 return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth(); 1526 } 1527 1528 void RenderStyle::setMarginStart(Length margin) 1529 { 1530 if (isHorizontalWritingMode()) { 1531 if (isLeftToRightDirection()) 1532 setMarginLeft(margin); 1533 else 1534 setMarginRight(margin); 1535 } else { 1536 if (isLeftToRightDirection()) 1537 setMarginTop(margin); 1538 else 1539 setMarginBottom(margin); 1540 } 1541 } 1542 1543 void RenderStyle::setMarginEnd(Length margin) 1544 { 1545 if (isHorizontalWritingMode()) { 1546 if (isLeftToRightDirection()) 1547 setMarginRight(margin); 1548 else 1549 setMarginLeft(margin); 1550 } else { 1551 if (isLeftToRightDirection()) 1552 setMarginBottom(margin); 1553 else 1554 setMarginTop(margin); 1555 } 1556 } 1557 1558 TextEmphasisMark RenderStyle::textEmphasisMark() const 1559 { 1560 TextEmphasisMark mark = static_cast<TextEmphasisMark>(rareInheritedData->textEmphasisMark); 1561 if (mark != TextEmphasisMarkAuto) 1562 return mark; 1563 1564 if (isHorizontalWritingMode()) 1565 return TextEmphasisMarkDot; 1566 1567 return TextEmphasisMarkSesame; 1568 } 1569 1570 Color RenderStyle::initialTapHighlightColor() 1571 { 1572 return RenderTheme::tapHighlightColor(); 1573 } 1574 1575 LayoutBoxExtent RenderStyle::imageOutsets(const NinePieceImage& image) const 1576 { 1577 return LayoutBoxExtent(NinePieceImage::computeOutset(image.outset().top(), borderTopWidth()), 1578 NinePieceImage::computeOutset(image.outset().right(), borderRightWidth()), 1579 NinePieceImage::computeOutset(image.outset().bottom(), borderBottomWidth()), 1580 NinePieceImage::computeOutset(image.outset().left(), borderLeftWidth())); 1581 } 1582 1583 void RenderStyle::setBorderImageSource(PassRefPtr<StyleImage> image) 1584 { 1585 if (surround->border.m_image.image() == image.get()) 1586 return; 1587 surround.access()->border.m_image.setImage(image); 1588 } 1589 1590 void RenderStyle::setBorderImageSlices(LengthBox slices) 1591 { 1592 if (surround->border.m_image.imageSlices() == slices) 1593 return; 1594 surround.access()->border.m_image.setImageSlices(slices); 1595 } 1596 1597 void RenderStyle::setBorderImageWidth(const BorderImageLengthBox& slices) 1598 { 1599 if (surround->border.m_image.borderSlices() == slices) 1600 return; 1601 surround.access()->border.m_image.setBorderSlices(slices); 1602 } 1603 1604 void RenderStyle::setBorderImageOutset(const BorderImageLengthBox& outset) 1605 { 1606 if (surround->border.m_image.outset() == outset) 1607 return; 1608 surround.access()->border.m_image.setOutset(outset); 1609 } 1610 1611 } // namespace WebCore 1612