ComputedStyle.h (13276B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* the interface (to internal code) for retrieving computed style data */ 8 9 #ifndef _ComputedStyle_h_ 10 #define _ComputedStyle_h_ 11 12 #include "mozilla/Assertions.h" 13 #include "mozilla/CachedInheritingStyles.h" 14 #include "mozilla/Maybe.h" 15 #include "mozilla/PseudoStyleType.h" 16 #include "mozilla/ServoComputedData.h" 17 #include "mozilla/ServoStyleConsts.h" 18 #include "nsCSSPseudoElements.h" 19 #include "nsColor.h" 20 #include "nsStyleStructFwd.h" 21 22 enum nsChangeHint : uint32_t; 23 class nsWindowSizes; 24 25 #define FORWARD_STRUCT(name_) struct nsStyle##name_; 26 FOR_EACH_STYLE_STRUCT(FORWARD_STRUCT, FORWARD_STRUCT) 27 #undef FORWARD_STRUCT 28 29 extern "C" { 30 void Gecko_ComputedStyle_Destroy(mozilla::ComputedStyle*); 31 } 32 33 namespace mozilla { 34 35 enum class StylePointerEvents : uint8_t; 36 enum class StyleUserSelect : uint8_t; 37 38 namespace dom { 39 class Document; 40 } 41 42 /** 43 * A ComputedStyle represents the computed style data for an element. 44 * 45 * The computed style data are stored in a set of reference counted structs 46 * (see nsStyleStruct.h) that are stored directly on the ComputedStyle. 47 * 48 * Style structs are immutable once they have been produced, so when any change 49 * is made that needs a restyle, we create a new ComputedStyle. 50 * 51 * ComputedStyles are reference counted. References are generally held by: 52 * 53 * 1. nsIFrame::mComputedStyle, for every frame 54 * 2. Element::mServoData, for every element not inside a display:none subtree 55 * 3. nsComputedDOMStyle, when created for elements in display:none subtrees 56 * 4. media_queries::Device, which holds the initial value of every property 57 */ 58 59 class ComputedStyle { 60 using Flag = StyleComputedValueFlags; 61 62 const StyleComputedValueFlags& Flags() const { return mSource.flags; } 63 64 public: 65 ComputedStyle(PseudoStyleType aPseudoType, 66 ServoComputedDataForgotten aComputedValues); 67 68 // Returns the computed (not resolved) value of the given property. 69 void GetComputedPropertyValue(NonCustomCSSPropertyId aId, 70 nsACString& aOut) const { 71 Servo_GetComputedValue(this, aId, &aOut); 72 } 73 74 // Returns the computed typed value of the given property. 75 bool GetPropertyTypedValue(const nsACString& aProperty, 76 StylePropertyTypedValueResult& aOut) const { 77 return Servo_GetComputedTypedValue(this, &aProperty, &aOut); 78 } 79 80 // Return the ComputedStyle whose style data should be used for the R, 81 // G, and B components of color, background-color, and border-*-color 82 // if RelevantLinkIsVisited(). 83 // 84 // GetPseudo() and GetPseudoType() on this ComputedStyle return the 85 // same as on |this|, and its depth in the tree (number of GetParent() 86 // calls until null is returned) is the same as |this|, since its 87 // parent is either |this|'s parent or |this|'s parent's 88 // style-if-visited. 89 // 90 // Structs on this context should never be examined without also 91 // examining the corresponding struct on |this|. Doing so will likely 92 // both (1) lead to a privacy leak and (2) lead to dynamic change bugs 93 // related to the Peek code in ComputedStyle::CalcStyleDifference. 94 const ComputedStyle* GetStyleIfVisited() const { 95 return mSource.visited_style; 96 } 97 98 bool IsLazilyCascadedPseudoElement() const { 99 return IsPseudoElement() && 100 !nsCSSPseudoElements::IsEagerlyCascadedInServo(GetPseudoType()); 101 } 102 103 PseudoStyleType GetPseudoType() const { return mPseudoType; } 104 105 bool IsPseudoElement() const { 106 return PseudoStyle::IsPseudoElement(mPseudoType); 107 } 108 109 bool IsInheritingAnonBox() const { 110 return PseudoStyle::IsInheritingAnonBox(mPseudoType); 111 } 112 113 bool IsNonInheritingAnonBox() const { 114 return PseudoStyle::IsNonInheritingAnonBox(mPseudoType); 115 } 116 117 bool IsWrapperAnonBox() const { 118 return PseudoStyle::IsWrapperAnonBox(mPseudoType); 119 } 120 121 bool IsAnonBox() const { return PseudoStyle::IsAnonBox(mPseudoType); } 122 123 bool IsPseudoOrAnonBox() const { 124 return mPseudoType != PseudoStyleType::NotPseudo; 125 } 126 127 // Whether there are author-specified rules for border or background 128 // properties. 129 // Only returns something meaningful if the appearance property is not `none`. 130 bool HasAuthorSpecifiedBorderOrBackground() const { 131 return bool(Flags() & Flag::HAS_AUTHOR_SPECIFIED_BORDER_BACKGROUND); 132 } 133 134 // Whether there are author-specific rules for text color. 135 bool HasAuthorSpecifiedTextColor() const { 136 return bool(Flags() & Flag::HAS_AUTHOR_SPECIFIED_TEXT_COLOR); 137 } 138 139 // Does this ComputedStyle or any of its ancestors have text 140 // decoration lines? 141 // Differs from nsStyleTextReset::HasTextDecorationLines, which tests 142 // only the data for a single context. 143 bool HasTextDecorationLines() const { 144 return bool(Flags() & Flag::HAS_TEXT_DECORATION_LINES); 145 } 146 147 // Whether any line break inside should be suppressed? If this returns 148 // true, the line should not be broken inside, which means inlines act 149 // as if nowrap is set, <br> is suppressed, and blocks are inlinized. 150 // This bit is propogated to all children of line partitipants. It is 151 // currently used by ruby to make its content frames unbreakable. 152 // NOTE: for nsTextFrame, use nsTextFrame::ShouldSuppressLineBreak() 153 // instead of this method. 154 bool ShouldSuppressLineBreak() const { 155 return bool(Flags() & Flag::SHOULD_SUPPRESS_LINEBREAK); 156 } 157 158 // Is this horizontal-in-vertical (tate-chu-yoko) text? This flag is 159 // only set on ComputedStyles whose pseudo is nsCSSAnonBoxes::mozText(). 160 bool IsTextCombined() const { return bool(Flags() & Flag::IS_TEXT_COMBINED); } 161 162 // Whether there's any font metric dependency coming directly from our style. 163 bool DependsOnSelfFontMetrics() const { 164 return bool(Flags() & Flag::DEPENDS_ON_SELF_FONT_METRICS); 165 } 166 167 // Whether there's any font metric dependency coming directly from our parent 168 // style. 169 bool DependsOnInheritedFontMetrics() const { 170 return bool(Flags() & Flag::DEPENDS_ON_INHERITED_FONT_METRICS); 171 } 172 173 // Whether this style is inside a ::first-line. 174 bool IsInFirstLineSubtree() const { 175 return bool(Flags() & Flag::IS_IN_FIRST_LINE_SUBTREE); 176 } 177 178 bool SelfOrAncestorHasContainStyle() const { 179 return bool(Flags() & Flag::SELF_OR_ANCESTOR_HAS_CONTAIN_STYLE); 180 } 181 182 // Is the only link whose visitedness is allowed to influence the 183 // style of the node this ComputedStyle is for (which is that element 184 // or its nearest ancestor that is a link) visited? 185 bool RelevantLinkVisited() const { 186 return bool(Flags() & Flag::IS_RELEVANT_LINK_VISITED); 187 } 188 189 // Whether this style is for the root element of the document. 190 bool IsRootElementStyle() const { 191 return bool(Flags() & Flag::IS_ROOT_ELEMENT_STYLE); 192 } 193 194 bool IsInOpacityZeroSubtree() const { 195 return bool(Flags() & Flag::IS_IN_OPACITY_ZERO_SUBTREE); 196 } 197 198 bool HasAnchorPosReference() const; 199 200 bool MaybeAnchorPosReferencesDiffer(const ComputedStyle* aOther) const; 201 202 ComputedStyle* GetCachedInheritingAnonBoxStyle( 203 PseudoStyleType aPseudoType) const { 204 MOZ_ASSERT(PseudoStyle::IsInheritingAnonBox(aPseudoType)); 205 return mCachedInheritingStyles.Lookup(aPseudoType); 206 } 207 208 void SetCachedInheritedAnonBoxStyle(ComputedStyle* aStyle) { 209 mCachedInheritingStyles.Insert(aStyle); 210 } 211 212 ComputedStyle* GetCachedLazyPseudoStyle(PseudoStyleType aPseudo) const; 213 214 void SetCachedLazyPseudoStyle(ComputedStyle* aStyle) { 215 MOZ_ASSERT(aStyle->IsPseudoElement()); 216 MOZ_ASSERT(!GetCachedLazyPseudoStyle(aStyle->GetPseudoType())); 217 MOZ_ASSERT(aStyle->IsLazilyCascadedPseudoElement()); 218 219 // Since we're caching lazy pseudo styles on the ComputedValues of the 220 // originating element, we can assume that we either have the same 221 // originating element, or that they were at least similar enough to share 222 // the same ComputedValues, which means that they would match the same 223 // pseudo rules. This allows us to avoid matching selectors and checking 224 // the rule node before deciding to share. 225 // 226 // The one place this optimization breaks is with pseudo-elements that 227 // support state (like :hover). So we just avoid sharing in those cases. 228 if (nsCSSPseudoElements::PseudoElementSupportsUserActionState( 229 aStyle->GetPseudoType())) { 230 return; 231 } 232 233 mCachedInheritingStyles.Insert(aStyle); 234 } 235 236 #define GENERATE_ACCESSOR(name_) \ 237 inline const nsStyle##name_* Style##name_() const MOZ_NONNULL_RETURN { \ 238 return mSource.Style##name_(); \ 239 } 240 FOR_EACH_STYLE_STRUCT(GENERATE_ACCESSOR, GENERATE_ACCESSOR) 241 #undef GENERATE_ACCESSOR 242 243 inline mozilla::StylePointerEvents PointerEvents() const; 244 inline mozilla::StyleUserSelect UserSelect() const; 245 246 /** 247 * Returns whether the element is a containing block for its absolutely 248 * positioned descendants. 249 * aContextFrame is the frame for which this is the style (or an old style). 250 */ 251 inline bool IsAbsPosContainingBlock(const nsIFrame*) const; 252 253 /** 254 * Returns true when the element is a containing block for its fixed-pos 255 * descendants. 256 * aContextFrame is the frame for which this is the style (or an old style). 257 */ 258 inline bool IsFixedPosContainingBlock(const nsIFrame*) const; 259 260 /** 261 * Tests for only the sub-parts of IsFixedPosContainingBlock that apply to: 262 * - nearly all frames, except those that are in SVG text subtrees. 263 * - frames that support CSS contain:layout and contain:paint and are not 264 * in SVG text subtrees. 265 * - frames that support CSS transforms and are not in SVG text subtrees. 266 * 267 * This should be used only when the caller has the style but not the 268 * frame (i.e., when calculating style changes). 269 */ 270 inline bool IsFixedPosContainingBlockForNonSVGTextFrames() const; 271 272 /** 273 * Compute the style changes needed during restyling when this style 274 * context is being replaced by aNewContext. (This is nonsymmetric since 275 * we optimize by skipping comparison for styles that have never been 276 * requested.) 277 * 278 * This method returns a change hint (see nsChangeHint.h). All change 279 * hints apply to the frame and its later continuations or ib-split 280 * siblings. Most (all of those except the "NotHandledForDescendants" 281 * hints) also apply to all descendants. 282 * 283 * aEqualStructs must not be null. Into it will be stored a bitfield 284 * representing which structs were compared to be non-equal. 285 * 286 * CSS Variables are not compared here. Instead, the caller is responsible for 287 * that when needed (basically only for elements). 288 */ 289 nsChangeHint CalcStyleDifference(const ComputedStyle& aNewContext, 290 uint32_t* aEqualStructs) const; 291 292 #ifdef DEBUG 293 bool EqualForCachedAnonymousContentStyle(const ComputedStyle&) const; 294 #endif 295 296 #ifdef DEBUG 297 void DumpMatchedRules() const; 298 #endif 299 300 /** 301 * Get a color that depends on link-visitedness using this and 302 * this->GetStyleIfVisited(). 303 * 304 * @param aField A pointer to a member variable in a style struct. 305 * The member variable and its style struct must have 306 * been listed in nsCSSVisitedDependentPropList.h. 307 */ 308 template <typename T, typename S> 309 nscolor GetVisitedDependentColor(T S::* aField) const; 310 311 /** 312 * aColors should be a two element array of nscolor in which the first 313 * color is the unvisited color and the second is the visited color. 314 * 315 * Combine the R, G, and B components of whichever of aColors should 316 * be used based on aLinkIsVisited with the A component of aColors[0]. 317 */ 318 static nscolor CombineVisitedColors(nscolor* aColors, bool aLinkIsVisited); 319 320 /** 321 * Start image loads for this style. 322 * 323 * The Document is used to get a hand on the image loader. The old style is a 324 * hack for bug 1439285. 325 */ 326 inline void StartImageLoads(dom::Document&, 327 const ComputedStyle* aOldStyle = nullptr); 328 329 #ifdef DEBUG 330 void List(FILE* out, int32_t aIndent); 331 static const char* StructName(StyleStructID aSID); 332 static Maybe<StyleStructID> LookupStruct(const nsACString& aName); 333 #endif 334 335 // The |aCVsSize| outparam on this function is where the actual CVs size 336 // value is added. It's done that way because the callers know which value 337 // the size should be added to. 338 void AddSizeOfIncludingThis(nsWindowSizes& aSizes, size_t* aCVsSize) const; 339 340 StyleWritingMode WritingMode() const { return {mSource.WritingMode().mBits}; } 341 342 const StyleZoom& EffectiveZoom() const { return mSource.effective_zoom; } 343 344 protected: 345 // Needs to be friend so that it can call the destructor without making it 346 // public. 347 friend void ::Gecko_ComputedStyle_Destroy(ComputedStyle*); 348 349 ~ComputedStyle() = default; 350 351 ServoComputedData mSource; 352 353 // A cache of anonymous box and lazy pseudo styles inheriting from this style. 354 CachedInheritingStyles mCachedInheritingStyles; 355 356 const PseudoStyleType mPseudoType; 357 }; 358 359 } // namespace mozilla 360 361 #endif