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