1 // Copyright 2014 PDFium Authors. All rights reserved.
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 "core/fxcrt/fx_bidi.h"
8 
9 #include <algorithm>
10 
11 #include "core/fxcrt/fx_unicode.h"
12 #include "third_party/base/stl_util.h"
13 
CFX_BidiChar()14 CFX_BidiChar::CFX_BidiChar()
15     : m_CurrentSegment({0, 0, NEUTRAL}), m_LastSegment({0, 0, NEUTRAL}) {}
16 
AppendChar(wchar_t wch)17 bool CFX_BidiChar::AppendChar(wchar_t wch) {
18   Direction direction;
19   switch (FX_GetBidiClass(wch)) {
20     case FX_BIDICLASS::kL:
21     case FX_BIDICLASS::kAN:
22     case FX_BIDICLASS::kEN:
23       direction = LEFT;
24       break;
25     case FX_BIDICLASS::kR:
26     case FX_BIDICLASS::kAL:
27       direction = RIGHT;
28       break;
29     default:
30       direction = NEUTRAL;
31       break;
32   }
33 
34   bool bChangeDirection = (direction != m_CurrentSegment.direction);
35   if (bChangeDirection)
36     StartNewSegment(direction);
37 
38   m_CurrentSegment.count++;
39   return bChangeDirection;
40 }
41 
EndChar()42 bool CFX_BidiChar::EndChar() {
43   StartNewSegment(NEUTRAL);
44   return m_LastSegment.count > 0;
45 }
46 
StartNewSegment(CFX_BidiChar::Direction direction)47 void CFX_BidiChar::StartNewSegment(CFX_BidiChar::Direction direction) {
48   m_LastSegment = m_CurrentSegment;
49   m_CurrentSegment.start += m_CurrentSegment.count;
50   m_CurrentSegment.count = 0;
51   m_CurrentSegment.direction = direction;
52 }
53 
CFX_BidiString(const WideString & str)54 CFX_BidiString::CFX_BidiString(const WideString& str) : m_Str(str) {
55   CFX_BidiChar bidi;
56   for (wchar_t c : m_Str) {
57     if (bidi.AppendChar(c))
58       m_Order.push_back(bidi.GetSegmentInfo());
59   }
60   if (bidi.EndChar())
61     m_Order.push_back(bidi.GetSegmentInfo());
62 
63   size_t nR2L = std::count_if(m_Order.begin(), m_Order.end(),
64                               [](const CFX_BidiChar::Segment& seg) {
65                                 return seg.direction == CFX_BidiChar::RIGHT;
66                               });
67 
68   size_t nL2R = std::count_if(m_Order.begin(), m_Order.end(),
69                               [](const CFX_BidiChar::Segment& seg) {
70                                 return seg.direction == CFX_BidiChar::LEFT;
71                               });
72 
73   if (nR2L > 0 && nR2L >= nL2R)
74     SetOverallDirectionRight();
75 }
76 
~CFX_BidiString()77 CFX_BidiString::~CFX_BidiString() {}
78 
OverallDirection() const79 CFX_BidiChar::Direction CFX_BidiString::OverallDirection() const {
80   ASSERT(m_eOverallDirection != CFX_BidiChar::NEUTRAL);
81   return m_eOverallDirection;
82 }
83 
SetOverallDirectionRight()84 void CFX_BidiString::SetOverallDirectionRight() {
85   if (m_eOverallDirection != CFX_BidiChar::RIGHT) {
86     std::reverse(m_Order.begin(), m_Order.end());
87     m_eOverallDirection = CFX_BidiChar::RIGHT;
88   }
89 }
90