tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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