/src/mozilla-central/layout/generic/JustificationUtils.h
Line | Count | Source (jump to first uncovered line) |
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 "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 | | constexpr JustificationInfo() |
50 | | : mInnerOpportunities(0) |
51 | | , mIsStartJustifiable(false) |
52 | | , mIsEndJustifiable(false) |
53 | 0 | { |
54 | 0 | } |
55 | | |
56 | | // Claim that the last opportunity should be cancelled |
57 | | // because the trailing space just gets trimmed. |
58 | | void CancelOpportunityForTrimmedSpace() |
59 | 0 | { |
60 | 0 | if (mInnerOpportunities > 0) { |
61 | 0 | mInnerOpportunities--; |
62 | 0 | } else { |
63 | 0 | // There is no inner opportunities, hence the whole frame must |
64 | 0 | // contain only the trimmed space, because any content before |
65 | 0 | // space would cause an inner opportunity. The space made each |
66 | 0 | // side justifiable, which should be cancelled now. |
67 | 0 | mIsStartJustifiable = false; |
68 | 0 | mIsEndJustifiable = false; |
69 | 0 | } |
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 | | constexpr JustificationAssignment() |
80 | | : mGapsAtStart(0) |
81 | | , mGapsAtEnd(0) |
82 | 0 | { |
83 | 0 | } |
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 | | 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 | | bool IsJustifiable() const |
115 | 0 | { |
116 | 0 | return mGaps.mCount > 0 && mWidth.mAvailable > 0; |
117 | 0 | } |
118 | | |
119 | | nscoord Consume(int32_t aGaps) |
120 | 0 | { |
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 | 0 | } |
127 | | }; |
128 | | |
129 | | class JustificationUtils |
130 | | { |
131 | | public: |
132 | | // Compute justification gaps should be applied on a unit. |
133 | | static int32_t CountGaps(const JustificationInfo& aInfo, |
134 | | const JustificationAssignment& aAssign) |
135 | 0 | { |
136 | 0 | // Justification gaps include two gaps for each inner opportunities |
137 | 0 | // and the gaps given assigned to the ends. |
138 | 0 | return aInfo.mInnerOpportunities * 2 + aAssign.TotalGaps(); |
139 | 0 | } |
140 | | }; |
141 | | |
142 | | } // namespace mozilla |
143 | | |
144 | | #endif /* !defined(mozilla_JustificationUtils_h_) */ |