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