Bug 1746711 Part 2: Ensure the enqueued surface has a color space. r=gfx-reviewers...
[gecko.git] / intl / components / src / Bidi.cpp
blob2ce355c8ebd8b1619ed6628190557ecfb6b59b7c
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/intl/Bidi.h"
6 #include "mozilla/Casting.h"
7 #include "mozilla/intl/ICU4CGlue.h"
9 #include "unicode/ubidi.h"
11 namespace mozilla::intl {
13 Bidi::Bidi() { mBidi = ubidi_open(); }
14 Bidi::~Bidi() { ubidi_close(mBidi.GetMut()); }
16 ICUResult Bidi::SetParagraph(Span<const char16_t> aParagraph,
17 BidiEmbeddingLevel aLevel) {
18 // Do not allow any reordering of the runs, as this can change the
19 // performance characteristics of working with runs. In the default mode,
20 // the levels can be iterated over directly, rather than relying on computing
21 // logical runs on the fly. This can have negative performance characteristics
22 // compared to iterating over the levels.
24 // In the UBIDI_REORDER_RUNS_ONLY the levels are encoded with additional
25 // information which can be safely ignored in this Bidi implementation.
26 // Note that this check is here since setting the mode must be done before
27 // calls to setting the paragraph.
28 MOZ_ASSERT(ubidi_getReorderingMode(mBidi.GetMut()) == UBIDI_REORDER_DEFAULT);
30 UErrorCode status = U_ZERO_ERROR;
31 ubidi_setPara(mBidi.GetMut(), aParagraph.Elements(),
32 AssertedCast<int32_t>(aParagraph.Length()), aLevel, nullptr,
33 &status);
35 mLevels = nullptr;
37 return ToICUResult(status);
40 Bidi::ParagraphDirection Bidi::GetParagraphDirection() const {
41 switch (ubidi_getDirection(mBidi.GetConst())) {
42 case UBIDI_LTR:
43 return Bidi::ParagraphDirection::LTR;
44 case UBIDI_RTL:
45 return Bidi::ParagraphDirection::RTL;
46 case UBIDI_MIXED:
47 return Bidi::ParagraphDirection::Mixed;
48 case UBIDI_NEUTRAL:
49 // This is only used in `ubidi_getBaseDirection` which is unused in this
50 // API.
51 MOZ_ASSERT_UNREACHABLE("Unexpected UBiDiDirection value.");
53 return Bidi::ParagraphDirection::Mixed;
56 /* static */
57 void Bidi::ReorderVisual(const BidiEmbeddingLevel* aLevels, int32_t aLength,
58 int32_t* aIndexMap) {
59 ubidi_reorderVisual(reinterpret_cast<const uint8_t*>(aLevels), aLength,
60 aIndexMap);
63 /* static */
64 Bidi::BaseDirection Bidi::GetBaseDirection(Span<const char16_t> aParagraph) {
65 UBiDiDirection direction = ubidi_getBaseDirection(
66 aParagraph.Elements(), AssertedCast<int32_t>(aParagraph.Length()));
68 switch (direction) {
69 case UBIDI_LTR:
70 return Bidi::BaseDirection::LTR;
71 case UBIDI_RTL:
72 return Bidi::BaseDirection::RTL;
73 case UBIDI_NEUTRAL:
74 return Bidi::BaseDirection::Neutral;
75 case UBIDI_MIXED:
76 MOZ_ASSERT_UNREACHABLE("Unexpected UBiDiDirection value.");
79 return Bidi::BaseDirection::Neutral;
82 static BidiDirection ToBidiDirection(UBiDiDirection aDirection) {
83 switch (aDirection) {
84 case UBIDI_LTR:
85 return BidiDirection::LTR;
86 case UBIDI_RTL:
87 return BidiDirection::RTL;
88 case UBIDI_MIXED:
89 case UBIDI_NEUTRAL:
90 MOZ_ASSERT_UNREACHABLE("Unexpected UBiDiDirection value.");
92 return BidiDirection::LTR;
95 Result<int32_t, ICUError> Bidi::CountRuns() {
96 UErrorCode status = U_ZERO_ERROR;
97 int32_t runCount = ubidi_countRuns(mBidi.GetMut(), &status);
98 if (U_FAILURE(status)) {
99 return Err(ToICUError(status));
102 mLength = ubidi_getProcessedLength(mBidi.GetConst());
103 mLevels = mLength > 0 ? reinterpret_cast<const BidiEmbeddingLevel*>(
104 ubidi_getLevels(mBidi.GetMut(), &status))
105 : nullptr;
106 if (U_FAILURE(status)) {
107 return Err(ToICUError(status));
110 return runCount;
113 void Bidi::GetLogicalRun(int32_t aLogicalStart, int32_t* aLogicalLimitOut,
114 BidiEmbeddingLevel* aLevelOut) {
115 MOZ_ASSERT(mLevels, "CountRuns hasn't been run?");
116 MOZ_RELEASE_ASSERT(aLogicalStart < mLength, "Out of bound");
117 BidiEmbeddingLevel level = mLevels[aLogicalStart];
118 int32_t limit;
119 for (limit = aLogicalStart + 1; limit < mLength; limit++) {
120 if (mLevels[limit] != level) {
121 break;
124 *aLogicalLimitOut = limit;
125 *aLevelOut = level;
128 BidiEmbeddingLevel Bidi::GetParagraphEmbeddingLevel() const {
129 return BidiEmbeddingLevel(ubidi_getParaLevel(mBidi.GetConst()));
132 BidiDirection Bidi::GetVisualRun(int32_t aRunIndex, int32_t* aLogicalStart,
133 int32_t* aLength) {
134 return ToBidiDirection(
135 ubidi_getVisualRun(mBidi.GetMut(), aRunIndex, aLogicalStart, aLength));
138 } // namespace mozilla::intl