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 "ui/accessibility/ax_text_utils.h"
6
7#include "base/logging.h"
8#include "base/strings/string_util.h"
9
10namespace ui {
11
12size_t FindAccessibleTextBoundary(const base::string16& text,
13                                  const std::vector<int>& line_breaks,
14                                  TextBoundaryType boundary,
15                                  size_t start_offset,
16                                  TextBoundaryDirection direction) {
17  size_t text_size = text.size();
18  DCHECK(start_offset <= text_size);
19
20  if (boundary == CHAR_BOUNDARY) {
21    if (direction == FORWARDS_DIRECTION && start_offset < text_size)
22      return start_offset + 1;
23    else
24      return start_offset;
25  } else if (boundary == LINE_BOUNDARY) {
26    if (direction == FORWARDS_DIRECTION) {
27      for (size_t j = 0; j < line_breaks.size(); ++j) {
28          size_t line_break = line_breaks[j] >= 0 ? line_breaks[j] : 0;
29        if (line_break > start_offset)
30          return line_break;
31      }
32      return text_size;
33    } else {
34      for (size_t j = line_breaks.size(); j != 0; --j) {
35        size_t line_break = line_breaks[j - 1] >= 0 ? line_breaks[j - 1] : 0;
36        if (line_break <= start_offset)
37          return line_break;
38      }
39      return 0;
40    }
41  }
42
43  size_t result = start_offset;
44  for (;;) {
45    size_t pos;
46    if (direction == FORWARDS_DIRECTION) {
47      if (result >= text_size)
48        return text_size;
49      pos = result;
50    } else {
51      if (result == 0)
52        return 0;
53      pos = result - 1;
54    }
55
56    switch (boundary) {
57      case CHAR_BOUNDARY:
58      case LINE_BOUNDARY:
59        NOTREACHED();  // These are handled above.
60        break;
61      case WORD_BOUNDARY:
62        if (IsWhitespace(text[pos]))
63          return result;
64        break;
65      case PARAGRAPH_BOUNDARY:
66        if (text[pos] == '\n')
67          return result;
68        break;
69      case SENTENCE_BOUNDARY:
70        if ((text[pos] == '.' || text[pos] == '!' || text[pos] == '?') &&
71            (pos == text_size - 1 || IsWhitespace(text[pos + 1]))) {
72          return result;
73        }
74        break;
75      case ALL_BOUNDARY:
76      default:
77        break;
78    }
79
80    if (direction == FORWARDS_DIRECTION) {
81      result++;
82    } else {
83      result--;
84    }
85  }
86}
87
88}  // Namespace ui
89