xref: /aosp_15_r20/external/libchrome/base/i18n/bidi_line_iterator.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1 // Copyright (c) 2011 The Chromium 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 #include "base/i18n/bidi_line_iterator.h"
6 
7 #include "base/logging.h"
8 
9 namespace base {
10 namespace i18n {
11 
12 namespace {
13 
GetParagraphLevelForDirection(TextDirection direction)14 UBiDiLevel GetParagraphLevelForDirection(TextDirection direction) {
15   switch (direction) {
16     case UNKNOWN_DIRECTION:
17       return UBIDI_DEFAULT_LTR;
18       break;
19     case RIGHT_TO_LEFT:
20       return 1;  // Highest RTL level.
21       break;
22     case LEFT_TO_RIGHT:
23       return 0;  // Highest LTR level.
24       break;
25     default:
26       NOTREACHED();
27       return 0;
28   }
29 }
30 
31 // Overrides the default bidi class for a given character, for the custom
32 // "AS_URL" behavior. Returns U_BIDI_CLASS_DEFAULT to defer to the default ICU
33 // behavior.
34 //
35 // Matches the C callback interface of ICU's UBiDiClassCallback type (which is
36 // why there is an unused argument).
GetURLBiDiClassCallback(const void *,UChar32 c)37 UCharDirection GetURLBiDiClassCallback(const void* /*unused*/, UChar32 c) {
38   // Note: Use a switch statement instead of strchr() to avoid iterating over a
39   // string for each character (the switch allows for much better compiler
40   // optimization).
41   switch (c) {
42     // The set of characters that delimit URL components (separating the scheme,
43     // username, password, domain labels, host, path segments, query
44     // names/values and fragment).
45     case '#':
46     case '&':
47     case '.':
48     case '/':
49     case ':':
50     case '=':
51     case '?':
52     case '@':
53       // Treat all of these characters as strong LTR, which effectively
54       // surrounds all of the text components of a URL (e.g., the domain labels
55       // and path segments) in a left-to-right embedding. This ensures that the
56       // URL components read from left to right, regardless of any RTL
57       // characters. (Within each component, RTL sequences are rendered from
58       // right to left as expected.)
59       return U_LEFT_TO_RIGHT;
60     default:
61       return U_BIDI_CLASS_DEFAULT;
62   }
63 }
64 
65 }  // namespace
66 
BiDiLineIterator()67 BiDiLineIterator::BiDiLineIterator() : bidi_(nullptr) {}
68 
~BiDiLineIterator()69 BiDiLineIterator::~BiDiLineIterator() {
70   if (bidi_) {
71     ubidi_close(bidi_);
72     bidi_ = nullptr;
73   }
74 }
75 
Open(const string16 & text,TextDirection direction,CustomBehavior behavior)76 bool BiDiLineIterator::Open(const string16& text,
77                             TextDirection direction,
78                             CustomBehavior behavior) {
79   DCHECK(!bidi_);
80   UErrorCode error = U_ZERO_ERROR;
81   bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
82   if (U_FAILURE(error))
83     return false;
84 
85   if (behavior == CustomBehavior::AS_URL) {
86     ubidi_setClassCallback(bidi_, GetURLBiDiClassCallback, nullptr, nullptr,
87                            nullptr, &error);
88     if (U_FAILURE(error))
89       return false;
90   }
91 
92   ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
93                 GetParagraphLevelForDirection(direction), nullptr, &error);
94   return (U_SUCCESS(error));
95 }
96 
CountRuns() const97 int BiDiLineIterator::CountRuns() const {
98   DCHECK(bidi_ != nullptr);
99   UErrorCode error = U_ZERO_ERROR;
100   const int runs = ubidi_countRuns(bidi_, &error);
101   return U_SUCCESS(error) ? runs : 0;
102 }
103 
GetVisualRun(int index,int * start,int * length) const104 UBiDiDirection BiDiLineIterator::GetVisualRun(int index,
105                                               int* start,
106                                               int* length) const {
107   DCHECK(bidi_ != nullptr);
108   return ubidi_getVisualRun(bidi_, index, start, length);
109 }
110 
GetLogicalRun(int start,int * end,UBiDiLevel * level) const111 void BiDiLineIterator::GetLogicalRun(int start,
112                                      int* end,
113                                      UBiDiLevel* level) const {
114   DCHECK(bidi_ != nullptr);
115   ubidi_getLogicalRun(bidi_, start, end, level);
116 }
117 
118 }  // namespace i18n
119 }  // namespace base
120