1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
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/.
11 #include <sal/types.h>
12 #include <vcl/kernarray.hxx>
14 #include "justify.hxx"
18 enum class IdeographicPunctuationClass
26 IdeographicPunctuationClass
lcl_WhichPunctuationClass(sal_Unicode cChar
)
28 if ((cChar
< 0x3001 || cChar
> 0x3002) && (cChar
< 0x3008 || cChar
> 0x3011)
29 && (cChar
< 0x3014 || cChar
> 0x301F) && 0xFF62 != cChar
&& 0xFF63 != cChar
)
30 return IdeographicPunctuationClass::NONE
;
31 else if (0x3001 == cChar
|| 0x3002 == cChar
)
32 return IdeographicPunctuationClass::COMMA_OR_FULLSTOP
;
33 else if (0x3009 == cChar
|| 0x300B == cChar
|| 0x300D == cChar
|| 0x300F == cChar
34 || 0x3011 == cChar
|| 0x3015 == cChar
|| 0x3017 == cChar
|| 0x3019 == cChar
35 || 0x301B == cChar
|| 0x301E == cChar
|| 0x301F == cChar
|| 0xFF63 == cChar
)
37 return IdeographicPunctuationClass::CLOSE_BRACKET
;
39 return IdeographicPunctuationClass::OPEN_BRACKET
;
42 tools::Long
lcl_MinGridWidth(tools::Long nGridWidth
, tools::Long nCharWidth
)
44 tools::Long nCount
= nCharWidth
> nGridWidth
? (nCharWidth
- 1) / nGridWidth
+ 1 : 1;
45 return nCount
* nGridWidth
;
48 tools::Long
lcl_OffsetFromGridEdge(tools::Long nMinWidth
, tools::Long nCharWidth
, sal_Unicode cChar
,
54 tools::Long nOffset
= 0;
56 switch (lcl_WhichPunctuationClass(cChar
))
58 case IdeographicPunctuationClass::NONE
:
60 nOffset
= (nMinWidth
- nCharWidth
) / 2;
62 case IdeographicPunctuationClass::OPEN_BRACKET
:
63 // Align to next edge, closer to next ideograph
64 nOffset
= nMinWidth
- nCharWidth
;
67 // CLOSE_BRACKET or COMMA_OR_FULLSTOP:
68 // Align to previous edge, closer to previous ideograph.
77 sal_Int32
GetModelPosition(const KernArray
& rKernArray
, sal_Int32 nLen
, tools::Long nX
)
79 tools::Long nLeft
= 0, nRight
= 0;
80 sal_Int32 nLast
= 0, nIdx
= 0;
84 nRight
= rKernArray
[nLast
];
86 while (nIdx
< nLen
&& rKernArray
[nIdx
] == rKernArray
[nLast
])
92 return (nX
- nLeft
< nRight
- nX
) ? nLast
: nIdx
;
97 } while (nIdx
< nLen
);
101 void SpaceDistribution(KernArray
& rKernArray
, std::u16string_view aText
, sal_Int32 nStt
,
102 sal_Int32 nLen
, tools::Long nSpaceAdd
, tools::Long nKern
, bool bNoHalfSpace
)
104 assert(nStt
+ nLen
<= sal_Int32(aText
.size()));
105 assert(nLen
<= sal_Int32(rKernArray
.size()));
106 // nSpaceSum contains the sum of the intermediate space distributed
107 // among Spaces by the Justification.
108 // The Spaces themselves will be positioned in the middle of the
109 // intermediate space, hence the nSpace/2.
110 // In case of word-by-word underlining they have to be positioned
111 // at the beginning of the intermediate space, so that the space
112 // is not underlined.
113 // A Space at the beginning or end of the text must be positioned
114 // before (resp. after) the whole intermediate space, otherwise
115 // the underline/strike-through would have gaps.
116 tools::Long nSpaceSum
= 0;
117 // in word line mode and for Arabic, we disable the half space trick:
118 const tools::Long nHalfSpace
= bNoHalfSpace
? 0 : nSpaceAdd
/ 2;
119 const tools::Long nOtherHalf
= nSpaceAdd
- nHalfSpace
;
120 tools::Long nKernSum
= nKern
;
121 sal_Unicode cChPrev
= aText
[nStt
];
123 if (nSpaceAdd
&& (cChPrev
== CH_BLANK
))
124 nSpaceSum
= nHalfSpace
;
126 sal_Int32 nPrevIdx
= 0;
128 for (sal_Int32 i
= 1; i
< nLen
; ++i
, nKernSum
+= nKern
)
130 // Find the beginning of the next cluster that has a different kern value.
131 while (i
< nLen
&& rKernArray
[i
] == rKernArray
[nPrevIdx
])
137 sal_Unicode nCh
= aText
[nStt
+ i
];
140 if (cChPrev
== CH_BLANK
)
143 nSpaceSum
+= nOtherHalf
;
149 nSpaceSum
+= nSpaceAdd
;
151 nSpaceSum
+= nHalfSpace
;
155 rKernArray
.adjust(nPrevIdx
, nKernSum
+ nSpaceSum
);
156 // In word line mode and for Arabic, we disabled the half space trick. If a portion
157 // ends with a blank, the full nSpaceAdd value has been added to the character in
158 // front of the blank. This leads to painting artifacts, therefore we remove the
159 // nSpaceAdd value again:
160 if (bNoHalfSpace
&& i
+ 1 == nLen
&& nCh
== CH_BLANK
)
161 rKernArray
.adjust(nPrevIdx
, -nSpaceAdd
);
163 // Advance nPrevIdx and assign kern values to previous cluster.
164 for (tools::Long nValue
= rKernArray
[nPrevIdx
++]; nPrevIdx
< i
; ++nPrevIdx
)
165 rKernArray
.set(nPrevIdx
, nValue
);
168 // the layout engine requires the total width of the output
169 while (nPrevIdx
< nLen
)
171 rKernArray
.adjust(nPrevIdx
, nKernSum
+ nSpaceSum
);
176 tools::Long
SnapToGrid(KernArray
& rKernArray
, std::u16string_view aText
, sal_Int32 nStt
,
177 sal_Int32 nLen
, tools::Long nGridWidth
, bool bForceLeft
)
179 assert(nStt
+ nLen
<= sal_Int32(aText
.size()));
180 assert(nLen
<= sal_Int32(rKernArray
.size()));
182 tools::Long nCharWidth
= rKernArray
[0];
183 tools::Long nMinWidth
= lcl_MinGridWidth(nGridWidth
, nCharWidth
);
184 tools::Long nDelta
= lcl_OffsetFromGridEdge(nMinWidth
, nCharWidth
, aText
[nStt
], bForceLeft
);
185 tools::Long nEdge
= nMinWidth
- nDelta
;
189 for (sal_Int32 i
= 1; i
< nLen
; ++i
)
191 if (rKernArray
[i
] == rKernArray
[nLast
])
194 nCharWidth
= rKernArray
[i
] - rKernArray
[nLast
];
195 nMinWidth
= lcl_MinGridWidth(nGridWidth
, nCharWidth
);
197 = nEdge
+ lcl_OffsetFromGridEdge(nMinWidth
, nCharWidth
, aText
[nStt
+ i
], bForceLeft
);
202 rKernArray
.set(nLast
, nX
);
209 rKernArray
.set(nLast
, nEdge
);
216 void SnapToGridEdge(KernArray
& rKernArray
, sal_Int32 nLen
, tools::Long nGridWidth
,
217 tools::Long nSpace
, tools::Long nKern
)
219 assert(nLen
<= sal_Int32(rKernArray
.size()));
221 tools::Long nCharWidth
= rKernArray
[0];
222 tools::Long nEdge
= lcl_MinGridWidth(nGridWidth
, nCharWidth
+ nKern
) + nSpace
;
226 for (sal_Int32 i
= 1; i
< nLen
; ++i
)
228 if (rKernArray
[i
] == rKernArray
[nLast
])
231 nCharWidth
= rKernArray
[i
] - rKernArray
[nLast
];
232 tools::Long nMinWidth
= lcl_MinGridWidth(nGridWidth
, nCharWidth
+ nKern
);
235 rKernArray
.set(nLast
, nEdge
);
239 nEdge
+= nMinWidth
+ nSpace
;
244 rKernArray
.set(nLast
, nEdge
);
250 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */