tor-browser

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

JustificationUtils.h (4353B)


      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_JustificationUtils_h_
      8 #define mozilla_JustificationUtils_h_
      9 
     10 #include "nsCoord.h"
     11 
     12 namespace mozilla {
     13 
     14 /**
     15 * Jutification Algorithm
     16 *
     17 * The justification algorithm is based on expansion opportunities
     18 * between justifiable clusters.  By this algorithm, there is one
     19 * expansion opportunity at each side of a justifiable cluster, and
     20 * at most one opportunity between two clusters. For example, if there
     21 * is a line in a Chinese document is: "你好世界hello world", then
     22 * the expansion opportunities (marked as '*') would be:
     23 *
     24 *                    你*好*世*界*hello*' '*world
     25 *
     26 * The spacing left in a line will then be distributed equally to each
     27 * opportunities. Because we want that, only justifiable clusters get
     28 * expanded, and the split point between two justifiable clusters would
     29 * be at the middle of the spacing, each expansion opportunities will be
     30 * filled by two justification gaps. The example above would be:
     31 *
     32 *              你 | 好 | 世 | 界  |hello|  ' '  |world
     33 *
     34 * In the algorithm, information about expansion opportunities is stored
     35 * in structure JustificationInfo, and the assignment of justification
     36 * gaps is in structure JustificationAssignment.
     37 */
     38 
     39 struct JustificationInfo {
     40  // Number of expansion opportunities inside a span. It doesn't include
     41  // any opportunities between this span and the one before or after.
     42  int32_t mInnerOpportunities;
     43  // The justifiability of the start and end sides of the span.
     44  bool mIsStartJustifiable;
     45  bool mIsEndJustifiable;
     46 
     47  constexpr JustificationInfo()
     48      : mInnerOpportunities(0),
     49        mIsStartJustifiable(false),
     50        mIsEndJustifiable(false) {}
     51 
     52  // Claim that the last opportunity should be cancelled
     53  // because the trailing space just gets trimmed.
     54  void CancelOpportunityForTrimmedSpace() {
     55    if (mInnerOpportunities > 0) {
     56      mInnerOpportunities--;
     57    } else {
     58      // There is no inner opportunities, hence the whole frame must
     59      // contain only the trimmed space, because any content before
     60      // space would cause an inner opportunity. The space made each
     61      // side justifiable, which should be cancelled now.
     62      mIsStartJustifiable = false;
     63      mIsEndJustifiable = false;
     64    }
     65  }
     66 };
     67 
     68 struct JustificationAssignment {
     69  // There are at most 2 gaps per end, so it is enough to use 2 bits.
     70  uint8_t mGapsAtStart : 2;
     71  uint8_t mGapsAtEnd : 2;
     72 
     73  constexpr JustificationAssignment() : mGapsAtStart(0), mGapsAtEnd(0) {}
     74 
     75  int32_t TotalGaps() const { return mGapsAtStart + mGapsAtEnd; }
     76 };
     77 
     78 struct JustificationApplicationState {
     79  struct {
     80    // The total number of justification gaps to be processed.
     81    int32_t mCount;
     82    // The number of justification gaps which have been handled.
     83    int32_t mHandled;
     84  } mGaps;
     85 
     86  struct {
     87    // The total spacing left in a line before justification.
     88    nscoord mAvailable;
     89    // The spacing has been consumed by handled justification gaps.
     90    nscoord mConsumed;
     91  } mWidth;
     92 
     93  JustificationApplicationState(int32_t aGaps, nscoord aWidth) {
     94    mGaps.mCount = aGaps;
     95    mGaps.mHandled = 0;
     96    mWidth.mAvailable = aWidth;
     97    mWidth.mConsumed = 0;
     98  }
     99 
    100  bool IsJustifiable() const {
    101    return mGaps.mCount > 0 && mWidth.mAvailable > 0;
    102  }
    103 
    104  nscoord Consume(int32_t aGaps) {
    105    mGaps.mHandled += aGaps;
    106    nscoord newAllocate = (mWidth.mAvailable * mGaps.mHandled) / mGaps.mCount;
    107    nscoord deltaWidth = newAllocate - mWidth.mConsumed;
    108    mWidth.mConsumed = newAllocate;
    109    return deltaWidth;
    110  }
    111 };
    112 
    113 class JustificationUtils {
    114 public:
    115  // Compute justification gaps should be applied on a unit.
    116  static int32_t CountGaps(const JustificationInfo& aInfo,
    117                           const JustificationAssignment& aAssign) {
    118    // Justification gaps include two gaps for each inner opportunities
    119    // and the gaps given assigned to the ends.
    120    return aInfo.mInnerOpportunities * 2 + aAssign.TotalGaps();
    121  }
    122 };
    123 
    124 }  // namespace mozilla
    125 
    126 #endif /* !defined(mozilla_JustificationUtils_h_) */