Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfgas_txtbreak.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "xfa/fgas/layout/cfgas_txtbreak.h"
8
9#include <algorithm>
10#include <array>
11
12#include "build/build_config.h"
13#include "core/fxcrt/check.h"
14#include "core/fxcrt/compiler_specific.h"
15#include "core/fxcrt/containers/adapters.h"
16#include "core/fxcrt/fx_codepage.h"
17#include "core/fxcrt/fx_extension.h"
18#include "core/fxcrt/fx_safe_types.h"
19#include "core/fxcrt/numerics/safe_conversions.h"
20#include "core/fxcrt/stl_util.h"
21#include "core/fxge/text_char_pos.h"
22#include "xfa/fgas/font/cfgas_gefont.h"
23#include "xfa/fgas/layout/cfgas_char.h"
24#include "xfa/fgas/layout/fgas_arabic.h"
25#include "xfa/fgas/layout/fgas_linebreak.h"
26
27namespace {
28
29struct FX_FORMCHAR {
30 uint16_t wch;
31 uint16_t wForm;
32 int32_t iWidth;
33};
34
35bool IsCtrlCode(wchar_t wch) {
36 FX_CHARTYPE dwRet = pdfium::unicode::GetCharType(wch);
37 return dwRet == FX_CHARTYPE::kTab || dwRet == FX_CHARTYPE::kControl;
38}
39
40} // namespace
41
43
44CFGAS_TxtBreak::~CFGAS_TxtBreak() = default;
45
46void CFGAS_TxtBreak::SetLineWidth(float fLineWidth) {
48 DCHECK(m_iLineWidth >= 20000);
49}
50
51void CFGAS_TxtBreak::SetAlignment(int32_t iAlignment) {
52 DCHECK(iAlignment >= CFX_TxtLineAlignment_Left);
53 DCHECK(iAlignment <= CFX_TxtLineAlignment_Justified);
54 m_iAlignment = iAlignment;
55}
56
57void CFGAS_TxtBreak::SetCombWidth(float fCombWidth) {
58 m_iCombWidth = FXSYS_roundf(fCombWidth * kConversionFactor);
59}
60
61void CFGAS_TxtBreak::AppendChar_Combination(CFGAS_Char* pCurChar) {
62 FX_SAFE_INT32 iCharWidth = m_iCombWidth;
63 pCurChar->m_iCharWidth = -1;
64 if (!m_bCombText) {
65 wchar_t wch = pCurChar->char_code();
66 CFGAS_Char* pLastChar = GetLastChar(0, false, false);
67 if (pLastChar &&
69 wchar_t wLast = pLastChar->char_code();
70 std::optional<uint16_t> maybe_shadda;
71 if (wch == pdfium::kArabicShadda) {
72 maybe_shadda = pdfium::GetArabicFromShaddaTable(wLast);
73 } else if (wLast == pdfium::kArabicShadda) {
74 maybe_shadda = pdfium::GetArabicFromShaddaTable(wch);
75 }
76 if (maybe_shadda.has_value()) {
77 wch = maybe_shadda.value();
80 pLastChar->m_iCharWidth = 0;
81 }
82 }
83 std::optional<uint16_t> iCharWidthRet;
84 if (m_pFont) {
85 iCharWidthRet = m_pFont->GetCharWidth(wch);
86 }
87 iCharWidth = iCharWidthRet.value_or(0);
88 iCharWidth *= m_iFontSize;
89 iCharWidth *= m_iHorizontalScale;
90 iCharWidth /= 100;
91 }
92 iCharWidth *= -1;
93 pCurChar->m_iCharWidth = iCharWidth.ValueOrDefault(0);
94}
95
96void CFGAS_TxtBreak::AppendChar_Tab(CFGAS_Char* pCurChar) {
97 m_eCharType = FX_CHARTYPE::kTab;
98}
99
100CFGAS_Char::BreakType CFGAS_TxtBreak::AppendChar_Control(CFGAS_Char* pCurChar) {
101 m_eCharType = FX_CHARTYPE::kControl;
103 if (!m_bSingleLine) {
104 wchar_t wch = pCurChar->char_code();
105 switch (wch) {
106 case L'\v':
109 break;
110 case L'\f':
112 break;
115 break;
116 default:
117 if (wch == m_wParagraphBreakChar)
119 break;
120 }
121 if (dwRet != CFGAS_Char::BreakType::kNone)
122 dwRet = EndBreak(dwRet);
123 }
124 return dwRet;
125}
126
127CFGAS_Char::BreakType CFGAS_TxtBreak::AppendChar_Arabic(CFGAS_Char* pCurChar) {
128 FX_CHARTYPE chartype = pCurChar->GetCharType();
129 int32_t& iLineWidth = m_pCurLine->m_iWidth;
130 wchar_t wForm;
131 CFGAS_Char* pLastChar = nullptr;
132 bool bAlef = false;
133 if (!m_bCombText && m_eCharType >= FX_CHARTYPE::kArabicAlef &&
134 m_eCharType <= FX_CHARTYPE::kArabicDistortion) {
135 FX_SAFE_INT32 iCharWidth = 0;
136 pLastChar = GetLastChar(1, true, false);
137 if (pLastChar) {
138 if (pLastChar->m_iCharWidth > 0)
139 iLineWidth -= pLastChar->m_iCharWidth;
140 iCharWidth = pLastChar->m_iCharWidth;
141
142 CFGAS_Char* pPrevChar = GetLastChar(2, true, false);
143 wForm = pdfium::GetArabicFormChar(pLastChar, pPrevChar, pCurChar);
144 bAlef = (wForm == pdfium::unicode::kZeroWidthNoBreakSpace &&
145 pLastChar->GetCharType() == FX_CHARTYPE::kArabicAlef);
146 if (m_pFont) {
147 iCharWidth = m_pFont->GetCharWidth(wForm).value_or(0);
148 }
150 iCharWidth = 0;
151
152 iCharWidth *= m_iFontSize;
153 iCharWidth *= m_iHorizontalScale;
154 iCharWidth /= 100;
155
156 int32_t iCharWidthValid = iCharWidth.ValueOrDefault(0);
157 pLastChar->m_iCharWidth = iCharWidthValid;
158 iLineWidth += iCharWidthValid;
159 }
160 }
161
162 m_eCharType = chartype;
163 wForm =
164 pdfium::GetArabicFormChar(pCurChar, bAlef ? nullptr : pLastChar, nullptr);
165 FX_SAFE_INT32 iCharWidth = 0;
166 if (m_bCombText) {
167 iCharWidth = m_iCombWidth;
168 } else {
169 if (m_pFont && wForm != pdfium::unicode::kZeroWidthNoBreakSpace) {
170 iCharWidth = m_pFont->GetCharWidth(wForm).value_or(0);
171 }
172 iCharWidth *= m_iFontSize;
173 iCharWidth *= m_iHorizontalScale;
174 iCharWidth /= 100;
175 }
176
177 int32_t iCharWidthValid = iCharWidth.ValueOrDefault(0);
178 pCurChar->m_iCharWidth = iCharWidthValid;
179 iLineWidth += iCharWidthValid;
180
181 m_pCurLine->IncrementArabicCharCount();
182 if (!m_bSingleLine && IsGreaterThanLineWidth(iLineWidth))
185}
186
187CFGAS_Char::BreakType CFGAS_TxtBreak::AppendChar_Others(CFGAS_Char* pCurChar) {
188 FX_CHARTYPE chartype = pCurChar->GetCharType();
189 int32_t& iLineWidth = m_pCurLine->m_iWidth;
190 m_eCharType = chartype;
191 wchar_t wch = pCurChar->char_code();
192 wchar_t wForm = wch;
193
194 FX_SAFE_INT32 iCharWidth = 0;
195 if (m_bCombText) {
196 iCharWidth = m_iCombWidth;
197 } else if (m_pFont) {
198 iCharWidth = m_pFont->GetCharWidth(wForm).value_or(0);
199 iCharWidth *= m_iFontSize;
200 iCharWidth *= m_iHorizontalScale;
201 iCharWidth /= 100;
202 }
203 iCharWidth += m_iCharSpace;
204
205 int32_t iValidCharWidth = iCharWidth.ValueOrDefault(0);
206 pCurChar->m_iCharWidth = iValidCharWidth;
207 iLineWidth += iValidCharWidth;
208 if (!m_bSingleLine && chartype != FX_CHARTYPE::kSpace &&
209 IsGreaterThanLineWidth(iLineWidth)) {
211 }
212
214}
215
216CFGAS_Char::BreakType CFGAS_TxtBreak::AppendChar(wchar_t wch) {
217 FX_CHARTYPE chartype = pdfium::unicode::GetCharType(wch);
218 m_pCurLine->m_LineChars.emplace_back(wch, m_iHorizontalScale,
219 m_iVerticalScale);
220 CFGAS_Char* pCurChar = &m_pCurLine->m_LineChars.back();
221 pCurChar->m_dwCharStyles = m_iAlignment | (1 << 8);
222
224 if (chartype != FX_CHARTYPE::kCombination &&
225 GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype) &&
226 m_eCharType != FX_CHARTYPE::kUnknown && !m_bSingleLine &&
227 IsGreaterThanLineWidth(m_pCurLine->m_iWidth) &&
228 (m_eCharType != FX_CHARTYPE::kSpace ||
229 chartype != FX_CHARTYPE::kControl)) {
231 if (!m_pCurLine->m_LineChars.empty())
232 pCurChar = &m_pCurLine->m_LineChars.back();
233 }
234
236 if (wch == m_wParagraphBreakChar) {
237 // This is handled in AppendChar_Control, but it seems like \n and \r
238 // don't get matched as control characters so we go into AppendChar_other
239 // and never detect the new paragraph ...
241 EndBreak(dwRet2);
242 } else {
243 switch (chartype) {
244 case FX_CHARTYPE::kTab:
245 AppendChar_Tab(pCurChar);
246 break;
247 case FX_CHARTYPE::kControl:
248 dwRet2 = AppendChar_Control(pCurChar);
249 break;
250 case FX_CHARTYPE::kCombination:
251 AppendChar_Combination(pCurChar);
252 break;
253 case FX_CHARTYPE::kArabicAlef:
254 case FX_CHARTYPE::kArabicSpecial:
255 case FX_CHARTYPE::kArabicDistortion:
256 case FX_CHARTYPE::kArabicNormal:
257 case FX_CHARTYPE::kArabicForm:
258 case FX_CHARTYPE::kArabic:
259 dwRet2 = AppendChar_Arabic(pCurChar);
260 break;
261 case FX_CHARTYPE::kUnknown:
262 case FX_CHARTYPE::kSpace:
263 case FX_CHARTYPE::kNumeric:
264 case FX_CHARTYPE::kNormal:
265 dwRet2 = AppendChar_Others(pCurChar);
266 break;
267 }
268 }
269 return std::max(dwRet1, dwRet2);
270}
271
272void CFGAS_TxtBreak::EndBreakSplitLine(CFGAS_BreakLine* pNextLine,
273 bool bAllChars) {
274 bool bDone = false;
275 CFGAS_Char* pTC;
276 if (!m_bSingleLine && IsGreaterThanLineWidth(m_pCurLine->m_iWidth)) {
277 pTC = m_pCurLine->LastChar();
278 switch (pTC->GetCharType()) {
279 case FX_CHARTYPE::kTab:
280 case FX_CHARTYPE::kControl:
281 case FX_CHARTYPE::kSpace:
282 break;
283 default:
284 SplitTextLine(m_pCurLine, pNextLine, bAllChars);
285 bDone = true;
286 break;
287 }
288 }
289 if (bAllChars && !bDone) {
290 int32_t iEndPos = m_pCurLine->m_iWidth;
291 GetBreakPos(&m_pCurLine->m_LineChars, bAllChars, true, &iEndPos);
292 }
293}
294
295std::deque<CFGAS_Break::TPO> CFGAS_TxtBreak::EndBreakBidiLine(
296 CFGAS_Char::BreakType dwStatus) {
298 std::deque<TPO> tpos;
299 CFGAS_Char* pTC;
300 std::vector<CFGAS_Char>& chars = m_pCurLine->m_LineChars;
301 if (!m_pCurLine->HasArabicChar()) {
302 tp.SetStatus(dwStatus);
303 tp.SetStartPos(m_pCurLine->m_iStart);
304 tp.SetWidth(m_pCurLine->m_iWidth);
306 tp.SetCharCount(fxcrt::CollectionSize<int32_t>(m_pCurLine->m_LineChars));
307 tp.SetChars(&m_pCurLine->m_LineChars);
308 pTC = &chars[0];
312 m_pCurLine->m_LinePieces.push_back(tp);
313 tpos.push_back({0, 0});
314 return tpos;
315 }
316
317 size_t iBidiNum = 0;
318 for (size_t i = 0; i < m_pCurLine->m_LineChars.size(); ++i) {
319 pTC = &chars[i];
320 pTC->m_iBidiPos = static_cast<int32_t>(i);
321 if (pTC->GetCharType() != FX_CHARTYPE::kControl)
322 iBidiNum = i;
323 if (i == 0)
324 pTC->m_iBidiLevel = 1;
325 }
326 CFGAS_Char::BidiLine(&chars, iBidiNum + 1);
327
329 tp.SetStartPos(m_pCurLine->m_iStart);
330 tp.SetChars(&m_pCurLine->m_LineChars);
331 int32_t iBidiLevel = -1;
332 int32_t iCharWidth;
333 int32_t i = 0;
334 int32_t j = -1;
335 int32_t iCount = fxcrt::CollectionSize<int32_t>(m_pCurLine->m_LineChars);
336 while (i < iCount) {
337 pTC = &chars[i];
338 if (iBidiLevel < 0) {
339 iBidiLevel = pTC->m_iBidiLevel;
340 tp.SetWidth(0);
341 tp.SetBidiLevel(iBidiLevel);
347 }
348 if (iBidiLevel != pTC->m_iBidiLevel ||
350 if (iBidiLevel == pTC->m_iBidiLevel) {
352 iCharWidth = pTC->m_iCharWidth;
353 if (iCharWidth > 0)
354 tp.IncrementWidth(iCharWidth);
355
356 i++;
357 }
359 m_pCurLine->m_LinePieces.push_back(tp);
362 tpos.push_back({++j, tp.GetBidiPos()});
363 iBidiLevel = -1;
364 } else {
365 iCharWidth = pTC->m_iCharWidth;
366 if (iCharWidth > 0)
367 tp.IncrementWidth(iCharWidth);
368
369 i++;
370 }
371 }
372 if (i > tp.GetStartChar()) {
373 tp.SetStatus(dwStatus);
375 m_pCurLine->m_LinePieces.push_back(tp);
376 tpos.push_back({++j, tp.GetBidiPos()});
377 }
378 if (j > -1) {
379 if (j > 0) {
380 std::sort(tpos.begin(), tpos.end());
381 int32_t iStartPos = 0;
382 for (i = 0; i <= j; i++) {
383 CFGAS_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpos[i].index];
384 ttp.SetStartPos(iStartPos);
385 iStartPos += ttp.GetWidth();
386 }
387 }
388 m_pCurLine->m_LinePieces[j].SetStatus(dwStatus);
389 }
390 return tpos;
391}
392
393void CFGAS_TxtBreak::EndBreakAlignment(const std::deque<TPO>& tpos,
394 bool bAllChars,
395 CFGAS_Char::BreakType dwStatus) {
396 int32_t iNetWidth = m_pCurLine->m_iWidth;
397 int32_t iGapChars = 0;
398 bool bFind = false;
399 for (const TPO& pos : pdfium::Reversed(tpos)) {
400 const CFGAS_BreakPiece& ttp = m_pCurLine->m_LinePieces[pos.index];
401 if (!bFind)
402 iNetWidth = ttp.GetEndPos();
403
404 bool bArabic = FX_IsOdd(ttp.GetBidiLevel());
405 int32_t j = bArabic ? 0 : ttp.GetCharCount() - 1;
406 while (j > -1 && j < ttp.GetCharCount()) {
407 const CFGAS_Char* pTC = ttp.GetChar(j);
408 if (pTC->m_eLineBreakType == FX_LINEBREAKTYPE::kDIRECT_BRK)
409 iGapChars++;
410 if (!bFind || !bAllChars) {
411 FX_CHARTYPE chartype = pTC->GetCharType();
412 if (chartype == FX_CHARTYPE::kSpace ||
413 chartype == FX_CHARTYPE::kControl) {
414 if (!bFind && bAllChars && pTC->m_iCharWidth > 0)
415 iNetWidth -= pTC->m_iCharWidth;
416 } else {
417 bFind = true;
418 if (!bAllChars)
419 break;
420 }
421 }
422 j += bArabic ? 1 : -1;
423 }
424 if (!bAllChars && bFind)
425 break;
426 }
427
428 int32_t iOffset = m_iLineWidth - iNetWidth;
429 if (iGapChars > 0 && m_iAlignment & CFX_TxtLineAlignment_Justified &&
431 int32_t iStart = -1;
432 for (auto& tpo : tpos) {
433 CFGAS_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpo.index];
434 if (iStart < -1)
435 iStart = ttp.GetStartPos();
436 else
437 ttp.SetStartPos(iStart);
438
439 for (int32_t j = 0; j < ttp.GetCharCount() && iGapChars > 0;
440 j++, iGapChars--) {
441 CFGAS_Char* pTC = ttp.GetChar(j);
442 if (pTC->m_eLineBreakType != FX_LINEBREAKTYPE::kDIRECT_BRK ||
443 pTC->m_iCharWidth < 0) {
444 continue;
445 }
446 int32_t k = iOffset / iGapChars;
447 pTC->m_iCharWidth += k;
448 ttp.IncrementWidth(k);
449 iOffset -= k;
450 }
451 iStart += ttp.GetWidth();
452 }
453 } else if (m_iAlignment & CFX_TxtLineAlignment_Center ||
454 m_iAlignment & CFX_TxtLineAlignment_Right) {
455 if (m_iAlignment & CFX_TxtLineAlignment_Center &&
456 !(m_iAlignment & CFX_TxtLineAlignment_Right)) {
457 iOffset /= 2;
458 }
459 if (iOffset > 0) {
460 for (auto& ttp : m_pCurLine->m_LinePieces)
461 ttp.IncrementStartPos(iOffset);
462 }
463 }
464}
465
466CFGAS_Char::BreakType CFGAS_TxtBreak::EndBreak(CFGAS_Char::BreakType dwStatus) {
467 DCHECK(dwStatus != CFGAS_Char::BreakType::kNone);
468
469 if (!m_pCurLine->m_LinePieces.empty()) {
470 if (dwStatus != CFGAS_Char::BreakType::kPiece)
471 m_pCurLine->m_LinePieces.back().SetStatus(dwStatus);
472 return m_pCurLine->m_LinePieces.back().GetStatus();
473 }
474
475 if (HasLine()) {
476 if (m_Lines[m_iReadyLineIndex].m_LinePieces.empty())
478
479 if (dwStatus != CFGAS_Char::BreakType::kPiece)
480 m_Lines[m_iReadyLineIndex].m_LinePieces.back().SetStatus(dwStatus);
481 return m_Lines[m_iReadyLineIndex].m_LinePieces.back().GetStatus();
482 }
483
484 if (m_pCurLine->m_LineChars.empty())
486
487 m_pCurLine->m_LineChars.back().m_dwStatus = dwStatus;
488 if (dwStatus == CFGAS_Char::BreakType::kPiece)
489 return dwStatus;
490
491 m_iReadyLineIndex = m_pCurLine == &m_Lines[0] ? 0 : 1;
492 CFGAS_BreakLine* pNextLine = &m_Lines[1 - m_iReadyLineIndex];
493 const bool bAllChars = m_iAlignment > CFX_TxtLineAlignment_Right;
494 EndBreakSplitLine(pNextLine, bAllChars);
495
496 std::deque<TPO> tpos = EndBreakBidiLine(dwStatus);
497 if (m_iAlignment > CFX_TxtLineAlignment_Left)
498 EndBreakAlignment(tpos, bAllChars, dwStatus);
499
500 m_pCurLine = pNextLine;
501 CFGAS_Char* pTC = GetLastChar(0, false, false);
502 m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE::kUnknown;
503 return dwStatus;
504}
505
506int32_t CFGAS_TxtBreak::GetBreakPos(std::vector<CFGAS_Char>* pChars,
507 bool bAllChars,
508 bool bOnlyBrk,
509 int32_t* pEndPos) {
510 std::vector<CFGAS_Char>& chars = *pChars;
511 int32_t iLength = fxcrt::CollectionSize<int32_t>(chars) - 1;
512 if (iLength < 1)
513 return iLength;
514
515 int32_t iBreak = -1;
516 int32_t iBreakPos = -1;
517 int32_t iIndirect = -1;
518 int32_t iIndirectPos = -1;
519 int32_t iLast = -1;
520 int32_t iLastPos = -1;
521 if (m_bSingleLine || *pEndPos <= m_iLineWidth) {
522 if (!bAllChars)
523 return iLength;
524
525 iBreak = iLength;
526 iBreakPos = *pEndPos;
527 }
528
529 FX_LINEBREAKTYPE eType;
530 FX_BREAKPROPERTY nCur;
531 FX_BREAKPROPERTY nNext;
532 CFGAS_Char* pCur = &chars[iLength--];
533 if (bAllChars)
535
536 nNext = pdfium::unicode::GetBreakProperty(pCur->char_code());
537 int32_t iCharWidth = pCur->m_iCharWidth;
538 if (iCharWidth > 0)
539 *pEndPos -= iCharWidth;
540
541 while (iLength >= 0) {
542 pCur = &chars[iLength];
543 nCur = pdfium::unicode::GetBreakProperty(pCur->char_code());
544 if (nNext == FX_BREAKPROPERTY::kSP)
546 else
547 eType = GetLineBreakTypeFromPair(nCur, nNext);
548 if (bAllChars)
549 pCur->m_eLineBreakType = eType;
550 if (!bOnlyBrk) {
551 if (m_bSingleLine || *pEndPos <= m_iLineWidth ||
552 nCur == FX_BREAKPROPERTY::kSP) {
553 if (eType == FX_LINEBREAKTYPE::kDIRECT_BRK && iBreak < 0) {
554 iBreak = iLength;
555 iBreakPos = *pEndPos;
556 if (!bAllChars)
557 return iLength;
558 } else if (eType == FX_LINEBREAKTYPE::kINDIRECT_BRK && iIndirect < 0) {
559 iIndirect = iLength;
560 iIndirectPos = *pEndPos;
561 }
562 if (iLast < 0) {
563 iLast = iLength;
564 iLastPos = *pEndPos;
565 }
566 }
567 iCharWidth = pCur->m_iCharWidth;
568 if (iCharWidth > 0)
569 *pEndPos -= iCharWidth;
570 }
571 nNext = nCur;
572 iLength--;
573 }
574 if (bOnlyBrk)
575 return 0;
576 if (iBreak > -1) {
577 *pEndPos = iBreakPos;
578 return iBreak;
579 }
580 if (iIndirect > -1) {
581 *pEndPos = iIndirectPos;
582 return iIndirect;
583 }
584 if (iLast > -1) {
585 *pEndPos = iLastPos;
586 return iLast;
587 }
588 return 0;
589}
590
591void CFGAS_TxtBreak::SplitTextLine(CFGAS_BreakLine* pCurLine,
592 CFGAS_BreakLine* pNextLine,
593 bool bAllChars) {
594 DCHECK(pCurLine);
595 DCHECK(pNextLine);
596
597 if (pCurLine->m_LineChars.size() < 2)
598 return;
599
600 int32_t iEndPos = pCurLine->m_iWidth;
601 std::vector<CFGAS_Char>& curChars = pCurLine->m_LineChars;
602 int32_t iCharPos = GetBreakPos(&curChars, bAllChars, false, &iEndPos);
603 if (iCharPos < 0)
604 iCharPos = 0;
605
606 iCharPos++;
607 if (iCharPos >= fxcrt::CollectionSize<int32_t>(pCurLine->m_LineChars)) {
608 pNextLine->Clear();
609 CFGAS_Char* pTC = &curChars[iCharPos - 1];
611 return;
612 }
613
614 pNextLine->m_LineChars =
615 std::vector<CFGAS_Char>(curChars.begin() + iCharPos, curChars.end());
616 curChars.erase(curChars.begin() + iCharPos, curChars.end());
617 pCurLine->m_iWidth = iEndPos;
618 CFGAS_Char* pTC = &curChars[iCharPos - 1];
620 int32_t iWidth = 0;
621 for (size_t i = 0; i < pNextLine->m_LineChars.size(); ++i) {
622 if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE::kArabicAlef) {
625 }
626 iWidth += std::max(0, pNextLine->m_LineChars[i].m_iCharWidth);
627 pNextLine->m_LineChars[i].m_dwStatus = CFGAS_Char::BreakType::kNone;
628 }
629 pNextLine->m_iWidth = iWidth;
630}
631
632size_t CFGAS_TxtBreak::GetDisplayPos(const Run& run,
633 pdfium::span<TextCharPos> pCharPos) const {
634 if (run.iLength < 1)
635 return 0;
636
637 Engine* pEngine = run.pEdtEngine;
638 WideStringView pStr = run.wsStr.AsStringView();
639 pdfium::span<int32_t> pWidths = run.pWidths;
640 int32_t iLength = run.iLength - 1;
641 RetainPtr<CFGAS_GEFont> pFont = run.pFont;
642 Mask<LayoutStyle> dwStyles = run.dwStyles;
643 CFX_RectF rtText(*run.pRect);
644 const bool bRTLPiece = (run.dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel) != 0;
645 const float fFontSize = run.fFontSize;
646 const int32_t iFontSize = FXSYS_roundf(fFontSize * 20.0f);
647 const int32_t iAscent = pFont->GetAscent();
648 const int32_t iDescent = pFont->GetDescent();
649 const int32_t iMaxHeight = iAscent - iDescent;
650 const float fAscent = iMaxHeight ? fFontSize * iAscent / iMaxHeight : 0;
651 int32_t iHorScale = run.iHorizontalScale;
652 int32_t iVerScale = run.iVerticalScale;
653 bool bSkipSpace = run.bSkipSpace;
654
655 const float fYBase = rtText.top + (rtText.height - fFontSize) / 2.0f;
656 float fX = bRTLPiece ? rtText.right() : rtText.left;
657 float fY = fYBase + fAscent;
658
659 size_t szCount = 0;
660 int32_t iNext = 0;
665 bool bShadda = false;
666 bool bLam = false;
667 for (int32_t i = 0; i <= iLength; i++) {
668 int32_t iAbsolute = i + run.iStart;
669 int32_t iWidth;
670 wchar_t wch;
671 if (pEngine) {
672 wch = pEngine->GetChar(iAbsolute);
673 iWidth = pEngine->GetWidthOfChar(iAbsolute);
674 } else {
675 wch = pStr.Front();
676 pStr = pStr.Substr(1);
677 iWidth = pWidths.front();
678 pWidths = pWidths.subspan(1);
679 }
680
681 FX_CHARTYPE chartype = pdfium::unicode::GetCharType(wch);
682 if (chartype == FX_CHARTYPE::kArabicAlef && iWidth == 0) {
684 wLast = wch;
685 continue;
686 }
687
688 if (chartype >= FX_CHARTYPE::kArabicAlef) {
689 if (i < iLength) {
690 if (pEngine) {
691 iNext = i + 1;
692 while (iNext <= iLength) {
693 int32_t iNextAbsolute = iNext + run.iStart;
694 wNext = pEngine->GetChar(iNextAbsolute);
695 if (pdfium::unicode::GetCharType(wNext) !=
696 FX_CHARTYPE::kCombination) {
697 break;
698 }
699 iNext++;
700 }
701 if (iNext > iLength)
703 } else {
704 int32_t j = -1;
705 do {
706 j++;
707 if (i + j >= iLength) {
708 break;
709 }
710 wNext = pStr[j];
711 } while (pdfium::unicode::GetCharType(wNext) ==
712 FX_CHARTYPE::kCombination);
713 if (i + j >= iLength)
715 }
716 } else {
718 }
719
720 wForm = pdfium::GetArabicFormChar(wch, wPrev, wNext);
721 bLam = (wPrev == pdfium::kArabicLetterLam &&
723 wNext == pdfium::kArabicLetterHeh);
724 } else if (chartype == FX_CHARTYPE::kCombination) {
725 wForm = wch;
726 if (wch >= 0x064C && wch <= 0x0651) {
727 if (bShadda) {
729 bShadda = false;
730 } else {
732 if (pEngine) {
733 iNext = i + 1;
734 if (iNext <= iLength) {
735 int32_t iNextAbsolute = iNext + run.iStart;
736 wNext = pEngine->GetChar(iNextAbsolute);
737 }
738 } else if (i < iLength) {
739 wNext = pStr.Front();
740 }
741 std::optional<uint16_t> maybe_shadda;
742 if (wch == pdfium::kArabicShadda) {
743 maybe_shadda = pdfium::GetArabicFromShaddaTable(wNext);
744 } else if (wNext == pdfium::kArabicShadda) {
745 maybe_shadda = pdfium::GetArabicFromShaddaTable(wch);
746 }
747 if (maybe_shadda.has_value()) {
748 wForm = maybe_shadda.value();
749 bShadda = true;
750 }
751 }
752 } else {
753 bShadda = false;
754 }
755 } else if (chartype == FX_CHARTYPE::kNumeric) {
756 wForm = wch;
757 } else if (wch == L'.') {
758 wForm = wch;
759 } else if (wch == L',') {
760 wForm = wch;
761 } else if (bRTLPiece) {
763 } else {
764 wForm = wch;
765 }
766 if (chartype != FX_CHARTYPE::kCombination)
767 bShadda = false;
768 if (chartype < FX_CHARTYPE::kArabicAlef)
769 bLam = false;
770
771 bool bEmptyChar =
772 (chartype >= FX_CHARTYPE::kTab && chartype <= FX_CHARTYPE::kControl);
774 bEmptyChar = true;
775
776 int32_t iForms = bLam ? 3 : 1;
777 szCount += (bEmptyChar && bSkipSpace) ? 0 : iForms;
778 if (pCharPos.empty()) {
779 if (iWidth > 0)
780 wPrev = wch;
781 wLast = wch;
782 continue;
783 }
784
785 int32_t iCharWidth = iWidth;
786 if (iCharWidth < 0)
787 iCharWidth = -iCharWidth;
788
789 iCharWidth /= iFontSize;
790 std::array<FX_FORMCHAR, 3> form_chars;
791 form_chars[0].wch = wch;
792 form_chars[0].wForm = wForm;
793 form_chars[0].iWidth = iCharWidth;
794 if (bLam) {
795 form_chars[1].wForm = pdfium::kArabicShadda;
796 form_chars[1].iWidth =
797 pFont->GetCharWidth(pdfium::kArabicShadda).value_or(0);
798 form_chars[2].wForm = pdfium::kArabicLetterSuperscriptAlef;
799 form_chars[2].iWidth =
800 pFont->GetCharWidth(pdfium::kArabicLetterSuperscriptAlef).value_or(0);
801 }
802
803 for (int32_t j = 0; j < iForms; j++) {
804 TextCharPos& front_ref = pCharPos.front();
805 wForm = (wchar_t)form_chars[j].wForm;
806 iCharWidth = form_chars[j].iWidth;
807 if (j > 0) {
808 chartype = FX_CHARTYPE::kCombination;
809 wch = wForm;
810 wLast = (wchar_t)form_chars[j - 1].wForm;
811 }
812 if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
813 front_ref.m_GlyphIndex = pFont->GetGlyphIndex(wForm);
814#if BUILDFLAG(IS_APPLE)
815 front_ref.m_ExtGID = front_ref.m_GlyphIndex;
816#endif
817 front_ref.m_FontCharWidth = iCharWidth;
818 }
819
820 const float fCharWidth = fFontSize * iCharWidth / 1000.0f;
821 if (bRTLPiece && chartype != FX_CHARTYPE::kCombination)
822 fX -= fCharWidth;
823
824 if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
825 front_ref.m_Origin = CFX_PointF(fX, fY);
826
827 if (!!(dwStyles & LayoutStyle::kCombText)) {
828 int32_t iFormWidth = pFont->GetCharWidth(wForm).value_or(iCharWidth);
829 float fOffset = fFontSize * (iCharWidth - iFormWidth) / 2000.0f;
830 front_ref.m_Origin.x += fOffset;
831 }
832 if (chartype == FX_CHARTYPE::kCombination) {
833 std::optional<FX_RECT> rtBBox = pFont->GetCharBBox(wForm);
834 if (rtBBox.has_value()) {
835 front_ref.m_Origin.y =
836 fYBase + fFontSize -
837 fFontSize * rtBBox.value().Height() / iMaxHeight;
838 }
839 if (wForm == wch &&
841 if (pdfium::unicode::GetCharType(wLast) ==
842 FX_CHARTYPE::kCombination) {
843 std::optional<FX_RECT> rtOtherBox = pFont->GetCharBBox(wLast);
844 if (rtOtherBox.has_value()) {
845 front_ref.m_Origin.y -=
846 fFontSize * rtOtherBox.value().Height() / iMaxHeight;
847 }
848 }
849 }
850 }
851 }
852 if (!bRTLPiece && chartype != FX_CHARTYPE::kCombination)
853 fX += fCharWidth;
854
855 if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
856 front_ref.m_bGlyphAdjust = true;
857 front_ref.m_AdjustMatrix[0] = -1;
858 front_ref.m_AdjustMatrix[1] = 0;
859 front_ref.m_AdjustMatrix[2] = 0;
860 front_ref.m_AdjustMatrix[3] = 1;
861
862 if (iHorScale != 100 || iVerScale != 100) {
863 front_ref.m_AdjustMatrix[0] =
864 front_ref.m_AdjustMatrix[0] * iHorScale / 100.0f;
865 front_ref.m_AdjustMatrix[1] =
866 front_ref.m_AdjustMatrix[1] * iHorScale / 100.0f;
867 front_ref.m_AdjustMatrix[2] =
868 front_ref.m_AdjustMatrix[2] * iVerScale / 100.0f;
869 front_ref.m_AdjustMatrix[3] =
870 front_ref.m_AdjustMatrix[3] * iVerScale / 100.0f;
871 }
872 pCharPos = pCharPos.subspan(1);
873 }
874 }
875 if (iWidth > 0)
876 wPrev = static_cast<wchar_t>(form_chars[0].wch);
877 wLast = wch;
878 }
879 return szCount;
880}
881
882std::vector<CFX_RectF> CFGAS_TxtBreak::GetCharRects(const Run& run) const {
883 if (run.iLength < 1)
884 return std::vector<CFX_RectF>();
885
886 Engine* pEngine = run.pEdtEngine;
887 WideStringView pStr = run.wsStr.AsStringView();
888 pdfium::span<int32_t> pWidths = run.pWidths;
889 int32_t iLength = run.iLength;
890 CFX_RectF rect(*run.pRect);
891 float fFontSize = run.fFontSize;
892 bool bRTLPiece = !!(run.dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel);
893 bool bSingleLine = !!(run.dwStyles & LayoutStyle::kSingleLine);
894 float fStart = bRTLPiece ? rect.right() : rect.left;
895
896 std::vector<CFX_RectF> rtArray(iLength);
897 for (int32_t i = 0; i < iLength; i++) {
898 wchar_t wch;
899 int32_t iCharSize;
900 if (pEngine) {
901 int32_t iAbsolute = i + run.iStart;
902 wch = pEngine->GetChar(iAbsolute);
903 iCharSize = pEngine->GetWidthOfChar(iAbsolute);
904 } else {
905 wch = pStr.Front();
906 pStr = pStr.Substr(1);
907 iCharSize = pWidths.front();
908 pWidths = pWidths.subspan(1);
909 }
910 float fCharSize = static_cast<float>(iCharSize) / kConversionFactor;
911 bool bRet = (!bSingleLine && IsCtrlCode(wch));
912 if (!(wch == L'\v' || wch == L'\f' ||
914 wch == pdfium::unicode::kParagraphSeparator || wch == L'\n')) {
915 bRet = false;
916 }
917 if (bRet)
918 fCharSize = fFontSize / 2.0f;
919 rect.left = fStart;
920 if (bRTLPiece) {
921 rect.left -= fCharSize;
922 fStart -= fCharSize;
923 } else {
924 fStart += fCharSize;
925 }
926 rect.width = fCharSize;
927 rtArray[i] = rect;
928 }
929 return rtArray;
930}
931
932CFGAS_TxtBreak::Engine::~Engine() = default;
933
934CFGAS_TxtBreak::Run::Run() = default;
935
936CFGAS_TxtBreak::Run::~Run() = default;
937
938CFGAS_TxtBreak::Run::Run(const CFGAS_TxtBreak::Run& other) = default;
#define FX_TXTCHARSTYLE_ArabicShadda
@ CFX_TxtLineAlignment_Justified
@ CFX_TxtLineAlignment_Right
@ CFX_TxtLineAlignment_Center
#define FX_TXTCHARSTYLE_OddBidiLevel
#define DCHECK
Definition check.h:33
void IncrementArabicCharCount()
void DecrementArabicCharCount()
int32_t GetStartChar() const
void SetVerticalScale(int32_t scale)
void SetStatus(CFGAS_Char::BreakType status)
void SetBidiLevel(int32_t level)
void SetStartPos(int32_t pos)
void SetCharCount(int32_t count)
void SetStartChar(int32_t pos)
int32_t GetBidiPos() const
void IncrementWidth(int32_t width)
void IncrementStartPos(int32_t count)
void SetBidiPos(int32_t pos)
void SetHorizontalScale(int32_t scale)
void SetCharStyles(uint32_t styles)
void SetWidth(int32_t width)
int32_t GetWidth() const
bool m_bCombText
Definition cfgas_break.h:78
int32_t m_iHorizontalScale
Definition cfgas_break.h:86
CFGAS_Char * GetLastChar(int32_t index, bool bOmitChar, bool bRichText) const
bool m_bSingleLine
Definition cfgas_break.h:77
int32_t m_iCharSpace
Definition cfgas_break.h:89
wchar_t m_wParagraphBreakChar
Definition cfgas_break.h:83
bool HasLine() const
Definition cfgas_break.h:72
int32_t m_iFontSize
Definition cfgas_break.h:84
bool IsGreaterThanLineWidth(int32_t width) const
static const float kConversionFactor
Definition cfgas_break.h:67
int32_t m_iLineWidth
Definition cfgas_break.h:82
int32_t m_iCharWidth
Definition cfgas_char.h:47
uint16_t m_iBidiOrder
Definition cfgas_char.h:50
uint16_t m_iBidiPos
Definition cfgas_char.h:49
uint32_t m_dwCharStyles
Definition cfgas_char.h:46
BreakType m_dwStatus
Definition cfgas_char.h:43
int16_t vertical_scale() const
Definition cfgas_char.h:41
uint16_t m_iBidiLevel
Definition cfgas_char.h:48
int16_t horizonal_scale() const
Definition cfgas_char.h:40
FX_LINEBREAKTYPE m_eLineBreakType
Definition cfgas_char.h:45
uint16_t char_code() const
Definition cfgas_char.h:39
std::vector< CFX_RectF > GetCharRects(const Run &run) const
CFGAS_Char::BreakType EndBreak(CFGAS_Char::BreakType dwStatus)
~CFGAS_TxtBreak() override
void SetLineWidth(float fLineWidth)
size_t GetDisplayPos(const Run &run, pdfium::span< TextCharPos > pCharPos) const
CFGAS_Char::BreakType AppendChar(wchar_t wch)
void SetAlignment(int32_t iAlignment)
void SetCombWidth(float fCombWidth)
float right() const
uint32_t m_GlyphIndex
bool m_bGlyphAdjust
FX_LINEBREAKTYPE
#define FX_IsOdd(a)
pdfium::CheckedNumeric< int32_t > FX_SAFE_INT32
int FXSYS_roundf(float f)
wchar_t GetMirrorChar(wchar_t wch)
constexpr wchar_t kZeroWidthNoBreakSpace
Definition fx_unicode.h:103
constexpr wchar_t kLineSeparator
Definition fx_unicode.h:100
constexpr wchar_t kParagraphSeparator
Definition fx_unicode.h:101
std::optional< wchar_t > GetArabicFromShaddaTable(wchar_t shadda)
wchar_t GetArabicFormChar(const CFGAS_Char *cur, const CFGAS_Char *prev, const CFGAS_Char *next)
constexpr wchar_t kArabicLetterLam
Definition fgas_arabic.h:16
wchar_t GetArabicFormChar(wchar_t wch, wchar_t prev, wchar_t next)
constexpr wchar_t kArabicShadda
Definition fgas_arabic.h:18
constexpr wchar_t kArabicLetterSuperscriptAlef
Definition fgas_arabic.h:19
constexpr wchar_t kArabicLetterHeh
Definition fgas_arabic.h:17
fxcrt::WideStringView WideStringView
Run(const Run &other)