|  | // 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 |