| // Copyright 2014 PDFium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| #include "core/fxcrt/fx_bidi.h" | |
| #include <algorithm> | |
| #include "core/fxcrt/fx_ucd.h" | |
| #include "third_party/base/ptr_util.h" | |
| CFX_BidiChar::CFX_BidiChar() | |
| : m_CurrentSegment({0, 0, NEUTRAL}), m_LastSegment({0, 0, NEUTRAL}) {} | |
| bool CFX_BidiChar::AppendChar(wchar_t wch) { | |
| uint32_t dwProps = FX_GetUnicodeProperties(wch); | |
| int32_t iBidiCls = (dwProps & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS; | |
| Direction direction = NEUTRAL; | |
| switch (iBidiCls) { | |
| case FX_BIDICLASS_L: | |
| case FX_BIDICLASS_AN: | |
| case FX_BIDICLASS_EN: | |
| direction = LEFT; | |
| break; | |
| case FX_BIDICLASS_R: | |
| case FX_BIDICLASS_AL: | |
| direction = RIGHT; | |
| break; | |
| } | |
| bool bChangeDirection = (direction != m_CurrentSegment.direction); | |
| if (bChangeDirection) | |
| StartNewSegment(direction); | |
| m_CurrentSegment.count++; | |
| return bChangeDirection; | |
| } | |
| bool CFX_BidiChar::EndChar() { | |
| StartNewSegment(NEUTRAL); | |
| return m_LastSegment.count > 0; | |
| } | |
| void CFX_BidiChar::StartNewSegment(CFX_BidiChar::Direction direction) { | |
| m_LastSegment = m_CurrentSegment; | |
| m_CurrentSegment.start += m_CurrentSegment.count; | |
| m_CurrentSegment.count = 0; | |
| m_CurrentSegment.direction = direction; | |
| } | |
| CFX_BidiString::CFX_BidiString(const CFX_WideString& str) | |
| : m_Str(str), | |
| m_pBidiChar(pdfium::MakeUnique<CFX_BidiChar>()), | |
| m_eOverallDirection(CFX_BidiChar::LEFT) { | |
| for (const auto& c : m_Str) { | |
| if (m_pBidiChar->AppendChar(c)) | |
| m_Order.push_back(m_pBidiChar->GetSegmentInfo()); | |
| } | |
| if (m_pBidiChar->EndChar()) | |
| m_Order.push_back(m_pBidiChar->GetSegmentInfo()); | |
| size_t nR2L = std::count_if(m_Order.begin(), m_Order.end(), | |
| [](const CFX_BidiChar::Segment& seg) { | |
| return seg.direction == CFX_BidiChar::RIGHT; | |
| }); | |
| size_t nL2R = std::count_if(m_Order.begin(), m_Order.end(), | |
| [](const CFX_BidiChar::Segment& seg) { | |
| return seg.direction == CFX_BidiChar::LEFT; | |
| }); | |
| if (nR2L > 0 && nR2L >= nL2R) | |
| SetOverallDirectionRight(); | |
| } | |
| CFX_BidiString::~CFX_BidiString() {} | |
| void CFX_BidiString::SetOverallDirectionRight() { | |
| if (m_eOverallDirection != CFX_BidiChar::RIGHT) { | |
| std::reverse(m_Order.begin(), m_Order.end()); | |
| m_eOverallDirection = CFX_BidiChar::RIGHT; | |
| } | |
| } |