simplify writeBitmapObject
[LibreOffice.git] / vcl / source / text / ImplLayoutArgs.cxx
blob73e470ecfe0c8f49980670b630c4a8f7d00038e8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <ImplLayoutArgs.hxx>
22 #include <unicode/ubidi.h>
23 #include <unicode/uchar.h>
25 #include <algorithm>
26 #include <memory>
27 #include <utility>
29 namespace vcl::text
31 ImplLayoutArgs::ImplLayoutArgs(const OUString& rStr, int nMinCharPos, int nEndCharPos,
32 SalLayoutFlags nFlags, LanguageTag aLanguageTag,
33 vcl::text::TextLayoutCache const* const pLayoutCache)
34 : maLanguageTag(std::move(aLanguageTag))
35 , mnFlags(nFlags)
36 , mrStr(rStr)
37 , mnMinCharPos(nMinCharPos)
38 , mnEndCharPos(nEndCharPos)
39 , m_pTextLayoutCache(pLayoutCache)
40 , mnLayoutWidth(0)
41 , mnOrientation(0)
43 if (mnFlags & SalLayoutFlags::BiDiStrong)
45 // handle strong BiDi mode
47 // do not bother to BiDi analyze strong LTR/RTL
48 // TODO: can we assume these strings do not have unicode control chars?
49 // if not remove the control characters from the runs
50 bool bRTL(mnFlags & SalLayoutFlags::BiDiRtl);
51 AddRun(mnMinCharPos, mnEndCharPos, bRTL);
53 else
55 // handle weak BiDi mode
56 UBiDiLevel nLevel = (mnFlags & SalLayoutFlags::BiDiRtl) ? 1 : 0;
58 // prepare substring for BiDi analysis
59 // TODO: reuse allocated pParaBidi
60 UErrorCode rcI18n = U_ZERO_ERROR;
61 const int nLength = mnEndCharPos - mnMinCharPos;
62 UBiDi* pParaBidi = ubidi_openSized(nLength, 0, &rcI18n);
63 if (!pParaBidi)
64 return;
65 ubidi_setPara(pParaBidi, reinterpret_cast<const UChar*>(mrStr.getStr()) + mnMinCharPos,
66 nLength, nLevel, nullptr, &rcI18n);
68 // run BiDi algorithm
69 const int nRunCount = ubidi_countRuns(pParaBidi, &rcI18n);
70 for (int i = 0; i < nRunCount; ++i)
72 int32_t nMinPos, nRunLength;
73 const UBiDiDirection nDir = ubidi_getVisualRun(pParaBidi, i, &nMinPos, &nRunLength);
74 const int nPos0 = nMinPos + mnMinCharPos;
75 const int nPos1 = nPos0 + nRunLength;
77 const bool bRTL = (nDir == UBIDI_RTL);
78 AddRun(nPos0, nPos1, bRTL);
81 // cleanup BiDi engine
82 ubidi_close(pParaBidi);
85 // prepare calls to GetNextPos/GetNextRun
86 maRuns.ResetPos();
89 void ImplLayoutArgs::SetLayoutWidth(double nWidth) { mnLayoutWidth = nWidth; }
91 void ImplLayoutArgs::SetJustificationData(JustificationData stJustification)
93 mstJustification = std::move(stJustification);
96 void ImplLayoutArgs::SetOrientation(Degree10 nOrientation) { mnOrientation = nOrientation; }
98 void ImplLayoutArgs::ResetPos() { maRuns.ResetPos(); }
100 bool ImplLayoutArgs::GetNextPos(int* nCharPos, bool* bRTL)
102 return maRuns.GetNextPos(nCharPos, bRTL);
105 void ImplLayoutArgs::AddFallbackRun(int nMinRunPos, int nEndRunPos, bool bRTL)
107 maFallbackRuns.AddRun(nMinRunPos, nEndRunPos, bRTL);
110 bool ImplLayoutArgs::HasFallbackRun() const { return !maFallbackRuns.IsEmpty(); }
112 static bool IsControlChar(sal_UCS4 cChar)
114 // C0 control characters
115 if ((0x0001 <= cChar) && (cChar <= 0x001F))
116 return true;
117 // formatting characters
118 if ((0x200E <= cChar) && (cChar <= 0x200F))
119 return true;
120 if ((0x2028 <= cChar) && (cChar <= 0x202E))
121 return true;
122 // deprecated formatting characters
123 if ((0x206A <= cChar) && (cChar <= 0x206F))
124 return true;
125 if (0x2060 == cChar)
126 return true;
127 // byte order markers and invalid unicode
128 if ((cChar == 0xFEFF) || (cChar == 0xFFFE) || (cChar == 0xFFFF))
129 return true;
130 // drop null character too, broken documents may contain it (ofz34898-1.doc)
131 if (cChar == 0)
132 return true;
133 return false;
136 // add a run after splitting it up to get rid of control chars
137 void ImplLayoutArgs::AddRun(int nCharPos0, int nCharPos1, bool bRTL)
139 SAL_WARN_IF(nCharPos0 > nCharPos1, "vcl", "ImplLayoutArgs::AddRun() nCharPos0>=nCharPos1");
141 // remove control characters from runs by splitting them up
142 if (!bRTL)
144 for (int i = nCharPos0; i < nCharPos1; ++i)
145 if (IsControlChar(mrStr[i]))
147 // add run until control char
148 maRuns.AddRun(nCharPos0, i, bRTL);
149 nCharPos0 = i + 1;
152 else
154 for (int i = nCharPos1; --i >= nCharPos0;)
155 if (IsControlChar(mrStr[i]))
157 // add run until control char
158 maRuns.AddRun(i + 1, nCharPos1, bRTL);
159 nCharPos1 = i;
163 // add remainder of run
164 maRuns.AddRun(nCharPos0, nCharPos1, bRTL);
167 bool ImplLayoutArgs::PrepareFallback(const SalLayoutGlyphsImpl* pGlyphsImpl)
169 // Generate runs with pre-calculated glyph items instead maFallbackRuns.
170 if (pGlyphsImpl != nullptr)
172 maRuns.Clear();
173 maFallbackRuns.Clear();
175 for (auto const& aGlyphItem : *pGlyphsImpl)
177 for (int i = aGlyphItem.charPos(); i < aGlyphItem.charPos() + aGlyphItem.charCount();
178 ++i)
179 maRuns.AddPos(i, aGlyphItem.IsRTLGlyph());
182 return !maRuns.IsEmpty();
185 // short circuit if no fallback is needed
186 if (maFallbackRuns.IsEmpty())
188 maRuns.Clear();
189 return false;
192 ImplLayoutRuns::PrepareFallbackRuns(&maRuns, &maFallbackRuns);
194 return true;
197 bool ImplLayoutArgs::GetNextRun(int* nMinRunPos, int* nEndRunPos, bool* bRTL)
199 bool bValid = maRuns.GetRun(nMinRunPos, nEndRunPos, bRTL);
200 maRuns.NextRun();
201 return bValid;
205 std::ostream& operator<<(std::ostream& s, vcl::text::ImplLayoutArgs const& rArgs)
207 #ifndef SAL_LOG_INFO
208 (void)rArgs;
209 #else
210 s << "ImplLayoutArgs{";
212 s << "Flags=";
213 if (rArgs.mnFlags == SalLayoutFlags::NONE)
214 s << 0;
215 else
217 bool need_or = false;
218 s << "{";
219 #define TEST(x) \
220 if (rArgs.mnFlags & SalLayoutFlags::x) \
222 if (need_or) \
223 s << "|"; \
224 s << #x; \
225 need_or = true; \
227 TEST(BiDiRtl);
228 TEST(BiDiStrong);
229 TEST(RightAlign);
230 TEST(DisableKerning);
231 TEST(KerningAsian);
232 TEST(Vertical);
233 TEST(DisableLigatures);
234 TEST(ForFallback);
235 #undef TEST
236 s << "}";
239 const int nLength = rArgs.mrStr.getLength();
241 s << ",Length=" << nLength;
242 s << ",MinCharPos=" << rArgs.mnMinCharPos;
243 s << ",EndCharPos=" << rArgs.mnEndCharPos;
245 s << ",Str=\"";
246 int lim = nLength;
247 if (lim > 10)
248 lim = 7;
249 for (int i = 0; i < lim; i++)
251 if (rArgs.mrStr[i] == '\n')
252 s << "\\n";
253 else if (rArgs.mrStr[i] < ' ' || (rArgs.mrStr[i] >= 0x7F && rArgs.mrStr[i] <= 0xFF))
254 s << "\\0x" << std::hex << std::setw(2) << std::setfill('0')
255 << static_cast<int>(rArgs.mrStr[i]) << std::setfill(' ') << std::setw(1) << std::dec;
256 else if (rArgs.mrStr[i] < 0x7F)
257 s << static_cast<char>(rArgs.mrStr[i]);
258 else
259 s << "\\u" << std::hex << std::setw(4) << std::setfill('0')
260 << static_cast<int>(rArgs.mrStr[i]) << std::setfill(' ') << std::setw(1) << std::dec;
262 if (nLength > lim)
263 s << "...";
264 s << "\"";
266 s << ",DXArray=";
267 if (!rArgs.mstJustification.empty())
269 s << "[";
270 int count = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
271 lim = count;
272 if (lim > 10)
273 lim = 7;
274 for (int i = 0; i < lim; i++)
276 s << rArgs.mstJustification.GetTotalAdvance(rArgs.mnMinCharPos + i);
277 if (i < lim - 1)
278 s << ",";
280 if (count > lim)
282 if (count > lim + 1)
283 s << "...";
284 s << rArgs.mstJustification.GetTotalAdvance(rArgs.mnMinCharPos + count - 1);
286 s << "]";
288 else
289 s << "NULL";
291 s << ",KashidaArray=";
292 if (!rArgs.mstJustification.empty() && rArgs.mstJustification.ContainsKashidaPositions())
294 s << "[";
295 int count = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
296 lim = count;
297 if (lim > 10)
298 lim = 7;
299 for (int i = 0; i < lim; i++)
301 s << rArgs.mstJustification.GetPositionHasKashida(rArgs.mnMinCharPos + i)
302 .value_or(false);
303 if (i < lim - 1)
304 s << ",";
306 if (count > lim)
308 if (count > lim + 1)
309 s << "...";
310 s << rArgs.mstJustification.GetPositionHasKashida(rArgs.mnMinCharPos + count - 1)
311 .value_or(false);
313 s << "]";
315 else
316 s << "NULL";
318 s << ",LayoutWidth=" << rArgs.mnLayoutWidth;
320 s << "}";
322 #endif
323 return s;
326 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */