Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; 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 "mozilla/Attributes.h"
11 : #include "nsCoord.h"
12 :
13 : namespace mozilla {
14 :
15 : /**
16 : * Jutification Algorithm
17 : *
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:
24 : *
25 : * 你*好*世*界*hello*' '*world
26 : *
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:
32 : *
33 : * 你 | 好 | 世 | 界 |hello| ' ' |world
34 : *
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.
38 : */
39 :
40 : struct JustificationInfo
41 : {
42 : // Number of expansion opportunities inside a span. It doesn't include
43 : // any opportunities between this span and the one before or after.
44 : int32_t mInnerOpportunities;
45 : // The justifiability of the start and end sides of the span.
46 : bool mIsStartJustifiable;
47 : bool mIsEndJustifiable;
48 :
49 375 : constexpr JustificationInfo()
50 375 : : mInnerOpportunities(0)
51 : , mIsStartJustifiable(false)
52 375 : , mIsEndJustifiable(false)
53 : {
54 375 : }
55 :
56 : // Claim that the last opportunity should be cancelled
57 : // because the trailing space just gets trimmed.
58 0 : void CancelOpportunityForTrimmedSpace()
59 : {
60 0 : if (mInnerOpportunities > 0) {
61 0 : mInnerOpportunities--;
62 : } else {
63 : // There is no inner opportunities, hence the whole frame must
64 : // contain only the trimmed space, because any content before
65 : // space would cause an inner opportunity. The space made each
66 : // side justifiable, which should be cancelled now.
67 0 : mIsStartJustifiable = false;
68 0 : mIsEndJustifiable = false;
69 : }
70 0 : }
71 : };
72 :
73 : struct JustificationAssignment
74 : {
75 : // There are at most 2 gaps per end, so it is enough to use 2 bits.
76 : uint8_t mGapsAtStart : 2;
77 : uint8_t mGapsAtEnd : 2;
78 :
79 150 : constexpr JustificationAssignment()
80 150 : : mGapsAtStart(0)
81 150 : , mGapsAtEnd(0)
82 : {
83 150 : }
84 :
85 0 : int32_t TotalGaps() const { return mGapsAtStart + mGapsAtEnd; }
86 : };
87 :
88 : struct JustificationApplicationState
89 : {
90 : struct
91 : {
92 : // The total number of justification gaps to be processed.
93 : int32_t mCount;
94 : // The number of justification gaps which have been handled.
95 : int32_t mHandled;
96 : } mGaps;
97 :
98 : struct
99 : {
100 : // The total spacing left in a line before justification.
101 : nscoord mAvailable;
102 : // The spacing has been consumed by handled justification gaps.
103 : nscoord mConsumed;
104 : } mWidth;
105 :
106 0 : JustificationApplicationState(int32_t aGaps, nscoord aWidth)
107 0 : {
108 0 : mGaps.mCount = aGaps;
109 0 : mGaps.mHandled = 0;
110 0 : mWidth.mAvailable = aWidth;
111 0 : mWidth.mConsumed = 0;
112 0 : }
113 :
114 0 : bool IsJustifiable() const
115 : {
116 0 : return mGaps.mCount > 0 && mWidth.mAvailable > 0;
117 : }
118 :
119 0 : nscoord Consume(int32_t aGaps)
120 : {
121 0 : mGaps.mHandled += aGaps;
122 0 : nscoord newAllocate = (mWidth.mAvailable * mGaps.mHandled) / mGaps.mCount;
123 0 : nscoord deltaWidth = newAllocate - mWidth.mConsumed;
124 0 : mWidth.mConsumed = newAllocate;
125 0 : return deltaWidth;
126 : }
127 : };
128 :
129 : class JustificationUtils
130 : {
131 : public:
132 : // Compute justification gaps should be applied on a unit.
133 0 : static int32_t CountGaps(const JustificationInfo& aInfo,
134 : const JustificationAssignment& aAssign)
135 : {
136 : // Justification gaps include two gaps for each inner opportunities
137 : // and the gaps given assigned to the ends.
138 0 : return aInfo.mInnerOpportunities * 2 + aAssign.TotalGaps();
139 : }
140 : };
141 :
142 : } // namespace mozilla
143 :
144 : #endif /* !defined(mozilla_JustificationUtils_h_) */
|