| // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/i18n/bidi_line_iterator.h" | 
 |  | 
 | #include "base/logging.h" | 
 |  | 
 | namespace base { | 
 | namespace i18n { | 
 |  | 
 | namespace { | 
 |  | 
 | UBiDiLevel GetParagraphLevelForDirection(TextDirection direction) { | 
 |   switch (direction) { | 
 |     case UNKNOWN_DIRECTION: | 
 |       return UBIDI_DEFAULT_LTR; | 
 |       break; | 
 |     case RIGHT_TO_LEFT: | 
 |       return 1;  // Highest RTL level. | 
 |       break; | 
 |     case LEFT_TO_RIGHT: | 
 |       return 0;  // Highest LTR level. | 
 |       break; | 
 |     default: | 
 |       NOTREACHED(); | 
 |       return 0; | 
 |   } | 
 | } | 
 |  | 
 | // Overrides the default bidi class for a given character, for the custom | 
 | // "AS_URL" behavior. Returns U_BIDI_CLASS_DEFAULT to defer to the default ICU | 
 | // behavior. | 
 | // | 
 | // Matches the C callback interface of ICU's UBiDiClassCallback type (which is | 
 | // why there is an unused argument). | 
 | UCharDirection GetURLBiDiClassCallback(const void* /*unused*/, UChar32 c) { | 
 |   // Note: Use a switch statement instead of strchr() to avoid iterating over a | 
 |   // string for each character (the switch allows for much better compiler | 
 |   // optimization). | 
 |   switch (c) { | 
 |     // The set of characters that delimit URL components (separating the scheme, | 
 |     // username, password, domain labels, host, path segments, query | 
 |     // names/values and fragment). | 
 |     case '#': | 
 |     case '&': | 
 |     case '.': | 
 |     case '/': | 
 |     case ':': | 
 |     case '=': | 
 |     case '?': | 
 |     case '@': | 
 |       // Treat all of these characters as strong LTR, which effectively | 
 |       // surrounds all of the text components of a URL (e.g., the domain labels | 
 |       // and path segments) in a left-to-right embedding. This ensures that the | 
 |       // URL components read from left to right, regardless of any RTL | 
 |       // characters. (Within each component, RTL sequences are rendered from | 
 |       // right to left as expected.) | 
 |       return U_LEFT_TO_RIGHT; | 
 |     default: | 
 |       return U_BIDI_CLASS_DEFAULT; | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | BiDiLineIterator::BiDiLineIterator() : bidi_(nullptr) {} | 
 |  | 
 | BiDiLineIterator::~BiDiLineIterator() { | 
 |   if (bidi_) { | 
 |     ubidi_close(bidi_); | 
 |     bidi_ = nullptr; | 
 |   } | 
 | } | 
 |  | 
 | bool BiDiLineIterator::Open(const string16& text, | 
 |                             TextDirection direction, | 
 |                             CustomBehavior behavior) { | 
 |   DCHECK(!bidi_); | 
 |   UErrorCode error = U_ZERO_ERROR; | 
 |   bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error); | 
 |   if (U_FAILURE(error)) | 
 |     return false; | 
 |  | 
 |   if (behavior == CustomBehavior::AS_URL) { | 
 |     ubidi_setClassCallback(bidi_, GetURLBiDiClassCallback, nullptr, nullptr, | 
 |                            nullptr, &error); | 
 |     if (U_FAILURE(error)) | 
 |       return false; | 
 |   } | 
 |  | 
 |   ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()), | 
 |                 GetParagraphLevelForDirection(direction), nullptr, &error); | 
 |   return (U_SUCCESS(error)); | 
 | } | 
 |  | 
 | int BiDiLineIterator::CountRuns() const { | 
 |   DCHECK(bidi_ != nullptr); | 
 |   UErrorCode error = U_ZERO_ERROR; | 
 |   const int runs = ubidi_countRuns(bidi_, &error); | 
 |   return U_SUCCESS(error) ? runs : 0; | 
 | } | 
 |  | 
 | UBiDiDirection BiDiLineIterator::GetVisualRun(int index, | 
 |                                               int* start, | 
 |                                               int* length) const { | 
 |   DCHECK(bidi_ != nullptr); | 
 |   return ubidi_getVisualRun(bidi_, index, start, length); | 
 | } | 
 |  | 
 | void BiDiLineIterator::GetLogicalRun(int start, | 
 |                                      int* end, | 
 |                                      UBiDiLevel* level) const { | 
 |   DCHECK(bidi_ != nullptr); | 
 |   ubidi_getLogicalRun(bidi_, start, end, level); | 
 | } | 
 |  | 
 | }  // namespace i18n | 
 | }  // namespace base |