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