LibreOffice Module sw (master) 1
justify.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10#include <vector>
11#include <sal/types.h>
12#include <swfont.hxx>
13#include "justify.hxx"
14
15namespace
16{
17enum class IdeographicPunctuationClass
18{
19 NONE,
20 OPEN_BRACKET,
21 CLOSE_BRACKET,
22 COMMA_OR_FULLSTOP
23};
24
25IdeographicPunctuationClass lcl_WhichPunctuationClass(sal_Unicode cChar)
26{
27 if ((cChar < 0x3001 || cChar > 0x3002) && (cChar < 0x3008 || cChar > 0x3011)
28 && (cChar < 0x3014 || cChar > 0x301F) && 0xFF62 != cChar && 0xFF63 != cChar)
30 else if (0x3001 == cChar || 0x3002 == cChar)
31 return IdeographicPunctuationClass::COMMA_OR_FULLSTOP;
32 else if (0x3009 == cChar || 0x300B == cChar || 0x300D == cChar || 0x300F == cChar
33 || 0x3011 == cChar || 0x3015 == cChar || 0x3017 == cChar || 0x3019 == cChar
34 || 0x301B == cChar || 0x301E == cChar || 0x301F == cChar || 0xFF63 == cChar)
35 // right punctuation
36 return IdeographicPunctuationClass::CLOSE_BRACKET;
37
38 return IdeographicPunctuationClass::OPEN_BRACKET;
39}
40
41tools::Long lcl_MinGridWidth(tools::Long nGridWidth, tools::Long nCharWidth)
42{
43 tools::Long nCount = nCharWidth > nGridWidth ? (nCharWidth - 1) / nGridWidth + 1 : 1;
44 return nCount * nGridWidth;
45}
46
47tools::Long lcl_OffsetFromGridEdge(tools::Long nMinWidth, tools::Long nCharWidth, sal_Unicode cChar,
48 bool bForceLeft)
49{
50 if (bForceLeft)
51 return 0;
52
53 tools::Long nOffset = 0;
54
55 switch (lcl_WhichPunctuationClass(cChar))
56 {
58 // Centered
59 nOffset = (nMinWidth - nCharWidth) / 2;
60 break;
61 case IdeographicPunctuationClass::OPEN_BRACKET:
62 // Align to next edge, closer to next ideograph
63 nOffset = nMinWidth - nCharWidth;
64 break;
65 default:
66 // CLOSE_BRACKET or COMMA_OR_FULLSTOP:
67 // Align to previous edge, closer to previous ideograph.
68 break;
69 }
70 return nOffset;
71}
72}
73
74namespace sw::Justify
75{
76sal_Int32 GetModelPosition(const std::vector<sal_Int32>& rKernArray, sal_Int32 nLen, tools::Long nX)
77{
78 tools::Long nLeft = 0, nRight = 0;
79 sal_Int32 nLast = 0, nIdx = 0;
80
81 do
82 {
83 nRight = rKernArray[nLast];
84 ++nIdx;
85 while (nIdx < nLen && rKernArray[nIdx] == rKernArray[nLast])
86 ++nIdx;
87
88 if (nIdx < nLen)
89 {
90 if (nX < nRight)
91 return (nX - nLeft < nRight - nX) ? nLast : nIdx;
92
93 nLeft = nRight;
94 nLast = nIdx;
95 }
96 } while (nIdx < nLen);
97 return nIdx;
98}
99
100void SpaceDistribution(std::vector<sal_Int32>& rKernArray, const OUString& rText, sal_Int32 nStt,
101 sal_Int32 nLen, tools::Long nSpaceAdd, tools::Long nKern, bool bNoHalfSpace)
102{
103 assert(nStt + nLen <= rText.getLength());
104 assert(nLen <= sal_Int32(rKernArray.size()));
105 // nSpaceSum contains the sum of the intermediate space distributed
106 // among Spaces by the Justification.
107 // The Spaces themselves will be positioned in the middle of the
108 // intermediate space, hence the nSpace/2.
109 // In case of word-by-word underlining they have to be positioned
110 // at the beginning of the intermediate space, so that the space
111 // is not underlined.
112 // A Space at the beginning or end of the text must be positioned
113 // before (resp. after) the whole intermediate space, otherwise
114 // the underline/strike-through would have gaps.
115 tools::Long nSpaceSum = 0;
116 // in word line mode and for Arabic, we disable the half space trick:
117 const tools::Long nHalfSpace = bNoHalfSpace ? 0 : nSpaceAdd / 2;
118 const tools::Long nOtherHalf = nSpaceAdd - nHalfSpace;
119 tools::Long nKernSum = nKern;
120 sal_Unicode cChPrev = rText[nStt];
121
122 if (nSpaceAdd && (cChPrev == CH_BLANK))
123 nSpaceSum = nHalfSpace;
124
125 sal_Int32 nPrevIdx = 0;
126
127 for (sal_Int32 i = 1; i < nLen; ++i, nKernSum += nKern)
128 {
129 // Find the beginning of the next cluster that has a different kern value.
130 while (i < nLen && rKernArray[i] == rKernArray[nPrevIdx])
131 ++i;
132
133 if (i == nLen)
134 break;
135
136 sal_Unicode nCh = rText[nStt + i];
137
138 // Apply SpaceSum
139 if (cChPrev == CH_BLANK)
140 {
141 // no Pixel is lost:
142 nSpaceSum += nOtherHalf;
143 }
144
145 if (nCh == CH_BLANK)
146 {
147 if (i + 1 == nLen)
148 nSpaceSum += nSpaceAdd;
149 else
150 nSpaceSum += nHalfSpace;
151 }
152
153 cChPrev = nCh;
154 rKernArray[nPrevIdx] += nKernSum + nSpaceSum;
155 // In word line mode and for Arabic, we disabled the half space trick. If a portion
156 // ends with a blank, the full nSpaceAdd value has been added to the character in
157 // front of the blank. This leads to painting artifacts, therefore we remove the
158 // nSpaceAdd value again:
159 if (bNoHalfSpace && i + 1 == nLen && nCh == CH_BLANK)
160 rKernArray[nPrevIdx] = rKernArray[nPrevIdx] - nSpaceAdd;
161
162 // Advance nPrevIdx and assign kern values to previous cluster.
163 for (tools::Long nValue = rKernArray[nPrevIdx++]; nPrevIdx < i; ++nPrevIdx)
164 rKernArray[nPrevIdx] = nValue;
165 }
166
167 // the layout engine requires the total width of the output
168 while (nPrevIdx < nLen)
169 rKernArray[nPrevIdx++] += nKernSum + nSpaceSum;
170}
171
172tools::Long SnapToGrid(std::vector<sal_Int32>& rKernArray, const OUString& rText, sal_Int32 nStt,
173 sal_Int32 nLen, tools::Long nGridWidth, bool bForceLeft)
174{
175 assert(nStt + nLen <= rText.getLength());
176 assert(nLen <= sal_Int32(rKernArray.size()));
177
178 tools::Long nCharWidth = rKernArray[0];
179 tools::Long nMinWidth = lcl_MinGridWidth(nGridWidth, nCharWidth);
180 tools::Long nDelta = lcl_OffsetFromGridEdge(nMinWidth, nCharWidth, rText[nStt], bForceLeft);
181 tools::Long nEdge = nMinWidth - nDelta;
182
183 sal_Int32 nLast = 0;
184
185 for (sal_Int32 i = 1; i < nLen; ++i)
186 {
187 if (rKernArray[i] == rKernArray[nLast])
188 continue;
189
190 nCharWidth = rKernArray[i] - rKernArray[nLast];
191 nMinWidth = lcl_MinGridWidth(nGridWidth, nCharWidth);
192 tools::Long nX
193 = nEdge + lcl_OffsetFromGridEdge(nMinWidth, nCharWidth, rText[nStt + i], bForceLeft);
194 nEdge += nMinWidth;
195
196 while (nLast < i)
197 rKernArray[nLast++] = nX;
198 }
199
200 while (nLast < nLen)
201 rKernArray[nLast++] = nEdge;
202
203 return nDelta;
204}
205
206void SnapToGridEdge(std::vector<sal_Int32>& rKernArray, sal_Int32 nLen, tools::Long nGridWidth,
207 tools::Long nSpace, tools::Long nKern)
208{
209 assert(nLen <= sal_Int32(rKernArray.size()));
210
211 tools::Long nCharWidth = rKernArray[0];
212 tools::Long nEdge = lcl_MinGridWidth(nGridWidth, nCharWidth + nKern) + nSpace;
213
214 sal_Int32 nLast = 0;
215
216 for (sal_Int32 i = 1; i < nLen; ++i)
217 {
218 if (rKernArray[i] == rKernArray[nLast])
219 continue;
220
221 nCharWidth = rKernArray[i] - rKernArray[nLast];
222 tools::Long nMinWidth = lcl_MinGridWidth(nGridWidth, nCharWidth + nKern);
223 while (nLast < i)
224 rKernArray[nLast++] = nEdge;
225
226 nEdge += nMinWidth + nSpace;
227 }
228
229 while (nLast < nLen)
230 rKernArray[nLast++] = nEdge;
231}
232}
233
234/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
int nCount
sal_Int16 nValue
int i
void SnapToGridEdge(std::vector< sal_Int32 > &rKernArray, sal_Int32 nLen, tools::Long nGridWidth, tools::Long nSpace, tools::Long nKern)
Snap ideographs to text grids edge ( used when snap to char is off ): space will be distributed ( in ...
Definition: justify.cxx:206
tools::Long SnapToGrid(std::vector< sal_Int32 > &rKernArray, const OUString &rText, sal_Int32 nStt, sal_Int32 nLen, tools::Long nGridWidth, bool bForceLeft)
Snap ideographs to text grids: a) Ideographic open brackets are aligned to the rightmost edge of span...
Definition: justify.cxx:172
sal_Int32 GetModelPosition(const std::vector< sal_Int32 > &rKernArray, sal_Int32 nLen, tools::Long nX)
Get model position base on given kern array.
Definition: justify.cxx:76
void SpaceDistribution(std::vector< sal_Int32 > &rKernArray, const OUString &rText, sal_Int32 nStt, sal_Int32 nLen, tools::Long nSpaceAdd, tools::Long nKern, bool bNoHalfSpace)
Distribute space between words and letters.
Definition: justify.cxx:100
long Long
const sal_Unicode CH_BLANK
Definition: swfont.hxx:42
sal_uInt16 sal_Unicode