summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-15 15:33:21 +0000
committerrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-15 15:33:21 +0000
commitb6350f81f78736ad32e5ce1d68231668109cc86a (patch)
tree6e28f51d4aae0fc29719942bc47ec73f76041b78 /ui
parent38066ee6e01bb5574b555d70278f4344458bf90f (diff)
downloadchromium_src-b6350f81f78736ad32e5ce1d68231668109cc86a.zip
chromium_src-b6350f81f78736ad32e5ce1d68231668109cc86a.tar.gz
chromium_src-b6350f81f78736ad32e5ce1d68231668109cc86a.tar.bz2
Introduce ui::Range, a simple container for integral ranges (like text selection).
BUG=none TEST=ui_base_unittests Review URL: http://codereview.chromium.org/6625085 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@78217 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/base/range/range.cc96
-rw-r--r--ui/base/range/range.h102
-rw-r--r--ui/base/range/range.mm36
-rw-r--r--ui/base/range/range_unittest.cc210
-rw-r--r--ui/base/range/range_unittest.mm43
-rw-r--r--ui/base/ui_base.gypi5
6 files changed, 492 insertions, 0 deletions
diff --git a/ui/base/range/range.cc b/ui/base/range/range.cc
new file mode 100644
index 0000000..a7ce516
--- /dev/null
+++ b/ui/base/range/range.cc
@@ -0,0 +1,96 @@
+// 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 "ui/base/range/range.h"
+
+#include <limits>
+#include <ostream>
+
+#include "base/logging.h"
+
+namespace ui {
+
+Range::Range()
+ : start_(0),
+ end_(0) {
+}
+
+Range::Range(size_t start, size_t end)
+ : start_(start),
+ end_(end) {
+}
+
+Range::Range(size_t position)
+ : start_(position),
+ end_(position) {
+}
+
+// static
+const Range Range::InvalidRange() {
+ return Range(std::numeric_limits<size_t>::max());
+}
+
+bool Range::IsValid() const {
+ return *this != InvalidRange();
+}
+
+size_t Range::GetMin() const {
+ return std::min(start(), end());
+}
+
+size_t Range::GetMax() const {
+ return std::max(start(), end());
+}
+
+bool Range::operator==(const Range& other) const {
+ return start() == other.start() && end() == other.end();
+}
+
+bool Range::operator!=(const Range& other) const {
+ return !(*this == other);
+}
+
+bool Range::EqualsIgnoringDirection(const Range& other) const {
+ return GetMin() == other.GetMin() && GetMax() == other.GetMax();
+}
+
+#if defined(OS_WIN)
+Range::Range(const CHARRANGE& range, LONG total_length) {
+ // Check if this is an invalid range.
+ if (range.cpMin == -1 && range.cpMax == -1) {
+ *this = InvalidRange();
+ } else {
+ DCHECK_GE(range.cpMin, 0);
+ set_start(range.cpMin);
+ // {0,-1} is the "whole range" but that doesn't mean much out of context,
+ // so use the |total_length| parameter.
+ if (range.cpMax == -1) {
+ DCHECK_EQ(0, range.cpMin);
+ DCHECK_NE(-1, total_length);
+ set_end(total_length);
+ } else {
+ set_end(range.cpMax);
+ }
+ }
+}
+
+CHARRANGE Range::ToCHARRANGE() const {
+ CHARRANGE r = { -1, -1 };
+ if (!IsValid())
+ return r;
+
+ const LONG kLONGMax = std::numeric_limits<LONG>::max();
+ DCHECK_LE(static_cast<LONG>(start()), kLONGMax);
+ DCHECK_LE(static_cast<LONG>(end()), kLONGMax);
+ r.cpMin = start();
+ r.cpMax = end();
+ return r;
+}
+#endif // defined(OS_WIN)
+
+std::ostream& operator<<(std::ostream& out, const ui::Range& range) {
+ return out << "{" << range.start() << "," << range.end() << "}";
+}
+
+} // namespace gfx
diff --git a/ui/base/range/range.h b/ui/base/range/range.h
new file mode 100644
index 0000000..a0614d0
--- /dev/null
+++ b/ui/base/range/range.h
@@ -0,0 +1,102 @@
+// 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.
+
+#ifndef UI_GFX_RANGE_H_
+#define UI_GFX_RANGE_H_
+
+#include <iosfwd>
+
+#include "base/basictypes.h"
+
+#if defined(OS_MACOSX)
+#if __OBJC__
+#import <Foundation/Foundation.h>
+#else
+typedef struct _NSRange NSRange;
+#endif
+#endif // defined(OS_MACOSX)
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <richedit.h>
+#endif
+
+namespace ui {
+
+// A Range contains two integer values that represent a numeric range, like the
+// range of characters in a text selection. A range is made of a start and end
+// position; when they are the same, the Range is akin to a caret. Note that
+// |start_| can be greater than |end_| to respect the directionality of the
+// range.
+class Range {
+ public:
+ // Creates an empty range {0,0}.
+ Range();
+
+ // Initializes the range with a start and end.
+ Range(size_t start, size_t end);
+
+ // Initializes the range with the same start and end positions.
+ explicit Range(size_t position);
+
+ // Platform constructors.
+#if defined(OS_MACOSX)
+ explicit Range(const NSRange& range);
+#elif defined(OS_WIN)
+ // The |total_length| paramater should be used if the CHARRANGE is set to
+ // {0,-1} to indicate the whole range.
+ Range(const CHARRANGE& range, LONG total_length = -1);
+#endif
+
+ // Returns a range that is invalid, which is {size_t_max,size_t_max}.
+ static const Range InvalidRange();
+
+ // Checks if the range is valid through comparision to InvalidRange().
+ bool IsValid() const;
+
+ // Getters and setters.
+ size_t start() const { return start_; }
+ void set_start(size_t start) { start_ = start; }
+
+ size_t end() const { return end_; }
+ void set_end(size_t end) { end_ = end; }
+
+ // Returns the absolute value of the length.
+ size_t length() const {
+ int length = end() - start();
+ return length >= 0 ? length : -length;
+ }
+
+ bool is_reversed() const { return start() > end(); }
+ bool is_empty() const { return start() == end(); }
+
+ // Returns the minimum and maximum values.
+ size_t GetMin() const;
+ size_t GetMax() const;
+
+ bool operator==(const Range& other) const;
+ bool operator!=(const Range& other) const;
+ bool EqualsIgnoringDirection(const Range& other) const;
+
+#if defined(OS_MACOSX)
+ Range& operator=(const NSRange& range);
+
+ // NSRange does not store the directionality of a range, so if this
+ // is_reversed(), the range will get flipped when converted to an NSRange.
+ NSRange ToNSRange() const;
+#elif defined(OS_WIN)
+ CHARRANGE ToCHARRANGE() const;
+#endif
+ // GTK+ has no concept of a range.
+
+ private:
+ size_t start_;
+ size_t end_;
+};
+
+std::ostream& operator<<(std::ostream& out, const ui::Range& range);
+
+} // namespace gfx
+
+#endif // UI_GFX_RANGE_H_
diff --git a/ui/base/range/range.mm b/ui/base/range/range.mm
new file mode 100644
index 0000000..e99db37
--- /dev/null
+++ b/ui/base/range/range.mm
@@ -0,0 +1,36 @@
+// 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 "ui/base/range/range.h"
+
+#include <limits>
+
+#include "base/logging.h"
+
+namespace ui {
+
+Range::Range(const NSRange& range) {
+ *this = range;
+}
+
+Range& Range::operator=(const NSRange& range) {
+ if (range.location == NSNotFound) {
+ DCHECK_EQ(0U, range.length);
+ *this = InvalidRange();
+ } else {
+ set_start(range.location);
+ // Don't overflow |end_|.
+ DCHECK_LE(range.length, std::numeric_limits<size_t>::max() - start());
+ set_end(start() + range.length);
+ }
+ return *this;
+}
+
+NSRange Range::ToNSRange() const {
+ if (!IsValid())
+ return NSMakeRange(NSNotFound, 0);
+ return NSMakeRange(GetMin(), length());
+}
+
+} // namespace gfx
diff --git a/ui/base/range/range_unittest.cc b/ui/base/range/range_unittest.cc
new file mode 100644
index 0000000..b650c15
--- /dev/null
+++ b/ui/base/range/range_unittest.cc
@@ -0,0 +1,210 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/range/range.h"
+
+TEST(RangeTest, EmptyInit) {
+ ui::Range r;
+ EXPECT_EQ(0U, r.start());
+ EXPECT_EQ(0U, r.end());
+ EXPECT_EQ(0U, r.length());
+ EXPECT_FALSE(r.is_reversed());
+ EXPECT_TRUE(r.is_empty());
+ EXPECT_TRUE(r.IsValid());
+ EXPECT_EQ(0U, r.GetMin());
+ EXPECT_EQ(0U, r.GetMax());
+}
+
+TEST(RangeTest, StartEndInit) {
+ ui::Range r(10, 15);
+ EXPECT_EQ(10U, r.start());
+ EXPECT_EQ(15U, r.end());
+ EXPECT_EQ(5U, r.length());
+ EXPECT_FALSE(r.is_reversed());
+ EXPECT_FALSE(r.is_empty());
+ EXPECT_TRUE(r.IsValid());
+ EXPECT_EQ(10U, r.GetMin());
+ EXPECT_EQ(15U, r.GetMax());
+}
+
+TEST(RangeTest, StartEndReversedInit) {
+ ui::Range r(10, 5);
+ EXPECT_EQ(10U, r.start());
+ EXPECT_EQ(5U, r.end());
+ EXPECT_EQ(5U, r.length());
+ EXPECT_TRUE(r.is_reversed());
+ EXPECT_FALSE(r.is_empty());
+ EXPECT_TRUE(r.IsValid());
+ EXPECT_EQ(5U, r.GetMin());
+ EXPECT_EQ(10U, r.GetMax());
+}
+
+TEST(RangeTest, PositionInit) {
+ ui::Range r(12);
+ EXPECT_EQ(12U, r.start());
+ EXPECT_EQ(12U, r.end());
+ EXPECT_EQ(0U, r.length());
+ EXPECT_FALSE(r.is_reversed());
+ EXPECT_TRUE(r.is_empty());
+ EXPECT_TRUE(r.IsValid());
+ EXPECT_EQ(12U, r.GetMin());
+ EXPECT_EQ(12U, r.GetMax());
+}
+
+TEST(RangeTest, InvalidRange) {
+ ui::Range r(ui::Range::InvalidRange());
+ EXPECT_EQ(0U, r.length());
+ EXPECT_EQ(r.start(), r.end());
+ EXPECT_FALSE(r.is_reversed());
+ EXPECT_TRUE(r.is_empty());
+ EXPECT_FALSE(r.IsValid());
+}
+
+TEST(RangeTest, Equality) {
+ ui::Range r1(10, 4);
+ ui::Range r2(10, 4);
+ ui::Range r3(10, 2);
+ EXPECT_EQ(r1, r2);
+ EXPECT_NE(r1, r3);
+ EXPECT_NE(r2, r3);
+
+ ui::Range r4(11, 4);
+ EXPECT_NE(r1, r4);
+ EXPECT_NE(r2, r4);
+ EXPECT_NE(r3, r4);
+
+ ui::Range r5(12, 5);
+ EXPECT_NE(r1, r5);
+ EXPECT_NE(r2, r5);
+ EXPECT_NE(r3, r5);
+}
+
+TEST(RangeTest, EqualsIgnoringDirection) {
+ ui::Range r1(10, 5);
+ ui::Range r2(5, 10);
+ EXPECT_TRUE(r1.EqualsIgnoringDirection(r2));
+}
+
+TEST(RangeTest, SetStart) {
+ ui::Range r(10, 20);
+ EXPECT_EQ(10U, r.start());
+ EXPECT_EQ(10U, r.length());
+
+ r.set_start(42);
+ EXPECT_EQ(42U, r.start());
+ EXPECT_EQ(20U, r.end());
+ EXPECT_EQ(22U, r.length());
+ EXPECT_TRUE(r.is_reversed());
+}
+
+TEST(RangeTest, SetEnd) {
+ ui::Range r(10, 13);
+ EXPECT_EQ(10U, r.start());
+ EXPECT_EQ(3U, r.length());
+
+ r.set_end(20);
+ EXPECT_EQ(10U, r.start());
+ EXPECT_EQ(20U, r.end());
+ EXPECT_EQ(10U, r.length());
+}
+
+TEST(RangeTest, SetStartAndEnd) {
+ ui::Range r;
+ r.set_end(5);
+ r.set_start(1);
+ EXPECT_EQ(1U, r.start());
+ EXPECT_EQ(5U, r.end());
+ EXPECT_EQ(4U, r.length());
+ EXPECT_EQ(1U, r.GetMin());
+ EXPECT_EQ(5U, r.GetMax());
+}
+
+TEST(RangeTest, ReversedRange) {
+ ui::Range r(10, 5);
+ EXPECT_EQ(10U, r.start());
+ EXPECT_EQ(5U, r.end());
+ EXPECT_EQ(5U, r.length());
+ EXPECT_TRUE(r.is_reversed());
+ EXPECT_TRUE(r.IsValid());
+ EXPECT_EQ(5U, r.GetMin());
+ EXPECT_EQ(10U, r.GetMax());
+}
+
+TEST(RangeTest, SetReversedRange) {
+ ui::Range r(10, 20);
+ r.set_start(25);
+ EXPECT_EQ(25U, r.start());
+ EXPECT_EQ(20U, r.end());
+ EXPECT_EQ(5U, r.length());
+ EXPECT_TRUE(r.is_reversed());
+ EXPECT_TRUE(r.IsValid());
+
+ r.set_end(21);
+ EXPECT_EQ(25U, r.start());
+ EXPECT_EQ(21U, r.end());
+ EXPECT_EQ(4U, r.length());
+ EXPECT_TRUE(r.IsValid());
+ EXPECT_EQ(21U, r.GetMin());
+ EXPECT_EQ(25U, r.GetMax());
+}
+
+#if defined(OS_WIN)
+TEST(RangeTest, FromCHARRANGE) {
+ CHARRANGE cr = { 10, 32 };
+ ui::Range r(cr, 50);
+ EXPECT_EQ(10U, r.start());
+ EXPECT_EQ(32U, r.end());
+ EXPECT_EQ(22U, r.length());
+ EXPECT_FALSE(r.is_reversed());
+ EXPECT_TRUE(r.IsValid());
+}
+
+TEST(RangeTest, FromReversedCHARRANGE) {
+ CHARRANGE cr = { 20, 10 };
+ ui::Range r(cr, 40);
+ EXPECT_EQ(20U, r.start());
+ EXPECT_EQ(10U, r.end());
+ EXPECT_EQ(10U, r.length());
+ EXPECT_TRUE(r.is_reversed());
+ EXPECT_TRUE(r.IsValid());
+}
+
+TEST(RangeTest, FromCHARRANGETotal) {
+ CHARRANGE cr = { 0, -1 };
+ ui::Range r(cr, 20);
+ EXPECT_EQ(0U, r.start());
+ EXPECT_EQ(20U, r.end());
+ EXPECT_EQ(20U, r.length());
+ EXPECT_FALSE(r.is_reversed());
+ EXPECT_TRUE(r.IsValid());
+}
+
+TEST(RangeTest, ToCHARRANGE) {
+ ui::Range r(10, 30);
+ CHARRANGE cr = r.ToCHARRANGE();
+ EXPECT_EQ(10, cr.cpMin);
+ EXPECT_EQ(30, cr.cpMax);
+}
+
+TEST(RangeTest, ReversedToCHARRANGE) {
+ ui::Range r(20, 10);
+ CHARRANGE cr = r.ToCHARRANGE();
+ EXPECT_EQ(20U, cr.cpMin);
+ EXPECT_EQ(10U, cr.cpMax);
+}
+
+TEST(RangeTest, FromCHARRANGEInvalid) {
+ CHARRANGE cr = { -1, -1 };
+ ui::Range r(cr, 30);
+ EXPECT_FALSE(r.IsValid());
+}
+
+TEST(RangeTest, ToCHARRANGEInvalid) {
+ ui::Range r(ui::Range::InvalidRange());
+ CHARRANGE cr = r.ToCHARRANGE();
+ EXPECT_EQ(-1, cr.cpMin);
+ EXPECT_EQ(-1, cr.cpMax);
+}
+#endif // defined(OS_WIN)
diff --git a/ui/base/range/range_unittest.mm b/ui/base/range/range_unittest.mm
new file mode 100644
index 0000000..3142540
--- /dev/null
+++ b/ui/base/range/range_unittest.mm
@@ -0,0 +1,43 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/range/range.h"
+
+TEST(RangeTest, FromNSRange) {
+ NSRange nsr = NSMakeRange(10, 3);
+ ui::Range r(nsr);
+ EXPECT_EQ(nsr.location, r.start());
+ EXPECT_EQ(13U, r.end());
+ EXPECT_EQ(nsr.length, r.length());
+ EXPECT_FALSE(r.is_reversed());
+ EXPECT_TRUE(r.IsValid());
+}
+
+TEST(RangeTest, ToNSRange) {
+ ui::Range r(10, 12);
+ NSRange nsr = r.ToNSRange();
+ EXPECT_EQ(10U, nsr.location);
+ EXPECT_EQ(2U, nsr.length);
+}
+
+TEST(RangeTest, ReversedToNSRange) {
+ ui::Range r(20, 10);
+ NSRange nsr = r.ToNSRange();
+ EXPECT_EQ(10U, nsr.location);
+ EXPECT_EQ(10U, nsr.length);
+}
+
+TEST(RangeTest, FromNSRangeInvalid) {
+ NSRange nsr = NSMakeRange(NSNotFound, 0);
+ ui::Range r(nsr);
+ EXPECT_FALSE(r.IsValid());
+}
+
+TEST(RangeTest, ToNSRangeInvalid) {
+ ui::Range r(ui::Range::InvalidRange());
+ NSRange nsr = r.ToNSRange();
+ EXPECT_EQ(NSNotFound, nsr.location);
+ EXPECT_EQ(0U, nsr.length);
+}
diff --git a/ui/base/ui_base.gypi b/ui/base/ui_base.gypi
index 8bb0135..1d54c926 100644
--- a/ui/base/ui_base.gypi
+++ b/ui/base/ui_base.gypi
@@ -86,6 +86,9 @@
'clipboard/clipboard_win.cc',
'clipboard/scoped_clipboard_writer.cc',
'clipboard/scoped_clipboard_writer.h',
+ 'range/range.cc',
+ 'range/range.h',
+ 'range/range.mm',
],
'conditions': [
['OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
@@ -113,6 +116,8 @@
'animation/multi_animation_unittest.cc',
'animation/slide_animation_unittest.cc',
'clipboard/clipboard_unittest.cc',
+ 'range/range_unittest.cc',
+ 'range/range_unittest.mm',
'run_all_unittests.cc',
'test_suite.h',
],