tor-browser

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

RubyUtils.h (7267B)


      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 mozilla_RubyUtils_h_
      8 #define mozilla_RubyUtils_h_
      9 
     10 #include "nsCSSAnonBoxes.h"
     11 #include "nsGkAtoms.h"
     12 #include "nsIFrame.h"
     13 #include "nsTArray.h"
     14 
     15 #define RTC_ARRAY_SIZE 1
     16 
     17 class nsRubyFrame;
     18 class nsRubyBaseFrame;
     19 class nsRubyTextFrame;
     20 class nsRubyContentFrame;
     21 class nsRubyBaseContainerFrame;
     22 class nsRubyTextContainerFrame;
     23 
     24 namespace mozilla {
     25 
     26 /**
     27 * Reserved ISize
     28 *
     29 * With some exceptions, each ruby internal box has two isizes, which
     30 * are the reflowed isize and the final isize. The reflowed isize is
     31 * what a box itself needs. It is determined when the box gets reflowed.
     32 *
     33 * The final isize is what a box should be as the final result. For a
     34 * ruby base/text box, the final isize is the size of its ruby column.
     35 * For a ruby base/text container, the final isize is the size of its
     36 * ruby segment. The final isize is never smaller than the reflowed
     37 * isize. It is initially determined when a ruby column/segment gets
     38 * fully reflowed, and may be advanced when a box is expanded, e.g.
     39 * for justification.
     40 *
     41 * The difference between the reflowed isize and the final isize is
     42 * reserved in the line layout after reflowing a box, hence it is called
     43 * "Reserved ISize" here. It is used to expand the ruby boxes from their
     44 * reflowed isize to the final isize during alignment of the line.
     45 *
     46 * There are three exceptions for the final isize:
     47 * 1. A ruby text container has a larger final isize only if it is for
     48 *    a span or collapsed annotations.
     49 * 2. A ruby base container has a larger final isize only if at least
     50 *    one of its ruby text containers does.
     51 * 3. If a ruby text container has a larger final isize, its children
     52 *    must not have.
     53 */
     54 
     55 class RubyUtils {
     56 public:
     57  static inline bool IsRubyContentBox(LayoutFrameType aFrameType) {
     58    return aFrameType == mozilla::LayoutFrameType::RubyBase ||
     59           aFrameType == mozilla::LayoutFrameType::RubyText;
     60  }
     61 
     62  static inline bool IsRubyContainerBox(LayoutFrameType aFrameType) {
     63    return aFrameType == mozilla::LayoutFrameType::RubyBaseContainer ||
     64           aFrameType == mozilla::LayoutFrameType::RubyTextContainer;
     65  }
     66 
     67  static inline bool IsRubyBox(LayoutFrameType aFrameType) {
     68    return aFrameType == mozilla::LayoutFrameType::Ruby ||
     69           IsRubyContentBox(aFrameType) || IsRubyContainerBox(aFrameType);
     70  }
     71 
     72  static inline bool IsExpandableRubyBox(nsIFrame* aFrame) {
     73    mozilla::LayoutFrameType type = aFrame->Type();
     74    return IsRubyContentBox(type) || IsRubyContainerBox(type);
     75  }
     76 
     77  static inline bool IsRubyPseudo(PseudoStyleType aPseudo) {
     78    return aPseudo == PseudoStyleType::blockRubyContent ||
     79           aPseudo == PseudoStyleType::ruby ||
     80           aPseudo == PseudoStyleType::rubyBase ||
     81           aPseudo == PseudoStyleType::rubyText ||
     82           aPseudo == PseudoStyleType::rubyBaseContainer ||
     83           aPseudo == PseudoStyleType::rubyTextContainer;
     84  }
     85 
     86  static void SetReservedISize(nsIFrame* aFrame, nscoord aISize);
     87  static void ClearReservedISize(nsIFrame* aFrame);
     88  static nscoord GetReservedISize(nsIFrame* aFrame);
     89 };
     90 
     91 /**
     92 * This array stores all ruby text containers of the ruby segment
     93 * of the given ruby base container.
     94 */
     95 class MOZ_RAII AutoRubyTextContainerArray final
     96    : public AutoTArray<nsRubyTextContainerFrame*, RTC_ARRAY_SIZE> {
     97 public:
     98  explicit AutoRubyTextContainerArray(nsRubyBaseContainerFrame* aBaseContainer);
     99 };
    100 
    101 /**
    102 * This enumerator enumerates each ruby segment.
    103 */
    104 class MOZ_STACK_CLASS RubySegmentEnumerator {
    105 public:
    106  explicit RubySegmentEnumerator(nsRubyFrame* aRubyFrame);
    107 
    108  void Next();
    109  bool AtEnd() const { return !mBaseContainer; }
    110 
    111  nsRubyBaseContainerFrame* GetBaseContainer() const { return mBaseContainer; }
    112 
    113 private:
    114  nsRubyBaseContainerFrame* mBaseContainer;
    115 };
    116 
    117 /**
    118 * Ruby column is a unit consists of one ruby base and all ruby
    119 * annotations paired with it.
    120 * See http://dev.w3.org/csswg/css-ruby/#ruby-pairing
    121 */
    122 struct MOZ_STACK_CLASS RubyColumn {
    123  nsRubyBaseFrame* mBaseFrame;
    124  AutoTArray<nsRubyTextFrame*, RTC_ARRAY_SIZE> mTextFrames;
    125  bool mIsIntraLevelWhitespace;
    126 
    127  RubyColumn() : mBaseFrame(nullptr), mIsIntraLevelWhitespace(false) {}
    128 
    129  // Helper class to support iteration across the frames within a single
    130  // RubyColumn (the column's ruby base and its annotations).
    131  class MOZ_STACK_CLASS Iterator {
    132   public:
    133    nsIFrame* operator*() const;
    134 
    135    Iterator& operator++() {
    136      ++mIndex;
    137      SkipUntilExistingFrame();
    138      return *this;
    139    }
    140    Iterator operator++(int) {
    141      auto ret = *this;
    142      ++*this;
    143      return ret;
    144    }
    145 
    146    bool operator==(const Iterator& aIter2) const {
    147      MOZ_ASSERT(&mColumn == &aIter2.mColumn,
    148                 "Should only compare iterators of the same ruby column");
    149      return mIndex == aIter2.mIndex;
    150    }
    151    bool operator!=(const Iterator& aIter2) const = default;
    152 
    153   private:
    154    Iterator(const RubyColumn& aColumn, int32_t aIndex)
    155        : mColumn(aColumn), mIndex(aIndex) {
    156      MOZ_ASSERT(
    157          aIndex == -1 ||
    158          (aIndex >= 0 && aIndex <= int32_t(aColumn.mTextFrames.Length())));
    159      SkipUntilExistingFrame();
    160    }
    161    friend struct RubyColumn;  // for the constructor
    162 
    163    void SkipUntilExistingFrame();
    164 
    165    const RubyColumn& mColumn;
    166    // -1 means the ruby base frame,
    167    // non-negative means the index of ruby text frame
    168    // a value of mTextFrames.Length() means we're done iterating
    169    int32_t mIndex = -1;
    170  };
    171 
    172  Iterator begin() const { return Iterator(*this, -1); }
    173  Iterator end() const { return Iterator(*this, mTextFrames.Length()); }
    174  Iterator cbegin() const { return begin(); }
    175  Iterator cend() const { return end(); }
    176 };
    177 
    178 /**
    179 * This enumerator enumerates ruby columns in a segment.
    180 */
    181 class MOZ_STACK_CLASS RubyColumnEnumerator {
    182 public:
    183  RubyColumnEnumerator(nsRubyBaseContainerFrame* aRBCFrame,
    184                       const AutoRubyTextContainerArray& aRTCFrames);
    185 
    186  void Next();
    187  bool AtEnd() const;
    188 
    189  uint32_t GetLevelCount() const { return mFrames.Length(); }
    190  nsRubyContentFrame* GetFrameAtLevel(uint32_t aIndex) const;
    191  void GetColumn(RubyColumn& aColumn) const;
    192 
    193 private:
    194  // Frames in this array are NOT necessary part of the current column.
    195  // When in doubt, use GetFrameAtLevel to access it.
    196  // See GetFrameAtLevel() and Next() for more info.
    197  AutoTArray<nsRubyContentFrame*, RTC_ARRAY_SIZE + 1> mFrames;
    198  // Whether we are on a column for intra-level whitespaces
    199  bool mAtIntraLevelWhitespace;
    200 };
    201 
    202 /**
    203 * Stores block-axis leadings produced from ruby annotations.
    204 */
    205 struct RubyBlockLeadings {
    206  nscoord mStart = 0;
    207  nscoord mEnd = 0;
    208 
    209  void Reset() { mStart = mEnd = 0; }
    210  void Update(nscoord aStart, nscoord aEnd) {
    211    mStart = std::max(mStart, aStart);
    212    mEnd = std::max(mEnd, aEnd);
    213  }
    214  void Update(const RubyBlockLeadings& aOther) {
    215    Update(aOther.mStart, aOther.mEnd);
    216  }
    217 };
    218 
    219 }  // namespace mozilla
    220 
    221 #endif /* !defined(mozilla_RubyUtils_h_) */