tor-browser

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

nsQueryFrame.h (6783B)


      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 #ifndef nsQueryFrame_h
      8 #define nsQueryFrame_h
      9 
     10 #include <type_traits>
     11 
     12 #include "mozilla/Assertions.h"
     13 #include "nscore.h"
     14 
     15 namespace mozilla {
     16 class ScrollContainerFrame;
     17 }
     18 
     19 #define NS_DECL_QUERYFRAME_TARGET(classname)      \
     20  static const nsQueryFrame::FrameIID kFrameIID = \
     21      nsQueryFrame::classname##_id;               \
     22  typedef classname Has_NS_DECL_QUERYFRAME_TARGET;
     23 
     24 #define NS_DECL_QUERYFRAME void* QueryFrame(FrameIID id) const override;
     25 
     26 #define NS_QUERYFRAME_HEAD(class)               \
     27  void* class ::QueryFrame(FrameIID id) const { \
     28    switch (id) {
     29 #define NS_QUERYFRAME_ENTRY(class)                                    \
     30  case class ::kFrameIID: {                                           \
     31    static_assert(                                                    \
     32        std::is_same_v<class, class ::Has_NS_DECL_QUERYFRAME_TARGET>, \
     33        #class " must declare itself as a queryframe target");        \
     34    return const_cast<class*>(static_cast<const class*>(this));       \
     35  }
     36 
     37 #define NS_QUERYFRAME_ENTRY_CONDITIONAL(class, condition)               \
     38  case class ::kFrameIID:                                               \
     39    if (condition) {                                                    \
     40      static_assert(                                                    \
     41          std::is_same_v<class, class ::Has_NS_DECL_QUERYFRAME_TARGET>, \
     42          #class " must declare itself as a queryframe target");        \
     43      return const_cast<class*>(static_cast<const class*>(this));       \
     44    }                                                                   \
     45    break;
     46 
     47 #define NS_QUERYFRAME_TAIL_INHERITING(class) \
     48  default:                                   \
     49    break;                                   \
     50    }                                        \
     51    return class ::QueryFrame(id);           \
     52    }
     53 
     54 #define NS_QUERYFRAME_TAIL_INHERITANCE_ROOT                          \
     55  default:                                                           \
     56    break;                                                           \
     57    }                                                                \
     58    MOZ_ASSERT(id != GetFrameId(),                                   \
     59               "A frame failed to QueryFrame to its *own type*. "    \
     60               "It may be missing NS_DECL_QUERYFRAME, or a "         \
     61               "NS_QUERYFRAME_ENTRY() line with its own type name"); \
     62    return nullptr;                                                  \
     63    }
     64 
     65 class nsQueryFrame {
     66 public:
     67  enum FrameIID {
     68 #define FRAME_ID(classname, ...) classname##_id,
     69 #define ABSTRACT_FRAME_ID(classname) classname##_id,
     70 #include "mozilla/FrameIdList.h"
     71 #undef FRAME_ID
     72 #undef ABSTRACT_FRAME_ID
     73  };
     74 
     75  // A strict subset of FrameIID above for frame classes that we instantiate.
     76  enum class ClassID : uint8_t {
     77 #define FRAME_ID(classname, ...) classname##_id,
     78 #define ABSTRACT_FRAME_ID(classname)
     79 #include "mozilla/FrameIdList.h"
     80 #undef FRAME_ID
     81 #undef ABSTRACT_FRAME_ID
     82  };
     83 
     84  virtual void* QueryFrame(FrameIID id) const = 0;
     85 };
     86 
     87 class nsIFrame;
     88 
     89 namespace detail {
     90 template <typename Dest, typename = void>
     91 struct FastQueryFrame {
     92  static constexpr bool kSupported = false;
     93 };
     94 
     95 // For final classes we can check the class id.
     96 template <typename Dest>
     97 struct FastQueryFrame<Dest, std::enable_if_t<std::is_final_v<Dest>, void>> {
     98  static constexpr bool kSupported = true;
     99 
    100  template <typename Src>
    101  static Dest* QueryFrame(Src* aPtr) {
    102    return nsQueryFrame::FrameIID(aPtr->GetClassID()) == Dest::kFrameIID
    103               ? static_cast<Dest*>(aPtr)
    104               : nullptr;
    105  }
    106 };
    107 
    108 #define IMPL_FAST_QUERYFRAME(Dest_, Check_)                        \
    109  template <>                                                      \
    110  struct FastQueryFrame<Dest_, void> {                             \
    111    static constexpr bool kSupported = true;                       \
    112    template <typename Src>                                        \
    113    static Dest_* QueryFrame(Src* aPtr) {                          \
    114      return aPtr->Check_() ? static_cast<Dest_*>(aPtr) : nullptr; \
    115    }                                                              \
    116  }
    117 
    118 IMPL_FAST_QUERYFRAME(mozilla::ScrollContainerFrame,
    119                     IsScrollContainerOrSubclass);
    120 
    121 #undef IMPL_FAST_QUERYFRAME
    122 }
    123 
    124 template <typename Source>
    125 class do_QueryFrameHelper {
    126 public:
    127  explicit do_QueryFrameHelper(Source* s) : mRawPtr(s) {}
    128 
    129  // The return and argument types here are arbitrarily selected so no
    130  // corresponding member function exists.
    131  using MatchNullptr = void (*)(double, float);
    132  // Implicit constructor for nullptr, trick borrowed from already_AddRefed.
    133  MOZ_IMPLICIT do_QueryFrameHelper(MatchNullptr aRawPtr) : mRawPtr(nullptr) {}
    134 
    135  template <typename Dest>
    136  operator Dest*() {
    137    static_assert(std::is_same_v<std::remove_const_t<Dest>,
    138                                 typename Dest::Has_NS_DECL_QUERYFRAME_TARGET>,
    139                  "Dest must declare itself as a queryframe target");
    140    if (!mRawPtr) {
    141      return nullptr;
    142    }
    143    if constexpr (::detail::FastQueryFrame<Dest>::kSupported) {
    144      static_assert(
    145          std::is_base_of_v<nsIFrame, Source>,
    146          "We only support fast do_QueryFrame() where the source must be a "
    147          "derived class of nsIFrame. Consider a two-step do_QueryFrame() "
    148          "(once to nsIFrame, another to the target) if absolutely needed.");
    149      Dest* f = ::detail::FastQueryFrame<Dest>::QueryFrame(mRawPtr);
    150      MOZ_ASSERT(
    151          f == reinterpret_cast<Dest*>(mRawPtr->QueryFrame(Dest::kFrameIID)),
    152          "fast and slow paths should give the same result");
    153      return f;
    154    }
    155    if constexpr (std::is_base_of_v<nsIFrame, Source> &&
    156                  std::is_base_of_v<nsIFrame, Dest>) {
    157      // For non-final frames we can still optimize the virtual call some of the
    158      // time.
    159      if (nsQueryFrame::FrameIID(mRawPtr->GetClassID()) == Dest::kFrameIID) {
    160        auto* f = static_cast<Dest*>(mRawPtr);
    161        MOZ_ASSERT(
    162            f == reinterpret_cast<Dest*>(mRawPtr->QueryFrame(Dest::kFrameIID)),
    163            "fast and slow paths should give the same result");
    164        return f;
    165      }
    166    }
    167    return reinterpret_cast<Dest*>(mRawPtr->QueryFrame(Dest::kFrameIID));
    168  }
    169 
    170 private:
    171  Source* mRawPtr;
    172 };
    173 
    174 template <typename T>
    175 inline do_QueryFrameHelper<T> do_QueryFrame(T* s) {
    176  return do_QueryFrameHelper<T>(s);
    177 }
    178 
    179 #endif  // nsQueryFrame_h