blob: d94b05fa23be3fb59e74a204cfc06b71ee1d23f4 [file] [log] [blame]
// Copyright 2017 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 "xfa/fgas/layout/cfgas_char.h"
#include <algorithm>
#include "core/fxcrt/fx_extension.h"
#include "third_party/base/check.h"
#include "third_party/base/stl_util.h"
namespace {
#if DCHECK_IS_ON()
constexpr int32_t kBidiMaxLevel = 61;
#endif
#undef PACK_NIBBLES
#define PACK_NIBBLES(hi, lo) \
((static_cast<uint32_t>(hi) << 4) + static_cast<uint32_t>(lo))
enum FX_BIDIWEAKSTATE : uint8_t {
FX_BWSxa = 0,
FX_BWSxr,
FX_BWSxl,
FX_BWSao,
FX_BWSro,
FX_BWSlo,
FX_BWSrt,
FX_BWSlt,
FX_BWScn,
FX_BWSra,
FX_BWSre,
FX_BWSla,
FX_BWSle,
FX_BWSac,
FX_BWSrc,
FX_BWSrs,
FX_BWSlc,
FX_BWSls,
FX_BWSret,
FX_BWSlet
};
// NOTE: Range of FX_BIDICLASS prevents encoding all possible values in this
// manner, but the ones used manage to fit. Except that I suspect that 0xF
// was intended to be used as a sentinel, even though it also means kRLE.
// TODO(tsepez): pick a better representation.
enum FX_BIDIWEAKACTION : uint16_t {
FX_BWAIX = 0x100,
FX_BWAXX = 0x0F,
FX_BWAxxx = 0xFF,
FX_BWAxIx = 0x100 + FX_BWAxxx,
FX_BWAxxN = PACK_NIBBLES(0x0F, FX_BIDICLASS::kON),
FX_BWAxxE = PACK_NIBBLES(0x0F, FX_BIDICLASS::kEN),
FX_BWAxxA = PACK_NIBBLES(0x0F, FX_BIDICLASS::kAN),
FX_BWAxxR = PACK_NIBBLES(0x0F, FX_BIDICLASS::kR),
FX_BWAxxL = PACK_NIBBLES(0x0F, FX_BIDICLASS::kL),
FX_BWANxx = PACK_NIBBLES(FX_BIDICLASS::kON, 0x0F),
FX_BWAAxx = PACK_NIBBLES(FX_BIDICLASS::kAN, 0x0F),
FX_BWAExE = PACK_NIBBLES(FX_BIDICLASS::kEN, FX_BIDICLASS::kEN),
FX_BWANIx = 0x100 + PACK_NIBBLES(FX_BIDICLASS::kON, 0x0F),
FX_BWANxN = PACK_NIBBLES(FX_BIDICLASS::kON, FX_BIDICLASS::kON),
FX_BWANxR = PACK_NIBBLES(FX_BIDICLASS::kON, FX_BIDICLASS::kR),
FX_BWANxE = PACK_NIBBLES(FX_BIDICLASS::kON, FX_BIDICLASS::kEN),
FX_BWAAxA = PACK_NIBBLES(FX_BIDICLASS::kAN, FX_BIDICLASS::kAN),
FX_BWANxL = PACK_NIBBLES(FX_BIDICLASS::kON, FX_BIDICLASS::kL),
FX_BWALxL = PACK_NIBBLES(FX_BIDICLASS::kL, FX_BIDICLASS::kL),
FX_BWAxIL = 0x100 + PACK_NIBBLES(0x0F, FX_BIDICLASS::kL),
FX_BWAAxR = PACK_NIBBLES(FX_BIDICLASS::kAN, FX_BIDICLASS::kR),
FX_BWALxx = PACK_NIBBLES(FX_BIDICLASS::kL, 0x0F),
};
enum FX_BIDINEUTRALSTATE : uint8_t {
FX_BNSr = 0,
FX_BNSl,
FX_BNSrn,
FX_BNSln,
FX_BNSa,
FX_BNSna
};
enum FX_BIDINEUTRALACTION : uint16_t {
// For placeholders in table.
FX_BNAZero = 0,
// Other values.
FX_BNAnL = PACK_NIBBLES(0, FX_BIDICLASS::kL),
FX_BNAEn = PACK_NIBBLES(FX_BIDICLASS::kAN, 0),
FX_BNARn = PACK_NIBBLES(FX_BIDICLASS::kR, 0),
FX_BNALn = PACK_NIBBLES(FX_BIDICLASS::kL, 0),
FX_BNAIn = FX_BWAIX,
FX_BNALnL = PACK_NIBBLES(FX_BIDICLASS::kL, FX_BIDICLASS::kL),
};
#undef PACK_NIBBLES
const FX_BIDICLASS kNTypes[] = {
FX_BIDICLASS::kN, FX_BIDICLASS::kL, FX_BIDICLASS::kR,
FX_BIDICLASS::kAN, FX_BIDICLASS::kEN, FX_BIDICLASS::kAL,
FX_BIDICLASS::kNSM, FX_BIDICLASS::kCS, FX_BIDICLASS::kES,
FX_BIDICLASS::kET, FX_BIDICLASS::kBN, FX_BIDICLASS::kBN,
FX_BIDICLASS::kN, FX_BIDICLASS::kB, FX_BIDICLASS::kRLO,
FX_BIDICLASS::kRLE, FX_BIDICLASS::kLRO, FX_BIDICLASS::kLRE,
FX_BIDICLASS::kPDF, FX_BIDICLASS::kON,
};
const FX_BIDIWEAKSTATE kWeakStates[20][10] = {
{FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSxa,
FX_BWSao, FX_BWSao, FX_BWSao},
{FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSxr,
FX_BWSro, FX_BWSro, FX_BWSrt},
{FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSxl,
FX_BWSlo, FX_BWSlo, FX_BWSlt},
{FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSao,
FX_BWSao, FX_BWSao, FX_BWSao},
{FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro,
FX_BWSro, FX_BWSro, FX_BWSrt},
{FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo,
FX_BWSlo, FX_BWSlo, FX_BWSlt},
{FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSrt,
FX_BWSro, FX_BWSro, FX_BWSrt},
{FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlt,
FX_BWSlo, FX_BWSlo, FX_BWSlt},
{FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWScn,
FX_BWSac, FX_BWSao, FX_BWSao},
{FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSra,
FX_BWSrc, FX_BWSro, FX_BWSrt},
{FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSre,
FX_BWSrs, FX_BWSrs, FX_BWSret},
{FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSla,
FX_BWSlc, FX_BWSlo, FX_BWSlt},
{FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSle,
FX_BWSls, FX_BWSls, FX_BWSlet},
{FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSao,
FX_BWSao, FX_BWSao, FX_BWSao},
{FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro,
FX_BWSro, FX_BWSro, FX_BWSrt},
{FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro,
FX_BWSro, FX_BWSro, FX_BWSrt},
{FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo,
FX_BWSlo, FX_BWSlo, FX_BWSlt},
{FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo,
FX_BWSlo, FX_BWSlo, FX_BWSlt},
{FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSret,
FX_BWSro, FX_BWSro, FX_BWSret},
{FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlet,
FX_BWSlo, FX_BWSlo, FX_BWSlet},
};
const FX_BIDIWEAKACTION kWeakActions[20][10] = {
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR,
FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR,
FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
{FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR,
FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx},
{FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR,
FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR,
FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxxN},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
FX_BWAxxE, FX_BWAxIx, FX_BWAxIx, FX_BWAxxE},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
FX_BWAxxL, FX_BWAxIx, FX_BWAxIx, FX_BWAxxL},
{FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWAAxA, FX_BWANxR,
FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANxN},
{FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxE, FX_BWANxR,
FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
{FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR,
FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
{FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxL, FX_BWANxR,
FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
{FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR,
FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
FX_BWAxxE, FX_BWAxxN, FX_BWAxxN, FX_BWAxxE},
{FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxxL},
};
const FX_BIDINEUTRALSTATE kNeutralStates[6][5] = {
{FX_BNSrn, FX_BNSl, FX_BNSr, FX_BNSr, FX_BNSr},
{FX_BNSln, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
{FX_BNSrn, FX_BNSl, FX_BNSr, FX_BNSr, FX_BNSr},
{FX_BNSln, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
{FX_BNSna, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
{FX_BNSna, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
};
const FX_BIDINEUTRALACTION kNeutralActions[6][5] = {
{FX_BNAIn, FX_BNAZero, FX_BNAZero, FX_BNAZero, FX_BNAZero},
{FX_BNAIn, FX_BNAZero, FX_BNAZero, FX_BNAZero, FX_BNAnL},
{FX_BNAIn, FX_BNAEn, FX_BNARn, FX_BNARn, FX_BNARn},
{FX_BNAIn, FX_BNALn, FX_BNAEn, FX_BNAEn, FX_BNALnL},
{FX_BNAIn, FX_BNAZero, FX_BNAZero, FX_BNAZero, FX_BNAnL},
{FX_BNAIn, FX_BNAEn, FX_BNARn, FX_BNARn, FX_BNAEn},
};
const uint8_t kAddLevel[2][4] = {
{0, 1, 2, 2},
{1, 0, 1, 1},
};
FX_BIDICLASS Direction(int32_t val) {
return FX_IsOdd(val) ? FX_BIDICLASS::kR : FX_BIDICLASS::kL;
}
FX_BIDICLASS GetDeferredType(int32_t val) {
return static_cast<FX_BIDICLASS>((val >> 4) & 0x0F);
}
FX_BIDICLASS GetResolvedType(int32_t val) {
return static_cast<FX_BIDICLASS>(val & 0x0F);
}
FX_BIDICLASS GetDeferredNeutrals(int32_t iAction, int32_t iLevel) {
FX_BIDICLASS eClass = GetDeferredType(iAction);
return eClass == FX_BIDICLASS::kAN ? Direction(iLevel) : eClass;
}
FX_BIDICLASS GetResolvedNeutrals(int32_t iAction) {
return GetResolvedType(iAction);
}
FX_BIDIWEAKSTATE GetWeakState(FX_BIDIWEAKSTATE eState, FX_BIDICLASS eClass) {
DCHECK(static_cast<size_t>(eState) < pdfium::size(kWeakStates));
DCHECK(static_cast<size_t>(eClass) < pdfium::size(kWeakStates[0]));
return kWeakStates[static_cast<size_t>(eState)][static_cast<size_t>(eClass)];
}
FX_BIDIWEAKACTION GetWeakAction(FX_BIDIWEAKSTATE eState, FX_BIDICLASS eClass) {
DCHECK(static_cast<size_t>(eState) < pdfium::size(kWeakActions));
DCHECK(static_cast<size_t>(eClass) < pdfium::size(kWeakActions[0]));
return kWeakActions[static_cast<size_t>(eState)][static_cast<size_t>(eClass)];
}
FX_BIDINEUTRALSTATE GetNeutralState(FX_BIDINEUTRALSTATE eState,
FX_BIDICLASS eClass) {
DCHECK(static_cast<size_t>(eState) < pdfium::size(kNeutralStates));
DCHECK(static_cast<size_t>(eClass) < pdfium::size(kNeutralStates[0]));
return kNeutralStates[static_cast<size_t>(eState)]
[static_cast<size_t>(eClass)];
}
FX_BIDINEUTRALACTION GetNeutralAction(FX_BIDINEUTRALSTATE eState,
FX_BIDICLASS eClass) {
DCHECK(static_cast<size_t>(eState) < pdfium::size(kNeutralActions));
DCHECK(static_cast<size_t>(eClass) < pdfium::size(kNeutralActions[0]));
return kNeutralActions[static_cast<size_t>(eState)]
[static_cast<size_t>(eClass)];
}
void ReverseString(std::vector<CFGAS_Char>* chars,
size_t iStart,
size_t iCount) {
DCHECK(pdfium::IndexInBounds(*chars, iStart));
DCHECK(iStart + iCount <= chars->size());
std::reverse(chars->begin() + iStart, chars->begin() + iStart + iCount);
}
void SetDeferredRunClass(std::vector<CFGAS_Char>* chars,
size_t iStart,
size_t iCount,
FX_BIDICLASS eValue) {
DCHECK(iStart <= chars->size());
DCHECK(iStart >= iCount);
size_t iLast = iStart - iCount;
for (size_t i = iStart; i > iLast; --i)
(*chars)[i - 1].m_iBidiClass = eValue;
}
void SetDeferredRunLevel(std::vector<CFGAS_Char>* chars,
size_t iStart,
size_t iCount,
int32_t iValue) {
DCHECK(iStart <= chars->size());
DCHECK(iStart >= iCount);
size_t iLast = iStart - iCount;
for (size_t i = iStart; i > iLast; --i)
(*chars)[i - 1].m_iBidiLevel = static_cast<int16_t>(iValue);
}
void Classify(std::vector<CFGAS_Char>* chars, size_t iCount) {
for (size_t i = 0; i < iCount; ++i) {
CFGAS_Char& cur = (*chars)[i];
cur.m_iBidiClass = FX_GetBidiClass(cur.char_code());
}
}
void ClassifyWithTransform(std::vector<CFGAS_Char>* chars, size_t iCount) {
for (size_t i = 0; i < iCount; ++i) {
CFGAS_Char& cur = (*chars)[i];
cur.m_iBidiClass =
kNTypes[static_cast<size_t>(FX_GetBidiClass(cur.char_code()))];
}
}
void ResolveExplicit(std::vector<CFGAS_Char>* chars, size_t iCount) {
for (size_t i = 0; i < iCount; ++i)
(*chars)[i].m_iBidiLevel = 0;
}
void ResolveWeak(std::vector<CFGAS_Char>* chars, size_t iCount) {
if (iCount <= 1)
return;
--iCount;
int32_t iLevelCur = 0;
size_t iNum = 0;
FX_BIDIWEAKSTATE eState = FX_BWSxl;
FX_BIDICLASS eClsCur;
FX_BIDICLASS eClsRun;
FX_BIDICLASS eClsNew;
size_t i = 0;
for (; i <= iCount; ++i) {
CFGAS_Char* pTC = &(*chars)[i];
eClsCur = pTC->m_iBidiClass;
if (eClsCur == FX_BIDICLASS::kBN) {
pTC->m_iBidiLevel = (int16_t)iLevelCur;
if (i == iCount && iLevelCur != 0) {
eClsCur = Direction(iLevelCur);
pTC->m_iBidiClass = eClsCur;
} else if (i < iCount) {
CFGAS_Char* pTCNext = &(*chars)[i + 1];
eClsNew = pTCNext->m_iBidiClass;
int32_t iLevelNext = pTCNext->m_iBidiLevel;
if (eClsNew != FX_BIDICLASS::kBN && iLevelCur != iLevelNext) {
int32_t iLevelNew = std::max(iLevelNext, iLevelCur);
pTC->m_iBidiLevel = static_cast<int16_t>(iLevelNew);
eClsCur = Direction(iLevelNew);
pTC->m_iBidiClass = eClsCur;
iLevelCur = iLevelNext;
} else {
if (iNum > 0)
++iNum;
continue;
}
} else {
if (iNum > 0)
++iNum;
continue;
}
}
if (eClsCur > FX_BIDICLASS::kBN)
continue;
FX_BIDIWEAKACTION eAction = GetWeakAction(eState, eClsCur);
eClsRun = GetDeferredType(eAction);
if (eClsRun != static_cast<FX_BIDICLASS>(0xF) && iNum > 0) {
SetDeferredRunClass(chars, i, iNum, eClsRun);
iNum = 0;
}
eClsNew = GetResolvedType(eAction);
if (eClsNew != static_cast<FX_BIDICLASS>(0xF))
pTC->m_iBidiClass = eClsNew;
if (FX_BWAIX & eAction)
++iNum;
eState = GetWeakState(eState, eClsCur);
}
if (iNum == 0)
return;
eClsCur = Direction(0);
eClsRun = GetDeferredType(GetWeakAction(eState, eClsCur));
if (eClsRun != static_cast<FX_BIDICLASS>(0xF))
SetDeferredRunClass(chars, i, iNum, eClsRun);
}
void ResolveNeutrals(std::vector<CFGAS_Char>* chars, size_t iCount) {
if (iCount <= 1)
return;
--iCount;
CFGAS_Char* pTC;
int32_t iLevel = 0;
size_t i = 0;
size_t iNum = 0;
FX_BIDINEUTRALSTATE eState = FX_BNSl;
FX_BIDICLASS eClsCur;
FX_BIDICLASS eClsRun;
FX_BIDICLASS eClsNew;
for (; i <= iCount; ++i) {
pTC = &(*chars)[i];
eClsCur = pTC->m_iBidiClass;
if (eClsCur == FX_BIDICLASS::kBN) {
if (iNum)
++iNum;
continue;
}
if (eClsCur >= FX_BIDICLASS::kAL)
continue;
FX_BIDINEUTRALACTION eAction = GetNeutralAction(eState, eClsCur);
eClsRun = GetDeferredNeutrals(eAction, iLevel);
if (eClsRun != FX_BIDICLASS::kN && iNum > 0) {
SetDeferredRunClass(chars, i, iNum, eClsRun);
iNum = 0;
}
eClsNew = GetResolvedNeutrals(eAction);
if (eClsNew != FX_BIDICLASS::kN)
pTC->m_iBidiClass = eClsNew;
if (FX_BNAIn & eAction)
++iNum;
eState = GetNeutralState(eState, eClsCur);
iLevel = pTC->m_iBidiLevel;
}
if (iNum == 0)
return;
eClsCur = Direction(iLevel);
eClsRun = GetDeferredNeutrals(GetNeutralAction(eState, eClsCur), iLevel);
if (eClsRun != FX_BIDICLASS::kN)
SetDeferredRunClass(chars, i, iNum, eClsRun);
}
void ResolveImplicit(std::vector<CFGAS_Char>* chars, size_t iCount) {
for (size_t i = 0; i < iCount; ++i) {
FX_BIDICLASS eCls = (*chars)[i].m_iBidiClass;
if (eCls == FX_BIDICLASS::kBN || eCls <= FX_BIDICLASS::kON ||
eCls >= FX_BIDICLASS::kAL) {
continue;
}
(*chars)[i].m_iBidiLevel += kAddLevel[FX_IsOdd((*chars)[i].m_iBidiLevel)]
[static_cast<size_t>(eCls) - 1];
}
}
void ResolveWhitespace(std::vector<CFGAS_Char>* chars, size_t iCount) {
if (iCount <= 1)
return;
iCount--;
int32_t iLevel = 0;
size_t i = 0;
size_t iNum = 0;
for (; i <= iCount; ++i) {
switch (static_cast<FX_BIDICLASS>((*chars)[i].m_iBidiClass)) {
case FX_BIDICLASS::kWS:
++iNum;
break;
case FX_BIDICLASS::kRLE:
case FX_BIDICLASS::kLRE:
case FX_BIDICLASS::kLRO:
case FX_BIDICLASS::kRLO:
case FX_BIDICLASS::kPDF:
case FX_BIDICLASS::kBN:
(*chars)[i].m_iBidiLevel = static_cast<int16_t>(iLevel);
++iNum;
break;
case FX_BIDICLASS::kS:
case FX_BIDICLASS::kB:
if (iNum > 0)
SetDeferredRunLevel(chars, i, iNum, 0);
(*chars)[i].m_iBidiLevel = 0;
iNum = 0;
break;
default:
iNum = 0;
break;
}
iLevel = (*chars)[i].m_iBidiLevel;
}
if (iNum > 0)
SetDeferredRunLevel(chars, i, iNum, 0);
}
size_t ReorderLevel(std::vector<CFGAS_Char>* chars,
size_t iCount,
int32_t iBaseLevel,
size_t iStart,
bool bReverse) {
DCHECK(iBaseLevel >= 0);
DCHECK(iBaseLevel <= kBidiMaxLevel);
DCHECK(iStart < iCount);
if (iCount < 1)
return 0;
bReverse = bReverse || FX_IsOdd(iBaseLevel);
size_t i = iStart;
for (; i < iCount; ++i) {
int32_t iLevel = (*chars)[i].m_iBidiLevel;
if (iLevel == iBaseLevel)
continue;
if (iLevel < iBaseLevel)
break;
i += ReorderLevel(chars, iCount, iBaseLevel + 1, i, bReverse) - 1;
}
size_t iNum = i - iStart;
if (bReverse && iNum > 1)
ReverseString(chars, iStart, iNum);
return iNum;
}
void Reorder(std::vector<CFGAS_Char>* chars, size_t iCount) {
for (size_t i = 0; i < iCount;)
i += ReorderLevel(chars, iCount, 0, i, false);
}
void Position(std::vector<CFGAS_Char>* chars, size_t iCount) {
for (size_t i = 0; i < iCount; ++i) {
if ((*chars)[i].m_iBidiPos > iCount)
continue;
(*chars)[(*chars)[i].m_iBidiPos].m_iBidiOrder = i;
}
}
} // namespace
// static
void CFGAS_Char::BidiLine(std::vector<CFGAS_Char>* chars, size_t iCount) {
DCHECK(iCount <= chars->size());
if (iCount < 2)
return;
ClassifyWithTransform(chars, iCount);
ResolveExplicit(chars, iCount);
ResolveWeak(chars, iCount);
ResolveNeutrals(chars, iCount);
ResolveImplicit(chars, iCount);
Classify(chars, iCount);
ResolveWhitespace(chars, iCount);
Reorder(chars, iCount);
Position(chars, iCount);
}
CFGAS_Char::CFGAS_Char(uint16_t wCharCode) : CFGAS_Char(wCharCode, 100, 100) {}
CFGAS_Char::CFGAS_Char(uint16_t wCharCode,
int32_t iHorizontalScale,
int32_t iVerticalScale)
: m_wCharCode(wCharCode),
m_iHorizontalScale(iHorizontalScale),
m_iVerticalScale(iVerticalScale) {}
CFGAS_Char::CFGAS_Char(const CFGAS_Char& other) = default;
CFGAS_Char::~CFGAS_Char() = default;
FX_CHARTYPE CFGAS_Char::GetCharType() const {
return FX_GetCharType(m_wCharCode);
}