diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-15 15:33:21 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-15 15:33:21 +0000 |
commit | b6350f81f78736ad32e5ce1d68231668109cc86a (patch) | |
tree | 6e28f51d4aae0fc29719942bc47ec73f76041b78 /ui | |
parent | 38066ee6e01bb5574b555d70278f4344458bf90f (diff) | |
download | chromium_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.cc | 96 | ||||
-rw-r--r-- | ui/base/range/range.h | 102 | ||||
-rw-r--r-- | ui/base/range/range.mm | 36 | ||||
-rw-r--r-- | ui/base/range/range_unittest.cc | 210 | ||||
-rw-r--r-- | ui/base/range/range_unittest.mm | 43 | ||||
-rw-r--r-- | ui/base/ui_base.gypi | 5 |
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', ], |