diff options
author | Hidehiko Abe <hidehiko@google.com> | 2018-04-13 06:33:47 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2018-04-13 06:33:47 -0700 |
commit | 8cadf386df57b1ed249634ab88dce7c6f252de4e (patch) | |
tree | 36c89cd375dee720134b6af77c4907a01371f5a7 | |
parent | 026f42b9b0be91cab925c28b01b5271e17d1e7f5 (diff) | |
parent | 34c1558fedad7b65b8595d9e452e3190efa3ed12 (diff) | |
download | libchrome-8cadf386df57b1ed249634ab88dce7c6f252de4e.tar.gz |
Migrate libmojo repository into libchrome, part 1.
am: 34c1558fed
Change-Id: I55e227b5f259dd320b23645d4d051b8e4aab9024
56 files changed, 5082 insertions, 83 deletions
diff --git a/Android.bp b/Android.bp index c2a3ec056c..d4842e1e08 100644 --- a/Android.bp +++ b/Android.bp @@ -80,6 +80,8 @@ libchromeCommonSrc = [ "base/at_exit.cc", "base/base64.cc", "base/base64url.cc", + "base/base_paths.cc", + "base/base_paths_posix.cc", "base/base_switches.cc", "base/bind_helpers.cc", "base/build_time.cc", @@ -154,6 +156,7 @@ libchromeCommonSrc = [ "base/metrics/sample_vector.cc", "base/metrics/sparse_histogram.cc", "base/metrics/statistics_recorder.cc", + "base/path_service.cc", "base/pending_task.cc", "base/pickle.cc", "base/posix/global_descriptors.cc", @@ -270,9 +273,27 @@ libchromeCommonSrc = [ "base/trace_event/trace_log_constants.cc", "base/tracked_objects.cc", "base/tracking_info.cc", + "base/unguessable_token.cc", "base/values.cc", "base/version.cc", "base/vlog.cc", + "device/bluetooth/bluetooth_advertisement.cc", + "device/bluetooth/bluetooth_uuid.cc", + "device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.cc", + "ui/gfx/geometry/insets.cc", + "ui/gfx/geometry/insets_f.cc", + "ui/gfx/geometry/point.cc", + "ui/gfx/geometry/point_conversions.cc", + "ui/gfx/geometry/point_f.cc", + "ui/gfx/geometry/rect.cc", + "ui/gfx/geometry/rect_f.cc", + "ui/gfx/geometry/size.cc", + "ui/gfx/geometry/size_conversions.cc", + "ui/gfx/geometry/size_f.cc", + "ui/gfx/geometry/vector2d.cc", + "ui/gfx/geometry/vector2d_f.cc", + "ui/gfx/range/range.cc", + "ui/gfx/range/range_f.cc", ] libchromeLinuxSrc = [ @@ -553,6 +574,7 @@ cc_test { "base/vlog_unittest.cc", "testing/multiprocess_func_list.cc", "testrunner.cc", + "ui/gfx/range/range_unittest.cc", ], cflags: ["-DUNIT_TEST"], diff --git a/base/base_paths.cc b/base/base_paths.cc new file mode 100644 index 0000000000..31bc55401a --- /dev/null +++ b/base/base_paths.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2006-2008 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/base_paths.h" + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/path_service.h" + +namespace base { + +bool PathProvider(int key, FilePath* result) { + // NOTE: DIR_CURRENT is a special case in PathService::Get + + switch (key) { + case DIR_EXE: + PathService::Get(FILE_EXE, result); + *result = result->DirName(); + return true; + case DIR_MODULE: + PathService::Get(FILE_MODULE, result); + *result = result->DirName(); + return true; + case DIR_TEMP: + if (!GetTempDir(result)) + return false; + return true; + case base::DIR_HOME: + *result = GetHomeDir(); + return true; + case DIR_TEST_DATA: { + FilePath test_data_path; + if (!PathService::Get(DIR_SOURCE_ROOT, &test_data_path)) + return false; + test_data_path = test_data_path.Append(FILE_PATH_LITERAL("base")); + test_data_path = test_data_path.Append(FILE_PATH_LITERAL("test")); + test_data_path = test_data_path.Append(FILE_PATH_LITERAL("data")); + if (!PathExists(test_data_path)) // We don't want to create this. + return false; + *result = test_data_path; + return true; + } + default: + return false; + } +} + +} // namespace base diff --git a/base/base_paths.h b/base/base_paths.h new file mode 100644 index 0000000000..ef6aa82836 --- /dev/null +++ b/base/base_paths.h @@ -0,0 +1,54 @@ +// Copyright (c) 2012 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 BASE_BASE_PATHS_H_ +#define BASE_BASE_PATHS_H_ + +// This file declares path keys for the base module. These can be used with +// the PathService to access various special directories and files. + +#include "build/build_config.h" + +#if defined(OS_WIN) +#include "base/base_paths_win.h" +#elif defined(OS_MACOSX) +#include "base/base_paths_mac.h" +#elif defined(OS_ANDROID) +#include "base/base_paths_android.h" +#endif + +#if defined(OS_POSIX) +#include "base/base_paths_posix.h" +#endif + +namespace base { + +enum BasePathKey { + PATH_START = 0, + + DIR_CURRENT, // Current directory. + DIR_EXE, // Directory containing FILE_EXE. + DIR_MODULE, // Directory containing FILE_MODULE. + DIR_TEMP, // Temporary directory. + DIR_HOME, // User's root home directory. On Windows this will look + // like "C:\Users\<user>" which isn't necessarily a great + // place to put files. + FILE_EXE, // Path and filename of the current executable. + FILE_MODULE, // Path and filename of the module containing the code for + // the PathService (which could differ from FILE_EXE if the + // PathService were compiled into a shared object, for + // example). + DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful + // for tests that need to locate various resources. It + // should not be used outside of test code. + DIR_USER_DESKTOP, // The current user's Desktop. + + DIR_TEST_DATA, // Used only for testing. + + PATH_END +}; + +} // namespace base + +#endif // BASE_BASE_PATHS_H_ diff --git a/base/base_paths_posix.cc b/base/base_paths_posix.cc new file mode 100644 index 0000000000..37d646cd26 --- /dev/null +++ b/base/base_paths_posix.cc @@ -0,0 +1,123 @@ +// Copyright (c) 2012 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. + +// Defines base::PathProviderPosix, default path provider on POSIX OSes that +// don't have their own base_paths_OS.cc implementation (i.e. all but Mac and +// Android). + +#include "base/base_paths.h" + +#include <limits.h> +#include <stddef.h> + +#include <memory> +#include <ostream> +#include <string> + +#include "base/environment.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/logging.h" +// Unused, and this file is not ported to libchrome. +// #include "base/nix/xdg_util.h" +#include "base/path_service.h" +#include "base/process/process_metrics.h" +#include "build/build_config.h" + +#if defined(OS_FREEBSD) +#include <sys/param.h> +#include <sys/sysctl.h> +#elif defined(OS_SOLARIS) +#include <stdlib.h> +#endif + +namespace base { + +bool PathProviderPosix(int key, FilePath* result) { + FilePath path; + switch (key) { + case FILE_EXE: + case FILE_MODULE: { // TODO(evanm): is this correct? +#if defined(OS_LINUX) + FilePath bin_dir; + if (!ReadSymbolicLink(FilePath(kProcSelfExe), &bin_dir)) { + NOTREACHED() << "Unable to resolve " << kProcSelfExe << "."; + return false; + } + *result = bin_dir; + return true; +#elif defined(OS_FREEBSD) + int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + char bin_dir[PATH_MAX + 1]; + size_t length = sizeof(bin_dir); + // Upon return, |length| is the number of bytes written to |bin_dir| + // including the string terminator. + int error = sysctl(name, 4, bin_dir, &length, NULL, 0); + if (error < 0 || length <= 1) { + NOTREACHED() << "Unable to resolve path."; + return false; + } + *result = FilePath(FilePath::StringType(bin_dir, length - 1)); + return true; +#elif defined(OS_SOLARIS) + char bin_dir[PATH_MAX + 1]; + if (realpath(getexecname(), bin_dir) == NULL) { + NOTREACHED() << "Unable to resolve " << getexecname() << "."; + return false; + } + *result = FilePath(bin_dir); + return true; +#elif defined(OS_OPENBSD) + // There is currently no way to get the executable path on OpenBSD + char* cpath; + if ((cpath = getenv("CHROME_EXE_PATH")) != NULL) + *result = FilePath(cpath); + else + *result = FilePath("/usr/local/chrome/chrome"); + return true; +#endif + } +// Following paths are not supported in libchrome/libmojo. +#if 0 + case DIR_SOURCE_ROOT: { + // Allow passing this in the environment, for more flexibility in build + // tree configurations (sub-project builds, gyp --output_dir, etc.) + std::unique_ptr<Environment> env(Environment::Create()); + std::string cr_source_root; + if (env->GetVar("CR_SOURCE_ROOT", &cr_source_root)) { + path = FilePath(cr_source_root); + if (PathExists(path)) { + *result = path; + return true; + } + DLOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not " + << "point to a directory."; + } + // On POSIX, unit tests execute two levels deep from the source root. + // For example: out/{Debug|Release}/net_unittest + if (PathService::Get(DIR_EXE, &path)) { + *result = path.DirName().DirName(); + return true; + } + + DLOG(ERROR) << "Couldn't find your source root. " + << "Try running from your chromium/src directory."; + return false; + } + case DIR_USER_DESKTOP: + *result = nix::GetXDGUserDirectory("DESKTOP", "Desktop"); + return true; + case DIR_CACHE: { + std::unique_ptr<Environment> env(Environment::Create()); + FilePath cache_dir( + nix::GetXDGDirectory(env.get(), "XDG_CACHE_HOME", ".cache")); + *result = cache_dir; + return true; + } +#endif + } + return false; +} + +} // namespace base diff --git a/base/base_paths_posix.h b/base/base_paths_posix.h new file mode 100644 index 0000000000..ef002aeb0b --- /dev/null +++ b/base/base_paths_posix.h @@ -0,0 +1,27 @@ +// Copyright (c) 2012 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 BASE_BASE_PATHS_POSIX_H_ +#define BASE_BASE_PATHS_POSIX_H_ + +// This file declares windows-specific path keys for the base module. +// These can be used with the PathService to access various special +// directories and files. + +namespace base { + +enum { + PATH_POSIX_START = 400, + + DIR_CACHE, // Directory where to put cache data. Note this is + // *not* where the browser cache lives, but the + // browser cache can be a subdirectory. + // This is $XDG_CACHE_HOME on Linux and + // ~/Library/Caches on Mac. + PATH_POSIX_END +}; + +} // namespace base + +#endif // BASE_BASE_PATHS_POSIX_H_ diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc index 3501e241e9..91f12030a0 100644 --- a/base/files/file_util_posix.cc +++ b/base/files/file_util_posix.cc @@ -29,6 +29,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/singleton.h" +#include "base/path_service.h" #include "base/posix/eintr_wrapper.h" #include "base/stl_util.h" #include "base/strings/string_split.h" @@ -49,7 +50,6 @@ #if defined(OS_ANDROID) #include "base/android/content_uri_utils.h" #include "base/os_compat_android.h" -#include "base/path_service.h" #endif #if !defined(OS_IOS) diff --git a/base/i18n/base_i18n_export.h b/base/i18n/base_i18n_export.h new file mode 100644 index 0000000000..e8a2adda17 --- /dev/null +++ b/base/i18n/base_i18n_export.h @@ -0,0 +1,29 @@ +// 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 BASE_I18N_BASE_I18N_EXPORT_H_ +#define BASE_I18N_BASE_I18N_EXPORT_H_ + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(BASE_I18N_IMPLEMENTATION) +#define BASE_I18N_EXPORT __declspec(dllexport) +#else +#define BASE_I18N_EXPORT __declspec(dllimport) +#endif // defined(BASE_I18N_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(BASE_I18N_IMPLEMENTATION) +#define BASE_I18N_EXPORT __attribute__((visibility("default"))) +#else +#define BASE_I18N_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define BASE_I18N_EXPORT +#endif + +#endif // BASE_I18N_BASE_I18N_EXPORT_H_ diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h new file mode 100644 index 0000000000..df15cd0208 --- /dev/null +++ b/base/i18n/rtl.h @@ -0,0 +1,155 @@ +// 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 BASE_I18N_RTL_H_ +#define BASE_I18N_RTL_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "base/i18n/base_i18n_export.h" +#include "base/strings/string16.h" +#include "build/build_config.h" + +namespace base { + +class FilePath; + +namespace i18n { + +const char16 kRightToLeftMark = 0x200F; +const char16 kLeftToRightMark = 0x200E; +const char16 kLeftToRightEmbeddingMark = 0x202A; +const char16 kRightToLeftEmbeddingMark = 0x202B; +const char16 kPopDirectionalFormatting = 0x202C; +const char16 kLeftToRightOverride = 0x202D; +const char16 kRightToLeftOverride = 0x202E; + +// Locale.java mirrored this enum TextDirection. Please keep in sync. +enum TextDirection { + UNKNOWN_DIRECTION = 0, + RIGHT_TO_LEFT = 1, + LEFT_TO_RIGHT = 2, + TEXT_DIRECTION_MAX = LEFT_TO_RIGHT, +}; + +// Get the locale that the currently running process has been configured to use. +// The return value is of the form language[-country] (e.g., en-US) where the +// language is the 2 or 3 letter code from ISO-639. +BASE_I18N_EXPORT std::string GetConfiguredLocale(); + +// Canonicalize a string (eg. a POSIX locale string) to a Chrome locale name. +BASE_I18N_EXPORT std::string GetCanonicalLocale(const std::string& locale); + +// Sets the default locale of ICU. +// Once the application locale of Chrome in GetApplicationLocale is determined, +// the default locale of ICU need to be changed to match the application locale +// so that ICU functions work correctly in a locale-dependent manner. +// This is handy in that we don't have to call GetApplicationLocale() +// everytime we call locale-dependent ICU APIs as long as we make sure +// that this is called before any locale-dependent API is called. +BASE_I18N_EXPORT void SetICUDefaultLocale(const std::string& locale_string); + +// Returns true if the application text direction is right-to-left. +BASE_I18N_EXPORT bool IsRTL(); + +// Returns whether the text direction for the default ICU locale is RTL. This +// assumes that SetICUDefaultLocale has been called to set the default locale to +// the UI locale of Chrome. +// NOTE: Generally, you should call IsRTL() instead of this. +BASE_I18N_EXPORT bool ICUIsRTL(); + +// Returns the text direction for |locale_name|. +// As a startup optimization, this method checks the locale against a list of +// Chrome-supported RTL locales. +BASE_I18N_EXPORT TextDirection +GetTextDirectionForLocaleInStartUp(const char* locale_name); + +// Returns the text direction for |locale_name|. +BASE_I18N_EXPORT TextDirection GetTextDirectionForLocale( + const char* locale_name); + +// Given the string in |text|, returns the directionality of the first or last +// character with strong directionality in the string. If no character in the +// text has strong directionality, LEFT_TO_RIGHT is returned. The Bidi +// character types L, LRE, LRO, R, AL, RLE, and RLO are considered as strong +// directionality characters. Please refer to http://unicode.org/reports/tr9/ +// for more information. +BASE_I18N_EXPORT TextDirection GetFirstStrongCharacterDirection( + const string16& text); +BASE_I18N_EXPORT TextDirection GetLastStrongCharacterDirection( + const string16& text); + +// Given the string in |text|, returns LEFT_TO_RIGHT or RIGHT_TO_LEFT if all the +// strong directionality characters in the string are of the same +// directionality. It returns UNKNOWN_DIRECTION if the string contains a mix of +// LTR and RTL strong directionality characters. Defaults to LEFT_TO_RIGHT if +// the string does not contain directionality characters. Please refer to +// http://unicode.org/reports/tr9/ for more information. +BASE_I18N_EXPORT TextDirection GetStringDirection(const string16& text); + +// Given the string in |text|, this function modifies the string in place with +// the appropriate Unicode formatting marks that mark the string direction +// (either left-to-right or right-to-left). The function checks both the current +// locale and the contents of the string in order to determine the direction of +// the returned string. The function returns true if the string in |text| was +// properly adjusted. +// +// Certain LTR strings are not rendered correctly when the context is RTL. For +// example, the string "Foo!" will appear as "!Foo" if it is rendered as is in +// an RTL context. Calling this function will make sure the returned localized +// string is always treated as a right-to-left string. This is done by +// inserting certain Unicode formatting marks into the returned string. +// +// ** Notes about the Windows version of this function: +// TODO(idana) bug 6806: this function adjusts the string in question only +// if the current locale is right-to-left. The function does not take care of +// the opposite case (an RTL string displayed in an LTR context) since +// adjusting the string involves inserting Unicode formatting characters that +// Windows does not handle well unless right-to-left language support is +// installed. Since the English version of Windows doesn't have right-to-left +// language support installed by default, inserting the direction Unicode mark +// results in Windows displaying squares. +BASE_I18N_EXPORT bool AdjustStringForLocaleDirection(string16* text); + +// Undoes the actions of the above function (AdjustStringForLocaleDirection). +BASE_I18N_EXPORT bool UnadjustStringForLocaleDirection(string16* text); + +// Returns true if the string contains at least one character with strong right +// to left directionality; that is, a character with either R or AL Unicode +// BiDi character type. +BASE_I18N_EXPORT bool StringContainsStrongRTLChars(const string16& text); + +// Wraps a string with an LRE-PDF pair which essentialy marks the string as a +// Left-To-Right string. Doing this is useful in order to make sure LTR +// strings are rendered properly in an RTL context. +BASE_I18N_EXPORT void WrapStringWithLTRFormatting(string16* text); + +// Wraps a string with an RLE-PDF pair which essentialy marks the string as a +// Right-To-Left string. Doing this is useful in order to make sure RTL +// strings are rendered properly in an LTR context. +BASE_I18N_EXPORT void WrapStringWithRTLFormatting(string16* text); + +// Wraps file path to get it to display correctly in RTL UI. All filepaths +// should be passed through this function before display in UI for RTL locales. +BASE_I18N_EXPORT void WrapPathWithLTRFormatting(const FilePath& path, + string16* rtl_safe_path); + +// Return the string in |text| wrapped with LRE (Left-To-Right Embedding) and +// PDF (Pop Directional Formatting) marks, if needed for UI display purposes. +BASE_I18N_EXPORT string16 GetDisplayStringInLTRDirectionality( + const string16& text) WARN_UNUSED_RESULT; + +// Strip the beginning (U+202A..U+202B, U+202D..U+202E) and/or ending (U+202C) +// explicit bidi control characters from |text|, if there are any. Otherwise, +// return the text itself. Explicit bidi control characters display and have +// semantic effect. They can be deleted so they might not always appear in a +// pair. +BASE_I18N_EXPORT string16 StripWrappingBidiControlCharacters( + const string16& text) WARN_UNUSED_RESULT; + +} // namespace i18n +} // namespace base + +#endif // BASE_I18N_RTL_H_ diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc index 1344de6391..f645b427fc 100644 --- a/base/json/json_reader_unittest.cc +++ b/base/json/json_reader_unittest.cc @@ -8,14 +8,11 @@ #include <memory> -#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__) #include "base/base_paths.h" -#include "base/path_service.h" -#endif - #include "base/files/file_util.h" #include "base/logging.h" #include "base/macros.h" +#include "base/path_service.h" #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" @@ -570,8 +567,7 @@ TEST(JSONReaderTest, Reading) { } } -#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__) -TEST(JSONReaderTest, ReadFromFile) { +TEST(JSONReaderTest, DISABLED_ReadFromFile) { FilePath path; ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &path)); path = path.AppendASCII("json"); @@ -585,7 +581,6 @@ TEST(JSONReaderTest, ReadFromFile) { ASSERT_TRUE(root) << reader.GetErrorMessage(); EXPECT_TRUE(root->IsType(Value::Type::DICTIONARY)); } -#endif // !__ANDROID__ && !__ANDROID_HOST__ // Tests that the root of a JSON object can be deleted safely while its // children outlive it. diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc index 1d58c61e04..e5cb126861 100644 --- a/base/json/json_value_serializer_unittest.cc +++ b/base/json/json_value_serializer_unittest.cc @@ -11,9 +11,7 @@ #include "base/json/json_reader.h" #include "base/json/json_string_value_serializer.h" #include "base/json/json_writer.h" -#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__) #include "base/path_service.h" -#endif #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -397,8 +395,6 @@ TEST(JSONValueSerializerTest, JSONReaderComments) { ASSERT_FALSE(JSONReader::Read("/ * * / [1]")); } -#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__) - class JSONFileValueSerializerTest : public testing::Test { protected: void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } @@ -406,7 +402,7 @@ class JSONFileValueSerializerTest : public testing::Test { ScopedTempDir temp_dir_; }; -TEST_F(JSONFileValueSerializerTest, Roundtrip) { +TEST_F(JSONFileValueSerializerTest, DISABLED_Roundtrip) { FilePath original_file_path; ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path)); original_file_path = original_file_path.AppendASCII("serializer_test.json"); @@ -449,7 +445,7 @@ TEST_F(JSONFileValueSerializerTest, Roundtrip) { EXPECT_TRUE(DeleteFile(written_file_path, false)); } -TEST_F(JSONFileValueSerializerTest, RoundtripNested) { +TEST_F(JSONFileValueSerializerTest, DISABLED_RoundtripNested) { FilePath original_file_path; ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path)); original_file_path = @@ -475,7 +471,7 @@ TEST_F(JSONFileValueSerializerTest, RoundtripNested) { EXPECT_TRUE(DeleteFile(written_file_path, false)); } -TEST_F(JSONFileValueSerializerTest, NoWhitespace) { +TEST_F(JSONFileValueSerializerTest, DISABLED_NoWhitespace) { FilePath source_file_path; ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &source_file_path)); source_file_path = @@ -485,7 +481,6 @@ TEST_F(JSONFileValueSerializerTest, NoWhitespace) { std::unique_ptr<Value> root = deserializer.Deserialize(nullptr, nullptr); ASSERT_TRUE(root); } -#endif // !__ANDROID__ && !__ANDROID_HOST__ } // namespace diff --git a/base/path_service.cc b/base/path_service.cc new file mode 100644 index 0000000000..1b9d394930 --- /dev/null +++ b/base/path_service.cc @@ -0,0 +1,329 @@ +// Copyright (c) 2012 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/path_service.h" + +#if defined(OS_WIN) +#include <windows.h> +#include <shellapi.h> +#include <shlobj.h> +#endif + +#include "base/containers/hash_tables.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/synchronization/lock.h" +#include "build/build_config.h" + +namespace base { + +bool PathProvider(int key, FilePath* result); + +#if defined(OS_WIN) +bool PathProviderWin(int key, FilePath* result); +#elif defined(OS_MACOSX) +bool PathProviderMac(int key, FilePath* result); +#elif defined(OS_ANDROID) +bool PathProviderAndroid(int key, FilePath* result); +#elif defined(OS_POSIX) +// PathProviderPosix is the default path provider on POSIX OSes other than +// Mac and Android. +bool PathProviderPosix(int key, FilePath* result); +#endif + +namespace { + +typedef hash_map<int, FilePath> PathMap; + +// We keep a linked list of providers. In a debug build we ensure that no two +// providers claim overlapping keys. +struct Provider { + PathService::ProviderFunc func; + struct Provider* next; +#ifndef NDEBUG + int key_start; + int key_end; +#endif + bool is_static; +}; + +Provider base_provider = { + PathProvider, + NULL, +#ifndef NDEBUG + PATH_START, + PATH_END, +#endif + true +}; + +#if defined(OS_WIN) +Provider base_provider_win = { + PathProviderWin, + &base_provider, +#ifndef NDEBUG + PATH_WIN_START, + PATH_WIN_END, +#endif + true +}; +#endif + +#if defined(OS_MACOSX) +Provider base_provider_mac = { + PathProviderMac, + &base_provider, +#ifndef NDEBUG + PATH_MAC_START, + PATH_MAC_END, +#endif + true +}; +#endif + +#if defined(OS_ANDROID) +Provider base_provider_android = { + PathProviderAndroid, + &base_provider, +#ifndef NDEBUG + PATH_ANDROID_START, + PATH_ANDROID_END, +#endif + true +}; +#endif + +#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) +Provider base_provider_posix = { + PathProviderPosix, + &base_provider, +#ifndef NDEBUG + PATH_POSIX_START, + PATH_POSIX_END, +#endif + true +}; +#endif + + +struct PathData { + Lock lock; + PathMap cache; // Cache mappings from path key to path value. + PathMap overrides; // Track path overrides. + Provider* providers; // Linked list of path service providers. + bool cache_disabled; // Don't use cache if true; + + PathData() : cache_disabled(false) { +#if defined(OS_WIN) + providers = &base_provider_win; +#elif defined(OS_MACOSX) + providers = &base_provider_mac; +#elif defined(OS_ANDROID) + providers = &base_provider_android; +#elif defined(OS_POSIX) + providers = &base_provider_posix; +#endif + } +}; + +static PathData* GetPathData() { + static auto* path_data = new PathData(); + return path_data; +} + +// Tries to find |key| in the cache. |path_data| should be locked by the caller! +bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) { + if (path_data->cache_disabled) + return false; + // check for a cached version + PathMap::const_iterator it = path_data->cache.find(key); + if (it != path_data->cache.end()) { + *result = it->second; + return true; + } + return false; +} + +// Tries to find |key| in the overrides map. |path_data| should be locked by the +// caller! +bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) { + // check for an overridden version. + PathMap::const_iterator it = path_data->overrides.find(key); + if (it != path_data->overrides.end()) { + if (!path_data->cache_disabled) + path_data->cache[key] = it->second; + *result = it->second; + return true; + } + return false; +} + +} // namespace + +// TODO(brettw): this function does not handle long paths (filename > MAX_PATH) +// characters). This isn't supported very well by Windows right now, so it is +// moot, but we should keep this in mind for the future. +// static +bool PathService::Get(int key, FilePath* result) { + PathData* path_data = GetPathData(); + DCHECK(path_data); + DCHECK(result); + DCHECK_GE(key, DIR_CURRENT); + + // special case the current directory because it can never be cached + if (key == DIR_CURRENT) + return GetCurrentDirectory(result); + + Provider* provider = NULL; + { + AutoLock scoped_lock(path_data->lock); + if (LockedGetFromCache(key, path_data, result)) + return true; + + if (LockedGetFromOverrides(key, path_data, result)) + return true; + + // Get the beginning of the list while it is still locked. + provider = path_data->providers; + } + + FilePath path; + + // Iterating does not need the lock because only the list head might be + // modified on another thread. + while (provider) { + if (provider->func(key, &path)) + break; + DCHECK(path.empty()) << "provider should not have modified path"; + provider = provider->next; + } + + if (path.empty()) + return false; + + if (path.ReferencesParent()) { + // Make sure path service never returns a path with ".." in it. + path = MakeAbsoluteFilePath(path); + if (path.empty()) + return false; + } + *result = path; + + AutoLock scoped_lock(path_data->lock); + if (!path_data->cache_disabled) + path_data->cache[key] = path; + + return true; +} + +// static +bool PathService::Override(int key, const FilePath& path) { + // Just call the full function with true for the value of |create|, and + // assume that |path| may not be absolute yet. + return OverrideAndCreateIfNeeded(key, path, false, true); +} + +// static +bool PathService::OverrideAndCreateIfNeeded(int key, + const FilePath& path, + bool is_absolute, + bool create) { + PathData* path_data = GetPathData(); + DCHECK(path_data); + DCHECK_GT(key, DIR_CURRENT) << "invalid path key"; + + FilePath file_path = path; + + // For some locations this will fail if called from inside the sandbox there- + // fore we protect this call with a flag. + if (create) { + // Make sure the directory exists. We need to do this before we translate + // this to the absolute path because on POSIX, MakeAbsoluteFilePath fails + // if called on a non-existent path. + if (!PathExists(file_path) && !CreateDirectory(file_path)) + return false; + } + + // We need to have an absolute path. + if (!is_absolute) { + file_path = MakeAbsoluteFilePath(file_path); + if (file_path.empty()) + return false; + } + DCHECK(file_path.IsAbsolute()); + + AutoLock scoped_lock(path_data->lock); + + // Clear the cache now. Some of its entries could have depended + // on the value we are overriding, and are now out of sync with reality. + path_data->cache.clear(); + + path_data->overrides[key] = file_path; + + return true; +} + +// static +bool PathService::RemoveOverride(int key) { + PathData* path_data = GetPathData(); + DCHECK(path_data); + + AutoLock scoped_lock(path_data->lock); + + if (path_data->overrides.find(key) == path_data->overrides.end()) + return false; + + // Clear the cache now. Some of its entries could have depended on the value + // we are going to remove, and are now out of sync. + path_data->cache.clear(); + + path_data->overrides.erase(key); + + return true; +} + +// static +void PathService::RegisterProvider(ProviderFunc func, int key_start, + int key_end) { + PathData* path_data = GetPathData(); + DCHECK(path_data); + DCHECK_GT(key_end, key_start); + + Provider* p; + + p = new Provider; + p->is_static = false; + p->func = func; +#ifndef NDEBUG + p->key_start = key_start; + p->key_end = key_end; +#endif + + AutoLock scoped_lock(path_data->lock); + +#ifndef NDEBUG + Provider *iter = path_data->providers; + while (iter) { + DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) << + "path provider collision"; + iter = iter->next; + } +#endif + + p->next = path_data->providers; + path_data->providers = p; +} + +// static +void PathService::DisableCache() { + PathData* path_data = GetPathData(); + DCHECK(path_data); + + AutoLock scoped_lock(path_data->lock); + path_data->cache.clear(); + path_data->cache_disabled = true; +} + +} // namespace base diff --git a/base/path_service.h b/base/path_service.h new file mode 100644 index 0000000000..c7f1abe714 --- /dev/null +++ b/base/path_service.h @@ -0,0 +1,97 @@ +// Copyright (c) 2012 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 BASE_PATH_SERVICE_H_ +#define BASE_PATH_SERVICE_H_ + +#include <string> + +#include "base/base_export.h" +#include "base/base_paths.h" +#include "base/gtest_prod_util.h" +#include "build/build_config.h" + +namespace base { + +class FilePath; +class ScopedPathOverride; + +// The path service is a global table mapping keys to file system paths. It is +// OK to use this service from multiple threads. +// +class BASE_EXPORT PathService { + public: + // Retrieves a path to a special directory or file and places it into the + // string pointed to by 'path'. If you ask for a directory it is guaranteed + // to NOT have a path separator at the end. For example, "c:\windows\temp" + // Directories are also guaranteed to exist when this function succeeds. + // + // Returns true if the directory or file was successfully retrieved. On + // failure, 'path' will not be changed. + static bool Get(int key, FilePath* path); + + // Overrides the path to a special directory or file. This cannot be used to + // change the value of DIR_CURRENT, but that should be obvious. Also, if the + // path specifies a directory that does not exist, the directory will be + // created by this method. This method returns true if successful. + // + // If the given path is relative, then it will be resolved against + // DIR_CURRENT. + // + // WARNING: Consumers of PathService::Get may expect paths to be constant + // over the lifetime of the app, so this method should be used with caution. + // + // Unit tests generally should use ScopedPathOverride instead. Overrides from + // one test should not carry over to another. + static bool Override(int key, const FilePath& path); + + // This function does the same as PathService::Override but it takes extra + // parameters: + // - |is_absolute| indicates that |path| has already been expanded into an + // absolute path, otherwise MakeAbsoluteFilePath() will be used. This is + // useful to override paths that may not exist yet, since MakeAbsoluteFilePath + // fails for those. Note that MakeAbsoluteFilePath also expands symbolic + // links, even if path.IsAbsolute() is already true. + // - |create| guides whether the directory to be overriden must + // be created in case it doesn't exist already. + static bool OverrideAndCreateIfNeeded(int key, + const FilePath& path, + bool is_absolute, + bool create); + + // To extend the set of supported keys, you can register a path provider, + // which is just a function mirroring PathService::Get. The ProviderFunc + // returns false if it cannot provide a non-empty path for the given key. + // Otherwise, true is returned. + // + // WARNING: This function could be called on any thread from which the + // PathService is used, so a the ProviderFunc MUST BE THREADSAFE. + // + typedef bool (*ProviderFunc)(int, FilePath*); + + // Call to register a path provider. You must specify the range "[key_start, + // key_end)" of supported path keys. + static void RegisterProvider(ProviderFunc provider, + int key_start, + int key_end); + + // Disable internal cache. + static void DisableCache(); + + private: + friend class ScopedPathOverride; + FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride); + + // Removes an override for a special directory or file. Returns true if there + // was an override to remove or false if none was present. + // NOTE: This function is intended to be used by tests only! + static bool RemoveOverride(int key); +}; + +} // namespace base + +// TODO(brettw) Convert all callers to using the base namespace and remove this. +using base::PathService; + +#endif // BASE_PATH_SERVICE_H_ diff --git a/base/unguessable_token.cc b/base/unguessable_token.cc new file mode 100644 index 0000000000..cd9830e686 --- /dev/null +++ b/base/unguessable_token.cc @@ -0,0 +1,41 @@ +// Copyright 2016 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/unguessable_token.h" + +#include "base/format_macros.h" +#include "base/rand_util.h" +#include "base/strings/stringprintf.h" + +namespace base { + +UnguessableToken::UnguessableToken(uint64_t high, uint64_t low) + : high_(high), low_(low) {} + +std::string UnguessableToken::ToString() const { + return base::StringPrintf("(%08" PRIX64 "%08" PRIX64 ")", high_, low_); +} + +// static +UnguessableToken UnguessableToken::Create() { + UnguessableToken token; + // Use base::RandBytes instead of crypto::RandBytes, because crypto calls the + // base version directly, and to prevent the dependency from base/ to crypto/. + base::RandBytes(&token, sizeof(token)); + return token; +} + +// static +UnguessableToken UnguessableToken::Deserialize(uint64_t high, uint64_t low) { + // Receiving a zeroed out UnguessableToken from another process means that it + // was never initialized via Create(). Treat this case as a security issue. + DCHECK(!(high == 0 && low == 0)); + return UnguessableToken(high, low); +} + +std::ostream& operator<<(std::ostream& out, const UnguessableToken& token) { + return out << token.ToString(); +} + +} // namespace base diff --git a/base/unguessable_token.h b/base/unguessable_token.h new file mode 100644 index 0000000000..9f38783a3c --- /dev/null +++ b/base/unguessable_token.h @@ -0,0 +1,103 @@ +// Copyright 2016 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 BASE_UNGUESSABLE_TOKEN_H_ +#define BASE_UNGUESSABLE_TOKEN_H_ + +#include <stdint.h> +#include <string.h> +#include <iosfwd> +#include <tuple> + +#include "base/base_export.h" +#include "base/hash.h" +#include "base/logging.h" + +namespace base { + +struct UnguessableTokenHash; + +// A UnguessableToken is an 128-bit token generated from a cryptographically +// strong random source. +// +// UnguessableToken should be used when a sensitive ID needs to be unguessable, +// and is shared across processes. It can be used as part of a larger aggregate +// type, or as an ID in and of itself. +// +// Use Create() for creating new UnguessableTokens. +// +// NOTE: It is illegal to send empty UnguessableTokens across processes, and +// sending/receiving empty tokens should be treated as a security issue. +// If there is a valid scenario for sending "no token" across processes, +// base::Optional should be used instead of an empty token. +class BASE_EXPORT UnguessableToken { + public: + // Create a unique UnguessableToken. + static UnguessableToken Create(); + + // Return a UnguessableToken built from the high/low bytes provided. + // It should only be used in deserialization scenarios. + // + // NOTE: If the deserialized token is empty, it means that it was never + // initialized via Create(). This is a security issue, and should be handled. + static UnguessableToken Deserialize(uint64_t high, uint64_t low); + + // Creates an empty UnguessableToken. + // Assign to it with Create() before using it. + constexpr UnguessableToken() = default; + + // NOTE: Serializing an empty UnguessableToken is an illegal operation. + uint64_t GetHighForSerialization() const { + DCHECK(!is_empty()); + return high_; + }; + + // NOTE: Serializing an empty UnguessableToken is an illegal operation. + uint64_t GetLowForSerialization() const { + DCHECK(!is_empty()); + return low_; + } + + bool is_empty() const { return high_ == 0 && low_ == 0; } + + std::string ToString() const; + + explicit operator bool() const { return !is_empty(); } + + bool operator<(const UnguessableToken& other) const { + return std::tie(high_, low_) < std::tie(other.high_, other.low_); + } + + bool operator==(const UnguessableToken& other) const { + return high_ == other.high_ && low_ == other.low_; + } + + bool operator!=(const UnguessableToken& other) const { + return !(*this == other); + } + + private: + friend struct UnguessableTokenHash; + UnguessableToken(uint64_t high, uint64_t low); + + // Note: Two uint64_t are used instead of uint8_t[16], in order to have a + // simpler ToString() and is_empty(). + uint64_t high_ = 0; + uint64_t low_ = 0; +}; + +BASE_EXPORT std::ostream& operator<<(std::ostream& out, + const UnguessableToken& token); + +// For use in std::unordered_map. +struct UnguessableTokenHash { + size_t operator()(const base::UnguessableToken& token) const { + DCHECK(token); + return base::HashInts64(token.high_, token.low_); + } +}; + +} // namespace base + +#endif // BASE_UNGUESSABLE_TOKEN_H_ diff --git a/device/bluetooth/bluetooth_advertisement.cc b/device/bluetooth/bluetooth_advertisement.cc new file mode 100644 index 0000000000..05b0e52d22 --- /dev/null +++ b/device/bluetooth/bluetooth_advertisement.cc @@ -0,0 +1,37 @@ +// Copyright 2015 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 "device/bluetooth/bluetooth_advertisement.h" + +namespace device { + +BluetoothAdvertisement::Data::Data(AdvertisementType type) + : type_(type), include_tx_power_(false) { +} + +BluetoothAdvertisement::Data::~Data() { +} + +BluetoothAdvertisement::Data::Data() + : type_(ADVERTISEMENT_TYPE_BROADCAST), include_tx_power_(false) { +} + +void BluetoothAdvertisement::AddObserver( + BluetoothAdvertisement::Observer* observer) { + CHECK(observer); + observers_.AddObserver(observer); +} + +void BluetoothAdvertisement::RemoveObserver( + BluetoothAdvertisement::Observer* observer) { + CHECK(observer); + observers_.RemoveObserver(observer); +} + +BluetoothAdvertisement::BluetoothAdvertisement() { +} +BluetoothAdvertisement::~BluetoothAdvertisement() { +} + +} // namespace device diff --git a/device/bluetooth/bluetooth_advertisement.h b/device/bluetooth/bluetooth_advertisement.h new file mode 100644 index 0000000000..412baa72ee --- /dev/null +++ b/device/bluetooth/bluetooth_advertisement.h @@ -0,0 +1,152 @@ +// Copyright 2015 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 DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_H_ +#define DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_H_ + +#include <stdint.h> + +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/observer_list.h" +#include "device/bluetooth/bluetooth_export.h" + +namespace device { + +// BluetoothAdvertisement represents an advertisement which advertises over the +// LE channel during its lifetime. +class DEVICE_BLUETOOTH_EXPORT BluetoothAdvertisement + : public base::RefCounted<BluetoothAdvertisement> { + public: + // Possible types of error raised while registering or unregistering + // advertisements. + enum ErrorCode { + ERROR_UNSUPPORTED_PLATFORM, // Bluetooth advertisement not supported on + // current platform. + ERROR_ADVERTISEMENT_ALREADY_EXISTS, // An advertisement is already + // registered. + ERROR_ADVERTISEMENT_DOES_NOT_EXIST, // Unregistering an advertisement which + // is not registered. + ERROR_ADVERTISEMENT_INVALID_LENGTH, // Advertisement is not of a valid + // length. +#if defined(OS_CHROMEOS) || defined(OS_LINUX) + ERROR_INVALID_ADVERTISEMENT_INTERVAL, // Advertisement interval specified + // is out of valid range. +#endif + INVALID_ADVERTISEMENT_ERROR_CODE + }; + + // Type of advertisement. + enum AdvertisementType { + // This advertises with the type set to ADV_NONCONN_IND, which indicates + // to receivers that our device is not connectable. + ADVERTISEMENT_TYPE_BROADCAST, + // This advertises with the type set to ADV_IND or ADV_SCAN_IND, which + // indicates to receivers that our device is connectable. + ADVERTISEMENT_TYPE_PERIPHERAL + }; + + using UUIDList = std::vector<std::string>; + using ManufacturerData = std::map<uint16_t, std::vector<uint8_t>>; + using ServiceData = std::map<std::string, std::vector<uint8_t>>; + + // Structure that holds the data for an advertisement. + class DEVICE_BLUETOOTH_EXPORT Data { + public: + explicit Data(AdvertisementType type); + ~Data(); + + AdvertisementType type() { return type_; } + std::unique_ptr<UUIDList> service_uuids() { + return std::move(service_uuids_); + } + std::unique_ptr<ManufacturerData> manufacturer_data() { + return std::move(manufacturer_data_); + } + std::unique_ptr<UUIDList> solicit_uuids() { + return std::move(solicit_uuids_); + } + std::unique_ptr<ServiceData> service_data() { + return std::move(service_data_); + } + + void set_service_uuids(std::unique_ptr<UUIDList> service_uuids) { + service_uuids_ = std::move(service_uuids); + } + void set_manufacturer_data( + std::unique_ptr<ManufacturerData> manufacturer_data) { + manufacturer_data_ = std::move(manufacturer_data); + } + void set_solicit_uuids(std::unique_ptr<UUIDList> solicit_uuids) { + solicit_uuids_ = std::move(solicit_uuids); + } + void set_service_data(std::unique_ptr<ServiceData> service_data) { + service_data_ = std::move(service_data); + } + + void set_include_tx_power(bool include_tx_power) { + include_tx_power_ = include_tx_power; + } + + private: + Data(); + + AdvertisementType type_; + std::unique_ptr<UUIDList> service_uuids_; + std::unique_ptr<ManufacturerData> manufacturer_data_; + std::unique_ptr<UUIDList> solicit_uuids_; + std::unique_ptr<ServiceData> service_data_; + bool include_tx_power_; + + DISALLOW_COPY_AND_ASSIGN(Data); + }; + + // Interface for observing changes to this advertisement. + class Observer { + public: + virtual ~Observer() {} + + // Called when this advertisement is released and is no longer advertising. + virtual void AdvertisementReleased( + BluetoothAdvertisement* advertisement) = 0; + }; + + // Adds and removes observers for events for this advertisement. + void AddObserver(BluetoothAdvertisement::Observer* observer); + void RemoveObserver(BluetoothAdvertisement::Observer* observer); + + // Unregisters this advertisement. Called on destruction of this object + // automatically but can be called directly to explicitly unregister this + // object. + using SuccessCallback = base::Closure; + using ErrorCallback = base::Callback<void(ErrorCode)>; + virtual void Unregister(const SuccessCallback& success_callback, + const ErrorCallback& error_callback) = 0; + + protected: + friend class base::RefCounted<BluetoothAdvertisement>; + + BluetoothAdvertisement(); + + // The destructor will unregister this advertisement. + virtual ~BluetoothAdvertisement(); + + // List of observers interested in event notifications from us. Objects in + // |observers_| are expected to outlive a BluetoothAdvertisement object. + base::ObserverList<BluetoothAdvertisement::Observer> observers_; + + private: + DISALLOW_COPY_AND_ASSIGN(BluetoothAdvertisement); +}; + +} // namespace device + +#endif // DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_H_ diff --git a/device/bluetooth/bluetooth_common.h b/device/bluetooth/bluetooth_common.h new file mode 100644 index 0000000000..6045980f9b --- /dev/null +++ b/device/bluetooth/bluetooth_common.h @@ -0,0 +1,49 @@ +// Copyright 2016 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 DEVICE_BLUETOOTH_BLUETOOTH_TYPES_H_ +#define DEVICE_BLUETOOTH_BLUETOOTH_TYPES_H_ + +#include "device/bluetooth/bluetooth_export.h" + +// This file is for enums and small types common to several +// parts of bluetooth. + +namespace device { + +// Devices and adapters can support a number of transports, +// and bluetooth hosts can scan for devices based on the +// transports they support. +enum BluetoothTransport : uint8_t { + BLUETOOTH_TRANSPORT_INVALID = 0x00, + // Valid transports are given as a bitset. + BLUETOOTH_TRANSPORT_CLASSIC = 0x01, + BLUETOOTH_TRANSPORT_LE = 0x02, + BLUETOOTH_TRANSPORT_DUAL = + (BLUETOOTH_TRANSPORT_CLASSIC | BLUETOOTH_TRANSPORT_LE) +}; + +// Possible values that may be returned by BluetoothDevice::GetDeviceType(), +// representing different types of bluetooth device that we support or are aware +// of decoded from the bluetooth class information. +enum class BluetoothDeviceType { + UNKNOWN, + COMPUTER, + PHONE, + MODEM, + AUDIO, + CAR_AUDIO, + VIDEO, + PERIPHERAL, + JOYSTICK, + GAMEPAD, + KEYBOARD, + MOUSE, + TABLET, + KEYBOARD_MOUSE_COMBO +}; + +} // namespace device + +#endif // DEVICE_BLUETOOTH_BLUETOOTH_TYPES_H_ diff --git a/device/bluetooth/bluetooth_export.h b/device/bluetooth/bluetooth_export.h new file mode 100644 index 0000000000..90cc58cdb0 --- /dev/null +++ b/device/bluetooth/bluetooth_export.h @@ -0,0 +1,28 @@ +// Copyright 2014 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 DEVICE_BLUETOOTH_DEVICE_BLUETOOTH_EXPORT_H_ +#define DEVICE_BLUETOOTH_DEVICE_BLUETOOTH_EXPORT_H_ + +#if defined(COMPONENT_BUILD) && defined(WIN32) + +#if defined(DEVICE_BLUETOOTH_IMPLEMENTATION) +#define DEVICE_BLUETOOTH_EXPORT __declspec(dllexport) +#else +#define DEVICE_BLUETOOTH_EXPORT __declspec(dllimport) +#endif + +#elif defined(COMPONENT_BUILD) && !defined(WIN32) + +#if defined(DEVICE_BLUETOOTH_IMPLEMENTATION) +#define DEVICE_BLUETOOTH_EXPORT __attribute__((visibility("default"))) +#else +#define DEVICE_BLUETOOTH_EXPORT +#endif + +#else +#define DEVICE_BLUETOOTH_EXPORT +#endif + +#endif // DEVICE_BLUETOOTH_DEVICE_BLUETOOTH_EXPORT_H_ diff --git a/device/bluetooth/bluetooth_uuid.cc b/device/bluetooth/bluetooth_uuid.cc new file mode 100644 index 0000000000..b35094deba --- /dev/null +++ b/device/bluetooth/bluetooth_uuid.cc @@ -0,0 +1,98 @@ +// Copyright 2014 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 "device/bluetooth/bluetooth_uuid.h" + +#include <stddef.h> + +#include "base/logging.h" +#include "base/strings/string_util.h" + +namespace device { + +namespace { + +const char kCommonUuidPostfix[] = "-0000-1000-8000-00805f9b34fb"; +const char kCommonUuidPrefix[] = "0000"; + +// Returns the canonical, 128-bit canonical, and the format of the UUID +// in |canonical|, |canonical_128|, and |format| based on |uuid|. +void GetCanonicalUuid(std::string uuid, + std::string* canonical, + std::string* canonical_128, + BluetoothUUID::Format* format) { + // Initialize the values for the failure case. + canonical->clear(); + canonical_128->clear(); + *format = BluetoothUUID::kFormatInvalid; + + if (uuid.empty()) + return; + + if (uuid.size() < 11 && + base::StartsWith(uuid, "0x", base::CompareCase::SENSITIVE)) { + uuid = uuid.substr(2); + } + + if (!(uuid.size() == 4 || uuid.size() == 8 || uuid.size() == 36)) + return; + + for (size_t i = 0; i < uuid.size(); ++i) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (uuid[i] != '-') + return; + } else { + if (!base::IsHexDigit(uuid[i])) + return; + uuid[i] = base::ToLowerASCII(uuid[i]); + } + } + + canonical->assign(uuid); + if (uuid.size() == 4) { + canonical_128->assign(kCommonUuidPrefix + uuid + kCommonUuidPostfix); + *format = BluetoothUUID::kFormat16Bit; + } else if (uuid.size() == 8) { + canonical_128->assign(uuid + kCommonUuidPostfix); + *format = BluetoothUUID::kFormat32Bit; + } else { + canonical_128->assign(uuid); + *format = BluetoothUUID::kFormat128Bit; + } +} + +} // namespace + + +BluetoothUUID::BluetoothUUID(const std::string& uuid) { + GetCanonicalUuid(uuid, &value_, &canonical_value_, &format_); +} + +BluetoothUUID::BluetoothUUID() : format_(kFormatInvalid) { +} + +BluetoothUUID::~BluetoothUUID() { +} + +bool BluetoothUUID::IsValid() const { + return format_ != kFormatInvalid; +} + +bool BluetoothUUID::operator<(const BluetoothUUID& uuid) const { + return canonical_value_ < uuid.canonical_value_; +} + +bool BluetoothUUID::operator==(const BluetoothUUID& uuid) const { + return canonical_value_ == uuid.canonical_value_; +} + +bool BluetoothUUID::operator!=(const BluetoothUUID& uuid) const { + return canonical_value_ != uuid.canonical_value_; +} + +void PrintTo(const BluetoothUUID& uuid, std::ostream* out) { + *out << uuid.canonical_value(); +} + +} // namespace device diff --git a/device/bluetooth/bluetooth_uuid.h b/device/bluetooth/bluetooth_uuid.h new file mode 100644 index 0000000000..8487f6a2da --- /dev/null +++ b/device/bluetooth/bluetooth_uuid.h @@ -0,0 +1,106 @@ +// Copyright 2014 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 DEVICE_BLUETOOTH_BLUETOOTH_UUID_H_ +#define DEVICE_BLUETOOTH_BLUETOOTH_UUID_H_ + +#include <string> + +#include "device/bluetooth/bluetooth_export.h" + +namespace device { + +// Opaque wrapper around a Bluetooth UUID. Instances of UUID represent the +// 128-bit universally unique identifiers (UUIDs) of profiles and attributes +// used in Bluetooth based communication, such as a peripheral's services, +// characteristics, and characteristic descriptors. An instance are +// constructed using a string representing 16, 32, or 128 bit UUID formats. +class DEVICE_BLUETOOTH_EXPORT BluetoothUUID { + public: + // Possible representation formats used during construction. + enum Format { + kFormatInvalid, + kFormat16Bit, + kFormat32Bit, + kFormat128Bit + }; + + // Single argument constructor. |uuid| can be a 16, 32, or 128 bit UUID + // represented as a 4, 8, or 36 character string with the following + // formats: + // xxxx + // 0xxxxx + // xxxxxxxx + // 0xxxxxxxxx + // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + // + // 16 and 32 bit UUIDs will be internally converted to a 128 bit UUID using + // the base UUID defined in the Bluetooth specification, hence custom UUIDs + // should be provided in the 128-bit format. If |uuid| is in an unsupported + // format, the result might be invalid. Use IsValid to check for validity + // after construction. + explicit BluetoothUUID(const std::string& uuid); + + // Default constructor does nothing. Since BluetoothUUID is copyable, this + // constructor is useful for initializing member variables and assigning a + // value to them later. The default constructor will initialize an invalid + // UUID by definition and the string accessors will return an empty string. + BluetoothUUID(); + virtual ~BluetoothUUID(); + + // Returns true, if the UUID is in a valid canonical format. + bool IsValid() const; + + // Returns the representation format of the UUID. This reflects the format + // that was provided during construction. + Format format() const { return format_; } + + // Returns the value of the UUID as a string. The representation format is + // based on what was passed in during construction. For the supported sizes, + // this representation can have the following formats: + // - 16 bit: xxxx + // - 32 bit: xxxxxxxx + // - 128 bit: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + // where x is a lowercase hex digit. + const std::string& value() const { return value_; } + + // Returns the underlying 128-bit value as a string in the following format: + // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + // where x is a lowercase hex digit. + const std::string& canonical_value() const { return canonical_value_; } + + // Permit sufficient comparison to allow a UUID to be used as a key in a + // std::map. + bool operator<(const BluetoothUUID& uuid) const; + + // Equality operators. + bool operator==(const BluetoothUUID& uuid) const; + bool operator!=(const BluetoothUUID& uuid) const; + + private: + // String representation of the UUID that was used during construction. For + // the supported sizes, this representation can have the following formats: + // - 16 bit: xxxx + // - 32 bit: xxxxxxxx + // - 128 bit: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + Format format_; + std::string value_; + + // The 128-bit string representation of the UUID. + std::string canonical_value_; +}; + +// This is required by gtest to print a readable output on test failures. +void DEVICE_BLUETOOTH_EXPORT +PrintTo(const BluetoothUUID& uuid, std::ostream* out); + +struct BluetoothUUIDHash { + size_t operator()(const device::BluetoothUUID& uuid) const { + return std::hash<std::string>()(uuid.canonical_value()); + } +}; + +} // namespace device + +#endif // DEVICE_BLUETOOTH_BLUETOOTH_UUID_H_ diff --git a/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.cc b/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.cc new file mode 100644 index 0000000000..ee6cbf6112 --- /dev/null +++ b/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.cc @@ -0,0 +1,54 @@ +// Copyright 2016 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 "device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h" + +#include <utility> + +#include "base/logging.h" +#include "base/memory/ptr_util.h" + +namespace bluez { + +BluetoothServiceAttributeValueBlueZ::BluetoothServiceAttributeValueBlueZ() + : type_(NULLTYPE), size_(0), value_(base::Value::CreateNullValue()) {} + +BluetoothServiceAttributeValueBlueZ::BluetoothServiceAttributeValueBlueZ( + Type type, + size_t size, + std::unique_ptr<base::Value> value) + : type_(type), size_(size), value_(std::move(value)) { + CHECK_NE(type, SEQUENCE); +} + +BluetoothServiceAttributeValueBlueZ::BluetoothServiceAttributeValueBlueZ( + std::unique_ptr<Sequence> sequence) + : type_(SEQUENCE), + size_(sequence->size()), + sequence_(std::move(sequence)) {} + +BluetoothServiceAttributeValueBlueZ::BluetoothServiceAttributeValueBlueZ( + const BluetoothServiceAttributeValueBlueZ& attribute) { + *this = attribute; +} + +BluetoothServiceAttributeValueBlueZ& BluetoothServiceAttributeValueBlueZ:: +operator=(const BluetoothServiceAttributeValueBlueZ& attribute) { + if (this != &attribute) { + type_ = attribute.type_; + size_ = attribute.size_; + if (attribute.type_ == SEQUENCE) { + value_ = nullptr; + sequence_ = base::MakeUnique<Sequence>(*attribute.sequence_); + } else { + value_ = attribute.value_->CreateDeepCopy(); + sequence_ = nullptr; + } + } + return *this; +} + +BluetoothServiceAttributeValueBlueZ::~BluetoothServiceAttributeValueBlueZ() {} + +} // namespace bluez diff --git a/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h b/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h new file mode 100644 index 0000000000..fdd291a5f1 --- /dev/null +++ b/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h @@ -0,0 +1,59 @@ +// Copyright 2016 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 DEVICE_BLUETOOTH_BLUEZ_BLUETOOTH_SERVICE_ATTRIBUTE_VALUE_BLUEZ_H_ +#define DEVICE_BLUETOOTH_BLUEZ_BLUETOOTH_SERVICE_ATTRIBUTE_VALUE_BLUEZ_H_ + +#include <cstddef> +#include <memory> +#include <vector> + +#include "base/values.h" +#include "device/bluetooth/bluetooth_export.h" + +namespace bluez { + +// This class contains a Bluetooth service attribute. A service attribute is +// defined by the following fields, +// type: This is the type of the attribute. Along with being any of the +// fixed types, an attribute can also be of type sequence, which means +// that it contains an array of other attributes. +// size: This is the size of the attribute. This can be variable for each type. +// For example, a UUID can have the sizes, 2, 4 or 16 bytes. +// value: This is the raw value of the attribute. For example, for a UUID, it +// will be the string representation of the UUID. For a sequence, it +// will be an array of other attributes. +class DEVICE_BLUETOOTH_EXPORT BluetoothServiceAttributeValueBlueZ { + public: + enum Type { NULLTYPE = 0, UINT, INT, UUID, STRING, BOOL, SEQUENCE, URL }; + + using Sequence = std::vector<BluetoothServiceAttributeValueBlueZ>; + + BluetoothServiceAttributeValueBlueZ(); + BluetoothServiceAttributeValueBlueZ(Type type, + size_t size, + std::unique_ptr<base::Value> value); + explicit BluetoothServiceAttributeValueBlueZ( + std::unique_ptr<Sequence> sequence); + BluetoothServiceAttributeValueBlueZ( + const BluetoothServiceAttributeValueBlueZ& attribute); + BluetoothServiceAttributeValueBlueZ& operator=( + const BluetoothServiceAttributeValueBlueZ& attribute); + ~BluetoothServiceAttributeValueBlueZ(); + + Type type() const { return type_; } + size_t size() const { return size_; } + const Sequence& sequence() const { return *sequence_.get(); } + const base::Value& value() const { return *value_.get(); } + + private: + Type type_; + size_t size_; + std::unique_ptr<base::Value> value_; + std::unique_ptr<Sequence> sequence_; +}; + +} // namespace bluez + +#endif // DEVICE_BLUETOOTH_BLUEZ_BLUETOOTH_SERVICE_ATTRIBUTE_VALUE_BLUEZ_H_ diff --git a/libchrome_tools/patch/path_service.patch b/libchrome_tools/patch/path_service.patch index f831d984e7..75b30dc044 100644 --- a/libchrome_tools/patch/path_service.patch +++ b/libchrome_tools/patch/path_service.patch @@ -1,23 +1,36 @@ -# Currently, PathService is not available on libchrome. +# Several paths are not supported in PathService by libchrome. ---- a/base/files/file_util_posix.cc -+++ b/base/files/file_util_posix.cc -@@ -29,7 +29,6 @@ +--- a/base/base_paths_posix.cc ++++ b/base/base_paths_posix.cc +@@ -19,7 +19,8 @@ + #include "base/files/file_path.h" + #include "base/files/file_util.h" #include "base/logging.h" - #include "base/macros.h" - #include "base/memory/singleton.h" --#include "base/path_service.h" - #include "base/posix/eintr_wrapper.h" - #include "base/stl_util.h" - #include "base/strings/string_split.h" -@@ -50,6 +49,7 @@ - #if defined(OS_ANDROID) - #include "base/android/content_uri_utils.h" - #include "base/os_compat_android.h" -+#include "base/path_service.h" +-#include "base/nix/xdg_util.h" ++// Unused, and this file is not ported to libchrome. ++// #include "base/nix/xdg_util.h" + #include "base/path_service.h" + #include "base/process/process_metrics.h" + #include "build/build_config.h" +@@ -77,6 +78,8 @@ bool PathProviderPosix(int key, FilePath + return true; #endif - - #if !defined(OS_IOS) + } ++// Following paths are not supported in libchrome/libmojo. ++#if 0 + case DIR_SOURCE_ROOT: { + // Allow passing this in the environment, for more flexibility in build + // tree configurations (sub-project builds, gyp --output_dir, etc.) +@@ -112,6 +115,7 @@ bool PathProviderPosix(int key, FilePath + *result = cache_dir; + return true; + } ++#endif + } + return false; + } +--- a/base/files/file_util_posix.cc ++++ b/base/files/file_util_posix.cc @@ -533,6 +533,8 @@ bool GetTempDir(FilePath* path) { } else { #if defined(OS_ANDROID) @@ -29,64 +42,41 @@ #endif --- a/base/json/json_reader_unittest.cc +++ b/base/json/json_reader_unittest.cc -@@ -8,11 +8,14 @@ - - #include <memory> - -+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__) - #include "base/base_paths.h" -+#include "base/path_service.h" -+#endif -+ - #include "base/files/file_util.h" - #include "base/logging.h" - #include "base/macros.h" --#include "base/path_service.h" - #include "base/strings/string_piece.h" - #include "base/strings/utf_string_conversions.h" - #include "base/values.h" -@@ -567,6 +570,7 @@ TEST(JSONReaderTest, Reading) { +@@ -567,7 +567,7 @@ TEST(JSONReaderTest, Reading) { } } -+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__) - TEST(JSONReaderTest, ReadFromFile) { +-TEST(JSONReaderTest, ReadFromFile) { ++TEST(JSONReaderTest, DISABLED_ReadFromFile) { FilePath path; ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &path)); -@@ -581,6 +585,7 @@ TEST(JSONReaderTest, ReadFromFile) { - ASSERT_TRUE(root) << reader.GetErrorMessage(); - EXPECT_TRUE(root->IsType(Value::Type::DICTIONARY)); - } -+#endif // !__ANDROID__ && !__ANDROID_HOST__ - - // Tests that the root of a JSON object can be deleted safely while its - // children outlive it. + path = path.AppendASCII("json"); --- a/base/json/json_value_serializer_unittest.cc +++ b/base/json/json_value_serializer_unittest.cc -@@ -11,7 +11,9 @@ - #include "base/json/json_reader.h" - #include "base/json/json_string_value_serializer.h" - #include "base/json/json_writer.h" -+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__) - #include "base/path_service.h" -+#endif - #include "base/strings/string_piece.h" - #include "base/strings/string_util.h" - #include "base/strings/utf_string_conversions.h" -@@ -395,6 +397,8 @@ TEST(JSONValueSerializerTest, JSONReader - ASSERT_FALSE(JSONReader::Read("/ * * / [1]")); - } +@@ -402,7 +402,7 @@ class JSONFileValueSerializerTest : publ + ScopedTempDir temp_dir_; + }; -+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__) -+ - class JSONFileValueSerializerTest : public testing::Test { - protected: - void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } -@@ -481,6 +485,7 @@ TEST_F(JSONFileValueSerializerTest, NoWh - std::unique_ptr<Value> root = deserializer.Deserialize(nullptr, nullptr); - ASSERT_TRUE(root); +-TEST_F(JSONFileValueSerializerTest, Roundtrip) { ++TEST_F(JSONFileValueSerializerTest, DISABLED_Roundtrip) { + FilePath original_file_path; + ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path)); + original_file_path = original_file_path.AppendASCII("serializer_test.json"); +@@ -445,7 +445,7 @@ TEST_F(JSONFileValueSerializerTest, Roun + EXPECT_TRUE(DeleteFile(written_file_path, false)); } -+#endif // !__ANDROID__ && !__ANDROID_HOST__ - } // namespace +-TEST_F(JSONFileValueSerializerTest, RoundtripNested) { ++TEST_F(JSONFileValueSerializerTest, DISABLED_RoundtripNested) { + FilePath original_file_path; + ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path)); + original_file_path = +@@ -471,7 +471,7 @@ TEST_F(JSONFileValueSerializerTest, Roun + EXPECT_TRUE(DeleteFile(written_file_path, false)); + } +-TEST_F(JSONFileValueSerializerTest, NoWhitespace) { ++TEST_F(JSONFileValueSerializerTest, DISABLED_NoWhitespace) { + FilePath source_file_path; + ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &source_file_path)); + source_file_path = diff --git a/ui/gfx/geometry/insets.cc b/ui/gfx/geometry/insets.cc new file mode 100644 index 0000000000..9acc6e0fc1 --- /dev/null +++ b/ui/gfx/geometry/insets.cc @@ -0,0 +1,22 @@ +// Copyright (c) 2009 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/gfx/geometry/insets.h" + +#include "base/strings/stringprintf.h" +#include "ui/gfx/geometry/vector2d.h" + +namespace gfx { + +std::string Insets::ToString() const { + // Print members in the same order of the constructor parameters. + return base::StringPrintf("%d,%d,%d,%d", top(), left(), bottom(), right()); +} + +Insets Insets::Offset(const gfx::Vector2d& vector) const { + return gfx::Insets(top() + vector.y(), left() + vector.x(), + bottom() - vector.y(), right() - vector.x()); +} + +} // namespace gfx diff --git a/ui/gfx/geometry/insets.h b/ui/gfx/geometry/insets.h new file mode 100644 index 0000000000..a88bae3e42 --- /dev/null +++ b/ui/gfx/geometry/insets.h @@ -0,0 +1,130 @@ +// Copyright (c) 2012 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_GEOMETRY_INSETS_H_ +#define UI_GFX_GEOMETRY_INSETS_H_ + +#include <string> + +#include "ui/gfx/geometry/insets_f.h" +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +class Vector2d; + +// Represents the widths of the four borders or margins of an unspecified +// rectangle. An Insets stores the thickness of the top, left, bottom and right +// edges, without storing the actual size and position of the rectangle itself. +// +// This can be used to represent a space within a rectangle, by "shrinking" the +// rectangle by the inset amount on all four sides. Alternatively, it can +// represent a border that has a different thickness on each side. +class GFX_EXPORT Insets { + public: + constexpr Insets() : top_(0), left_(0), bottom_(0), right_(0) {} + constexpr explicit Insets(int all) + : top_(all), left_(all), bottom_(all), right_(all) {} + constexpr Insets(int vertical, int horizontal) + : top_(vertical), + left_(horizontal), + bottom_(vertical), + right_(horizontal) {} + constexpr Insets(int top, int left, int bottom, int right) + : top_(top), left_(left), bottom_(bottom), right_(right) {} + + constexpr int top() const { return top_; } + constexpr int left() const { return left_; } + constexpr int bottom() const { return bottom_; } + constexpr int right() const { return right_; } + + // Returns the total width taken up by the insets, which is the sum of the + // left and right insets. + constexpr int width() const { return left_ + right_; } + + // Returns the total height taken up by the insets, which is the sum of the + // top and bottom insets. + constexpr int height() const { return top_ + bottom_; } + + // Returns true if the insets are empty. + bool IsEmpty() const { return width() == 0 && height() == 0; } + + void Set(int top, int left, int bottom, int right) { + top_ = top; + left_ = left; + bottom_ = bottom; + right_ = right; + } + + bool operator==(const Insets& insets) const { + return top_ == insets.top_ && left_ == insets.left_ && + bottom_ == insets.bottom_ && right_ == insets.right_; + } + + bool operator!=(const Insets& insets) const { + return !(*this == insets); + } + + void operator+=(const Insets& insets) { + top_ += insets.top_; + left_ += insets.left_; + bottom_ += insets.bottom_; + right_ += insets.right_; + } + + void operator-=(const Insets& insets) { + top_ -= insets.top_; + left_ -= insets.left_; + bottom_ -= insets.bottom_; + right_ -= insets.right_; + } + + Insets operator-() const { + return Insets(-top_, -left_, -bottom_, -right_); + } + + Insets Scale(float scale) const { + return Scale(scale, scale); + } + + Insets Scale(float x_scale, float y_scale) const { + return Insets(static_cast<int>(top() * y_scale), + static_cast<int>(left() * x_scale), + static_cast<int>(bottom() * y_scale), + static_cast<int>(right() * x_scale)); + } + + // Adjusts the vertical and horizontal dimensions by the values described in + // |vector|. Offsetting insets before applying to a rectangle would be + // equivalent to offseting the rectangle then applying the insets. + Insets Offset(const gfx::Vector2d& vector) const; + + operator InsetsF() const { + return InsetsF(static_cast<float>(top()), static_cast<float>(left()), + static_cast<float>(bottom()), static_cast<float>(right())); + } + + // Returns a string representation of the insets. + std::string ToString() const; + + private: + int top_; + int left_; + int bottom_; + int right_; +}; + +inline Insets operator+(Insets lhs, const Insets& rhs) { + lhs += rhs; + return lhs; +} + +inline Insets operator-(Insets lhs, const Insets& rhs) { + lhs -= rhs; + return lhs; +} + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_INSETS_H_ diff --git a/ui/gfx/geometry/insets_f.cc b/ui/gfx/geometry/insets_f.cc new file mode 100644 index 0000000000..c1bc27ec52 --- /dev/null +++ b/ui/gfx/geometry/insets_f.cc @@ -0,0 +1,16 @@ +// Copyright (c) 2012 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/gfx/geometry/insets_f.h" + +#include "base/strings/stringprintf.h" + +namespace gfx { + +std::string InsetsF::ToString() const { + // Print members in the same order of the constructor parameters. + return base::StringPrintf("%f,%f,%f,%f", top(), left(), bottom(), right()); +} + +} // namespace gfx diff --git a/ui/gfx/geometry/insets_f.h b/ui/gfx/geometry/insets_f.h new file mode 100644 index 0000000000..30c2ff2b79 --- /dev/null +++ b/ui/gfx/geometry/insets_f.h @@ -0,0 +1,100 @@ +// Copyright (c) 2012 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_GEOMETRY_INSETS_F_H_ +#define UI_GFX_GEOMETRY_INSETS_F_H_ + +#include <string> + +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +// A floating point version of gfx::Insets. +class GFX_EXPORT InsetsF { + public: + constexpr InsetsF() : top_(0.f), left_(0.f), bottom_(0.f), right_(0.f) {} + constexpr explicit InsetsF(float all) + : top_(all), left_(all), bottom_(all), right_(all) {} + constexpr InsetsF(float vertical, float horizontal) + : top_(vertical), + left_(horizontal), + bottom_(vertical), + right_(horizontal) {} + constexpr InsetsF(float top, float left, float bottom, float right) + : top_(top), left_(left), bottom_(bottom), right_(right) {} + + constexpr float top() const { return top_; } + constexpr float left() const { return left_; } + constexpr float bottom() const { return bottom_; } + constexpr float right() const { return right_; } + + // Returns the total width taken up by the insets, which is the sum of the + // left and right insets. + constexpr float width() const { return left_ + right_; } + + // Returns the total height taken up by the insets, which is the sum of the + // top and bottom insets. + constexpr float height() const { return top_ + bottom_; } + + // Returns true if the insets are empty. + bool IsEmpty() const { return width() == 0.f && height() == 0.f; } + + void Set(float top, float left, float bottom, float right) { + top_ = top; + left_ = left; + bottom_ = bottom; + right_ = right; + } + + bool operator==(const InsetsF& insets) const { + return top_ == insets.top_ && left_ == insets.left_ && + bottom_ == insets.bottom_ && right_ == insets.right_; + } + + bool operator!=(const InsetsF& insets) const { + return !(*this == insets); + } + + void operator+=(const InsetsF& insets) { + top_ += insets.top_; + left_ += insets.left_; + bottom_ += insets.bottom_; + right_ += insets.right_; + } + + void operator-=(const InsetsF& insets) { + top_ -= insets.top_; + left_ -= insets.left_; + bottom_ -= insets.bottom_; + right_ -= insets.right_; + } + + InsetsF operator-() const { + return InsetsF(-top_, -left_, -bottom_, -right_); + } + + // Returns a string representation of the insets. + std::string ToString() const; + + private: + float top_; + float left_; + float bottom_; + float right_; +}; + +inline InsetsF operator+(InsetsF lhs, const InsetsF& rhs) { + lhs += rhs; + return lhs; +} + +inline InsetsF operator-(InsetsF lhs, const InsetsF& rhs) { + lhs -= rhs; + return lhs; +} + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_INSETS_F_H_ diff --git a/ui/gfx/geometry/point.cc b/ui/gfx/geometry/point.cc new file mode 100644 index 0000000000..285b208d44 --- /dev/null +++ b/ui/gfx/geometry/point.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2012 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/gfx/geometry/point.h" + +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "ui/gfx/geometry/point_conversions.h" +#include "ui/gfx/geometry/point_f.h" + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(OS_IOS) +#include <CoreGraphics/CoreGraphics.h> +#elif defined(OS_MACOSX) +#include <ApplicationServices/ApplicationServices.h> +#endif + +namespace gfx { + +#if defined(OS_WIN) +Point::Point(DWORD point) { + POINTS points = MAKEPOINTS(point); + x_ = points.x; + y_ = points.y; +} + +Point::Point(const POINT& point) : x_(point.x), y_(point.y) { +} + +Point& Point::operator=(const POINT& point) { + x_ = point.x; + y_ = point.y; + return *this; +} +#elif defined(OS_MACOSX) +Point::Point(const CGPoint& point) : x_(point.x), y_(point.y) { +} +#endif + +#if defined(OS_WIN) +POINT Point::ToPOINT() const { + POINT p; + p.x = x(); + p.y = y(); + return p; +} +#elif defined(OS_MACOSX) +CGPoint Point::ToCGPoint() const { + return CGPointMake(x(), y()); +} +#endif + +void Point::SetToMin(const Point& other) { + x_ = x_ <= other.x_ ? x_ : other.x_; + y_ = y_ <= other.y_ ? y_ : other.y_; +} + +void Point::SetToMax(const Point& other) { + x_ = x_ >= other.x_ ? x_ : other.x_; + y_ = y_ >= other.y_ ? y_ : other.y_; +} + +std::string Point::ToString() const { + return base::StringPrintf("%d,%d", x(), y()); +} + +Point ScaleToCeiledPoint(const Point& point, float x_scale, float y_scale) { + if (x_scale == 1.f && y_scale == 1.f) + return point; + return ToCeiledPoint(ScalePoint(gfx::PointF(point), x_scale, y_scale)); +} + +Point ScaleToCeiledPoint(const Point& point, float scale) { + if (scale == 1.f) + return point; + return ToCeiledPoint(ScalePoint(gfx::PointF(point), scale, scale)); +} + +Point ScaleToFlooredPoint(const Point& point, float x_scale, float y_scale) { + if (x_scale == 1.f && y_scale == 1.f) + return point; + return ToFlooredPoint(ScalePoint(gfx::PointF(point), x_scale, y_scale)); +} + +Point ScaleToFlooredPoint(const Point& point, float scale) { + if (scale == 1.f) + return point; + return ToFlooredPoint(ScalePoint(gfx::PointF(point), scale, scale)); +} + +Point ScaleToRoundedPoint(const Point& point, float x_scale, float y_scale) { + if (x_scale == 1.f && y_scale == 1.f) + return point; + return ToRoundedPoint(ScalePoint(gfx::PointF(point), x_scale, y_scale)); +} + +Point ScaleToRoundedPoint(const Point& point, float scale) { + if (scale == 1.f) + return point; + return ToRoundedPoint(ScalePoint(gfx::PointF(point), scale, scale)); +} + +} // namespace gfx diff --git a/ui/gfx/geometry/point.h b/ui/gfx/geometry/point.h new file mode 100644 index 0000000000..bb248d5432 --- /dev/null +++ b/ui/gfx/geometry/point.h @@ -0,0 +1,148 @@ +// Copyright (c) 2012 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_GEOMETRY_POINT_H_ +#define UI_GFX_GEOMETRY_POINT_H_ + +#include <iosfwd> +#include <string> +#include <tuple> + +#include "base/numerics/saturated_arithmetic.h" +#include "build/build_config.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/gfx_export.h" + +#if defined(OS_WIN) +typedef unsigned long DWORD; +typedef struct tagPOINT POINT; +#elif defined(OS_MACOSX) +typedef struct CGPoint CGPoint; +#endif + +namespace gfx { + +// A point has an x and y coordinate. +class GFX_EXPORT Point { + public: + constexpr Point() : x_(0), y_(0) {} + constexpr Point(int x, int y) : x_(x), y_(y) {} +#if defined(OS_WIN) + // |point| is a DWORD value that contains a coordinate. The x-coordinate is + // the low-order short and the y-coordinate is the high-order short. This + // value is commonly acquired from GetMessagePos/GetCursorPos. + explicit Point(DWORD point); + explicit Point(const POINT& point); + Point& operator=(const POINT& point); +#elif defined(OS_MACOSX) + explicit Point(const CGPoint& point); +#endif + +#if defined(OS_WIN) + POINT ToPOINT() const; +#elif defined(OS_MACOSX) + CGPoint ToCGPoint() const; +#endif + + constexpr int x() const { return x_; } + constexpr int y() const { return y_; } + void set_x(int x) { x_ = x; } + void set_y(int y) { y_ = y; } + + void SetPoint(int x, int y) { + x_ = x; + y_ = y; + } + + void Offset(int delta_x, int delta_y) { + x_ = base::SaturatedAddition(x_, delta_x); + y_ = base::SaturatedAddition(y_, delta_y); + } + + void operator+=(const Vector2d& vector) { + x_ = base::SaturatedAddition(x_, vector.x()); + y_ = base::SaturatedAddition(y_, vector.y()); + } + + void operator-=(const Vector2d& vector) { + x_ = base::SaturatedSubtraction(x_, vector.x()); + y_ = base::SaturatedSubtraction(y_, vector.y()); + } + + void SetToMin(const Point& other); + void SetToMax(const Point& other); + + bool IsOrigin() const { return x_ == 0 && y_ == 0; } + + Vector2d OffsetFromOrigin() const { return Vector2d(x_, y_); } + + // A point is less than another point if its y-value is closer + // to the origin. If the y-values are the same, then point with + // the x-value closer to the origin is considered less than the + // other. + // This comparison is required to use Point in sets, or sorted + // vectors. + bool operator<(const Point& rhs) const { + return std::tie(y_, x_) < std::tie(rhs.y_, rhs.x_); + } + + // Returns a string representation of point. + std::string ToString() const; + + private: + int x_; + int y_; +}; + +inline bool operator==(const Point& lhs, const Point& rhs) { + return lhs.x() == rhs.x() && lhs.y() == rhs.y(); +} + +inline bool operator!=(const Point& lhs, const Point& rhs) { + return !(lhs == rhs); +} + +inline Point operator+(const Point& lhs, const Vector2d& rhs) { + Point result(lhs); + result += rhs; + return result; +} + +inline Point operator-(const Point& lhs, const Vector2d& rhs) { + Point result(lhs); + result -= rhs; + return result; +} + +inline Vector2d operator-(const Point& lhs, const Point& rhs) { + return Vector2d(base::SaturatedSubtraction(lhs.x(), rhs.x()), + base::SaturatedSubtraction(lhs.y(), rhs.y())); +} + +inline Point PointAtOffsetFromOrigin(const Vector2d& offset_from_origin) { + return Point(offset_from_origin.x(), offset_from_origin.y()); +} + +// This is declared here for use in gtest-based unit tests but is defined in +// the //ui/gfx:test_support target. Depend on that to use this in your unit +// test. This should not be used in production code - call ToString() instead. +void PrintTo(const Point& point, ::std::ostream* os); + +// Helper methods to scale a gfx::Point to a new gfx::Point. +GFX_EXPORT Point ScaleToCeiledPoint(const Point& point, + float x_scale, + float y_scale); +GFX_EXPORT Point ScaleToCeiledPoint(const Point& point, float x_scale); +GFX_EXPORT Point ScaleToFlooredPoint(const Point& point, + float x_scale, + float y_scale); +GFX_EXPORT Point ScaleToFlooredPoint(const Point& point, float x_scale); +GFX_EXPORT Point ScaleToRoundedPoint(const Point& point, + float x_scale, + float y_scale); +GFX_EXPORT Point ScaleToRoundedPoint(const Point& point, float x_scale); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_POINT_H_ diff --git a/ui/gfx/geometry/point_conversions.cc b/ui/gfx/geometry/point_conversions.cc new file mode 100644 index 0000000000..0613e7a9db --- /dev/null +++ b/ui/gfx/geometry/point_conversions.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2012 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/gfx/geometry/point_conversions.h" + +#include "ui/gfx/geometry/safe_integer_conversions.h" + +namespace gfx { + +Point ToFlooredPoint(const PointF& point) { + int x = ToFlooredInt(point.x()); + int y = ToFlooredInt(point.y()); + return Point(x, y); +} + +Point ToCeiledPoint(const PointF& point) { + int x = ToCeiledInt(point.x()); + int y = ToCeiledInt(point.y()); + return Point(x, y); +} + +Point ToRoundedPoint(const PointF& point) { + int x = ToRoundedInt(point.x()); + int y = ToRoundedInt(point.y()); + return Point(x, y); +} + +} // namespace gfx + diff --git a/ui/gfx/geometry/point_conversions.h b/ui/gfx/geometry/point_conversions.h new file mode 100644 index 0000000000..bfab9e4e46 --- /dev/null +++ b/ui/gfx/geometry/point_conversions.h @@ -0,0 +1,24 @@ +// Copyright (c) 2012 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_GEOMETRY_POINT_CONVERSIONS_H_ +#define UI_GFX_GEOMETRY_POINT_CONVERSIONS_H_ + +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/point_f.h" + +namespace gfx { + +// Returns a Point with each component from the input PointF floored. +GFX_EXPORT Point ToFlooredPoint(const PointF& point); + +// Returns a Point with each component from the input PointF ceiled. +GFX_EXPORT Point ToCeiledPoint(const PointF& point); + +// Returns a Point with each component from the input PointF rounded. +GFX_EXPORT Point ToRoundedPoint(const PointF& point); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_POINT_CONVERSIONS_H_ diff --git a/ui/gfx/geometry/point_f.cc b/ui/gfx/geometry/point_f.cc new file mode 100644 index 0000000000..0d15394593 --- /dev/null +++ b/ui/gfx/geometry/point_f.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2012 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/gfx/geometry/point_f.h" + +#include "base/strings/stringprintf.h" + +namespace gfx { + +void PointF::SetToMin(const PointF& other) { + x_ = x_ <= other.x_ ? x_ : other.x_; + y_ = y_ <= other.y_ ? y_ : other.y_; +} + +void PointF::SetToMax(const PointF& other) { + x_ = x_ >= other.x_ ? x_ : other.x_; + y_ = y_ >= other.y_ ? y_ : other.y_; +} + +std::string PointF::ToString() const { + return base::StringPrintf("%f,%f", x(), y()); +} + +PointF ScalePoint(const PointF& p, float x_scale, float y_scale) { + PointF scaled_p(p); + scaled_p.Scale(x_scale, y_scale); + return scaled_p; +} + + +} // namespace gfx diff --git a/ui/gfx/geometry/point_f.h b/ui/gfx/geometry/point_f.h new file mode 100644 index 0000000000..5d92b1100c --- /dev/null +++ b/ui/gfx/geometry/point_f.h @@ -0,0 +1,126 @@ +// Copyright (c) 2012 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_GEOMETRY_POINT_F_H_ +#define UI_GFX_GEOMETRY_POINT_F_H_ + +#include <iosfwd> +#include <string> +#include <tuple> + +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/vector2d_f.h" +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +// A floating version of gfx::Point. +class GFX_EXPORT PointF { + public: + constexpr PointF() : x_(0.f), y_(0.f) {} + constexpr PointF(float x, float y) : x_(x), y_(y) {} + + constexpr explicit PointF(const Point& p) + : PointF(static_cast<float>(p.x()), static_cast<float>(p.y())) {} + + constexpr float x() const { return x_; } + constexpr float y() const { return y_; } + void set_x(float x) { x_ = x; } + void set_y(float y) { y_ = y; } + + void SetPoint(float x, float y) { + x_ = x; + y_ = y; + } + + void Offset(float delta_x, float delta_y) { + x_ += delta_x; + y_ += delta_y; + } + + void operator+=(const Vector2dF& vector) { + x_ += vector.x(); + y_ += vector.y(); + } + + void operator-=(const Vector2dF& vector) { + x_ -= vector.x(); + y_ -= vector.y(); + } + + void SetToMin(const PointF& other); + void SetToMax(const PointF& other); + + bool IsOrigin() const { return x_ == 0 && y_ == 0; } + + Vector2dF OffsetFromOrigin() const { return Vector2dF(x_, y_); } + + // A point is less than another point if its y-value is closer + // to the origin. If the y-values are the same, then point with + // the x-value closer to the origin is considered less than the + // other. + // This comparison is required to use PointF in sets, or sorted + // vectors. + bool operator<(const PointF& rhs) const { + return std::tie(y_, x_) < std::tie(rhs.y_, rhs.x_); + } + + void Scale(float scale) { + Scale(scale, scale); + } + + void Scale(float x_scale, float y_scale) { + SetPoint(x() * x_scale, y() * y_scale); + } + + // Returns a string representation of point. + std::string ToString() const; + + private: + float x_; + float y_; +}; + +inline bool operator==(const PointF& lhs, const PointF& rhs) { + return lhs.x() == rhs.x() && lhs.y() == rhs.y(); +} + +inline bool operator!=(const PointF& lhs, const PointF& rhs) { + return !(lhs == rhs); +} + +inline PointF operator+(const PointF& lhs, const Vector2dF& rhs) { + PointF result(lhs); + result += rhs; + return result; +} + +inline PointF operator-(const PointF& lhs, const Vector2dF& rhs) { + PointF result(lhs); + result -= rhs; + return result; +} + +inline Vector2dF operator-(const PointF& lhs, const PointF& rhs) { + return Vector2dF(lhs.x() - rhs.x(), lhs.y() - rhs.y()); +} + +inline PointF PointAtOffsetFromOrigin(const Vector2dF& offset_from_origin) { + return PointF(offset_from_origin.x(), offset_from_origin.y()); +} + +GFX_EXPORT PointF ScalePoint(const PointF& p, float x_scale, float y_scale); + +inline PointF ScalePoint(const PointF& p, float scale) { + return ScalePoint(p, scale, scale); +} + +// This is declared here for use in gtest-based unit tests but is defined in +// the //ui/gfx:test_support target. Depend on that to use this in your unit +// test. This should not be used in production code - call ToString() instead. +void PrintTo(const PointF& point, ::std::ostream* os); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_POINT_F_H_ diff --git a/ui/gfx/geometry/rect.cc b/ui/gfx/geometry/rect.cc new file mode 100644 index 0000000000..b5ceda5829 --- /dev/null +++ b/ui/gfx/geometry/rect.cc @@ -0,0 +1,346 @@ +// Copyright (c) 2012 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/gfx/geometry/rect.h" + +#include <algorithm> + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(OS_IOS) +#include <CoreGraphics/CoreGraphics.h> +#elif defined(OS_MACOSX) +#include <ApplicationServices/ApplicationServices.h> +#endif + +#include "base/logging.h" +#include "base/numerics/saturated_arithmetic.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "ui/gfx/geometry/insets.h" + +namespace gfx { + +#if defined(OS_WIN) +Rect::Rect(const RECT& r) + : origin_(r.left, r.top), + size_(std::abs(r.right - r.left), std::abs(r.bottom - r.top)) { +} +#elif defined(OS_MACOSX) +Rect::Rect(const CGRect& r) + : origin_(r.origin.x, r.origin.y), size_(r.size.width, r.size.height) { +} +#endif + +#if defined(OS_WIN) +RECT Rect::ToRECT() const { + RECT r; + r.left = x(); + r.right = right(); + r.top = y(); + r.bottom = bottom(); + return r; +} +#elif defined(OS_MACOSX) +CGRect Rect::ToCGRect() const { + return CGRectMake(x(), y(), width(), height()); +} +#endif + +void AdjustAlongAxis(int dst_origin, int dst_size, int* origin, int* size) { + *size = std::min(dst_size, *size); + if (*origin < dst_origin) + *origin = dst_origin; + else + *origin = std::min(dst_origin + dst_size, *origin + *size) - *size; +} + +} // namespace + +namespace gfx { + +// This is the per-axis heuristic for picking the most useful origin and +// width/height to represent the input range. +static void SaturatedClampRange(int min, int max, int* origin, int* span) { + if (max < min) { + *span = 0; + *origin = min; + return; + } + + int effective_span = base::SaturatedSubtraction(max, min); + int span_loss = base::SaturatedSubtraction(max, min + effective_span); + + // If the desired width is within the limits of ints, we can just + // use the simple computations to represent the range precisely. + if (span_loss == 0) { + *span = effective_span; + *origin = min; + return; + } + + // Now we have to approximate. If one of min or max is close enough + // to zero we choose to represent that one precisely. The other side is + // probably practically "infinite", so we move it. + if (base::SaturatedAbsolute(max) < std::numeric_limits<int>::max() / 2) { + // Maintain origin + span == max. + *span = effective_span; + *origin = max - effective_span; + } else if (base::SaturatedAbsolute(min) < + std::numeric_limits<int>::max() / 2) { + // Maintain origin == min. + *span = effective_span; + *origin = min; + } else { + // Both are big, so keep the center. + *span = effective_span; + *origin = min + span_loss / 2; + } +} + +void Rect::SetByBounds(int left, int top, int right, int bottom) { + int x, y; + int width, height; + SaturatedClampRange(left, right, &x, &width); + SaturatedClampRange(top, bottom, &y, &height); + origin_.SetPoint(x, y); + size_.SetSize(width, height); +} + +void Rect::Inset(const Insets& insets) { + Inset(insets.left(), insets.top(), insets.right(), insets.bottom()); +} + +void Rect::Inset(int left, int top, int right, int bottom) { + origin_ += Vector2d(left, top); + // left+right might overflow/underflow, but width() - (left+right) might + // overflow as well. + set_width(base::SaturatedSubtraction(width(), + base::SaturatedAddition(left, right))); + set_height(base::SaturatedSubtraction(height(), + base::SaturatedAddition(top, bottom))); +} + +void Rect::Offset(int horizontal, int vertical) { + origin_ += Vector2d(horizontal, vertical); + // Ensure that width and height remain valid. + set_width(width()); + set_height(height()); +} + +void Rect::operator+=(const Vector2d& offset) { + origin_ += offset; + // Ensure that width and height remain valid. + set_width(width()); + set_height(height()); +} + +void Rect::operator-=(const Vector2d& offset) { + origin_ -= offset; +} + +Insets Rect::InsetsFrom(const Rect& inner) const { + return Insets(inner.y() - y(), + inner.x() - x(), + bottom() - inner.bottom(), + right() - inner.right()); +} + +bool Rect::operator<(const Rect& other) const { + if (origin_ == other.origin_) { + if (width() == other.width()) { + return height() < other.height(); + } else { + return width() < other.width(); + } + } else { + return origin_ < other.origin_; + } +} + +bool Rect::Contains(int point_x, int point_y) const { + return (point_x >= x()) && (point_x < right()) && (point_y >= y()) && + (point_y < bottom()); +} + +bool Rect::Contains(const Rect& rect) const { + return (rect.x() >= x() && rect.right() <= right() && rect.y() >= y() && + rect.bottom() <= bottom()); +} + +bool Rect::Intersects(const Rect& rect) const { + return !(IsEmpty() || rect.IsEmpty() || rect.x() >= right() || + rect.right() <= x() || rect.y() >= bottom() || rect.bottom() <= y()); +} + +void Rect::Intersect(const Rect& rect) { + if (IsEmpty() || rect.IsEmpty()) { + SetRect(0, 0, 0, 0); // Throws away empty position. + return; + } + + int left = std::max(x(), rect.x()); + int top = std::max(y(), rect.y()); + int new_right = std::min(right(), rect.right()); + int new_bottom = std::min(bottom(), rect.bottom()); + + if (left >= new_right || top >= new_bottom) { + SetRect(0, 0, 0, 0); // Throws away empty position. + return; + } + + SetByBounds(left, top, new_right, new_bottom); +} + +void Rect::Union(const Rect& rect) { + if (IsEmpty()) { + *this = rect; + return; + } + if (rect.IsEmpty()) + return; + + SetByBounds(std::min(x(), rect.x()), std::min(y(), rect.y()), + std::max(right(), rect.right()), + std::max(bottom(), rect.bottom())); +} + +void Rect::Subtract(const Rect& rect) { + if (!Intersects(rect)) + return; + if (rect.Contains(*this)) { + SetRect(0, 0, 0, 0); + return; + } + + int rx = x(); + int ry = y(); + int rr = right(); + int rb = bottom(); + + if (rect.y() <= y() && rect.bottom() >= bottom()) { + // complete intersection in the y-direction + if (rect.x() <= x()) { + rx = rect.right(); + } else if (rect.right() >= right()) { + rr = rect.x(); + } + } else if (rect.x() <= x() && rect.right() >= right()) { + // complete intersection in the x-direction + if (rect.y() <= y()) { + ry = rect.bottom(); + } else if (rect.bottom() >= bottom()) { + rb = rect.y(); + } + } + SetByBounds(rx, ry, rr, rb); +} + +void Rect::AdjustToFit(const Rect& rect) { + int new_x = x(); + int new_y = y(); + int new_width = width(); + int new_height = height(); + AdjustAlongAxis(rect.x(), rect.width(), &new_x, &new_width); + AdjustAlongAxis(rect.y(), rect.height(), &new_y, &new_height); + SetRect(new_x, new_y, new_width, new_height); +} + +Point Rect::CenterPoint() const { + return Point(x() + width() / 2, y() + height() / 2); +} + +void Rect::ClampToCenteredSize(const Size& size) { + int new_width = std::min(width(), size.width()); + int new_height = std::min(height(), size.height()); + int new_x = x() + (width() - new_width) / 2; + int new_y = y() + (height() - new_height) / 2; + SetRect(new_x, new_y, new_width, new_height); +} + +void Rect::SplitVertically(Rect* left_half, Rect* right_half) const { + DCHECK(left_half); + DCHECK(right_half); + + left_half->SetRect(x(), y(), width() / 2, height()); + right_half->SetRect( + left_half->right(), y(), width() - left_half->width(), height()); +} + +bool Rect::SharesEdgeWith(const Rect& rect) const { + return (y() == rect.y() && height() == rect.height() && + (x() == rect.right() || right() == rect.x())) || + (x() == rect.x() && width() == rect.width() && + (y() == rect.bottom() || bottom() == rect.y())); +} + +int Rect::ManhattanDistanceToPoint(const Point& point) const { + int x_distance = + std::max<int>(0, std::max(x() - point.x(), point.x() - right())); + int y_distance = + std::max<int>(0, std::max(y() - point.y(), point.y() - bottom())); + + return x_distance + y_distance; +} + +int Rect::ManhattanInternalDistance(const Rect& rect) const { + Rect c(*this); + c.Union(rect); + + int x = std::max(0, c.width() - width() - rect.width() + 1); + int y = std::max(0, c.height() - height() - rect.height() + 1); + return x + y; +} + +std::string Rect::ToString() const { + return base::StringPrintf("%s %s", + origin().ToString().c_str(), + size().ToString().c_str()); +} + +bool Rect::ApproximatelyEqual(const Rect& rect, int tolerance) const { + return std::abs(x() - rect.x()) <= tolerance && + std::abs(y() - rect.y()) <= tolerance && + std::abs(right() - rect.right()) <= tolerance && + std::abs(bottom() - rect.bottom()) <= tolerance; +} + +Rect operator+(const Rect& lhs, const Vector2d& rhs) { + Rect result(lhs); + result += rhs; + return result; +} + +Rect operator-(const Rect& lhs, const Vector2d& rhs) { + Rect result(lhs); + result -= rhs; + return result; +} + +Rect IntersectRects(const Rect& a, const Rect& b) { + Rect result = a; + result.Intersect(b); + return result; +} + +Rect UnionRects(const Rect& a, const Rect& b) { + Rect result = a; + result.Union(b); + return result; +} + +Rect SubtractRects(const Rect& a, const Rect& b) { + Rect result = a; + result.Subtract(b); + return result; +} + +Rect BoundingRect(const Point& p1, const Point& p2) { + Rect result; + result.SetByBounds(std::min(p1.x(), p2.x()), std::min(p1.y(), p2.y()), + std::max(p1.x(), p2.x()), std::max(p1.y(), p2.y())); + return result; +} + +} // namespace gfx diff --git a/ui/gfx/geometry/rect.h b/ui/gfx/geometry/rect.h new file mode 100644 index 0000000000..1858d44d2c --- /dev/null +++ b/ui/gfx/geometry/rect.h @@ -0,0 +1,350 @@ +// Copyright (c) 2012 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. + +// Defines a simple integer rectangle class. The containment semantics +// are array-like; that is, the coordinate (x, y) is considered to be +// contained by the rectangle, but the coordinate (x + width, y) is not. +// The class will happily let you create malformed rectangles (that is, +// rectangles with negative width and/or height), but there will be assertions +// in the operations (such as Contains()) to complain in this case. + +#ifndef UI_GFX_GEOMETRY_RECT_H_ +#define UI_GFX_GEOMETRY_RECT_H_ + +#include <cmath> +#include <iosfwd> +#include <string> + +#include "base/logging.h" +#include "build/build_config.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/safe_integer_conversions.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/vector2d.h" + +#if defined(OS_WIN) +typedef struct tagRECT RECT; +#elif defined(OS_MACOSX) +typedef struct CGRect CGRect; +#endif + +namespace gfx { + +class Insets; + +class GFX_EXPORT Rect { + public: + constexpr Rect() = default; + constexpr Rect(int width, int height) : size_(width, height) {} + constexpr Rect(int x, int y, int width, int height) + : origin_(x, y), + size_(GetClampedValue(x, width), GetClampedValue(y, height)) {} + constexpr explicit Rect(const Size& size) : size_(size) {} + constexpr Rect(const Point& origin, const Size& size) + : origin_(origin), + size_(GetClampedValue(origin.x(), size.width()), + GetClampedValue(origin.y(), size.height())) {} + +#if defined(OS_WIN) + explicit Rect(const RECT& r); +#elif defined(OS_MACOSX) + explicit Rect(const CGRect& r); +#endif + +#if defined(OS_WIN) + // Construct an equivalent Win32 RECT object. + RECT ToRECT() const; +#elif defined(OS_MACOSX) + // Construct an equivalent CoreGraphics object. + CGRect ToCGRect() const; +#endif + + constexpr int x() const { return origin_.x(); } + void set_x(int x) { + origin_.set_x(x); + size_.set_width(GetClampedValue(x, width())); + } + + constexpr int y() const { return origin_.y(); } + void set_y(int y) { + origin_.set_y(y); + size_.set_height(GetClampedValue(y, height())); + } + + constexpr int width() const { return size_.width(); } + void set_width(int width) { size_.set_width(GetClampedValue(x(), width)); } + + constexpr int height() const { return size_.height(); } + void set_height(int height) { + size_.set_height(GetClampedValue(y(), height)); + } + + constexpr const Point& origin() const { return origin_; } + void set_origin(const Point& origin) { + origin_ = origin; + // Ensure that width and height remain valid. + set_width(width()); + set_height(height()); + } + + constexpr const Size& size() const { return size_; } + void set_size(const Size& size) { + set_width(size.width()); + set_height(size.height()); + } + + constexpr int right() const { return x() + width(); } + constexpr int bottom() const { return y() + height(); } + + constexpr Point top_right() const { return Point(right(), y()); } + constexpr Point bottom_left() const { return Point(x(), bottom()); } + constexpr Point bottom_right() const { return Point(right(), bottom()); } + + Vector2d OffsetFromOrigin() const { return Vector2d(x(), y()); } + + void SetRect(int x, int y, int width, int height) { + origin_.SetPoint(x, y); + // Ensure that width and height remain valid. + set_width(width); + set_height(height); + } + + // Use in place of SetRect() when you know the edges of the rectangle instead + // of the dimensions, rather than trying to determine the width/height + // yourself. This safely handles cases where the width/height would overflow. + void SetByBounds(int left, int top, int right, int bottom); + + // Shrink the rectangle by a horizontal and vertical distance on all sides. + void Inset(int horizontal, int vertical) { + Inset(horizontal, vertical, horizontal, vertical); + } + + // Shrink the rectangle by the given insets. + void Inset(const Insets& insets); + + // Shrink the rectangle by the specified amount on each side. + void Inset(int left, int top, int right, int bottom); + + // Move the rectangle by a horizontal and vertical distance. + void Offset(int horizontal, int vertical); + void Offset(const Vector2d& distance) { Offset(distance.x(), distance.y()); } + void operator+=(const Vector2d& offset); + void operator-=(const Vector2d& offset); + + Insets InsetsFrom(const Rect& inner) const; + + // Returns true if the area of the rectangle is zero. + bool IsEmpty() const { return size_.IsEmpty(); } + + // A rect is less than another rect if its origin is less than + // the other rect's origin. If the origins are equal, then the + // shortest rect is less than the other. If the origin and the + // height are equal, then the narrowest rect is less than. + // This comparison is required to use Rects in sets, or sorted + // vectors. + bool operator<(const Rect& other) const; + + // Returns true if the point identified by point_x and point_y falls inside + // this rectangle. The point (x, y) is inside the rectangle, but the + // point (x + width, y + height) is not. + bool Contains(int point_x, int point_y) const; + + // Returns true if the specified point is contained by this rectangle. + bool Contains(const Point& point) const { + return Contains(point.x(), point.y()); + } + + // Returns true if this rectangle contains the specified rectangle. + bool Contains(const Rect& rect) const; + + // Returns true if this rectangle intersects the specified rectangle. + // An empty rectangle doesn't intersect any rectangle. + bool Intersects(const Rect& rect) const; + + // Computes the intersection of this rectangle with the given rectangle. + void Intersect(const Rect& rect); + + // Computes the union of this rectangle with the given rectangle. The union + // is the smallest rectangle containing both rectangles. + void Union(const Rect& rect); + + // Computes the rectangle resulting from subtracting |rect| from |*this|, + // i.e. the bounding rect of |Region(*this) - Region(rect)|. + void Subtract(const Rect& rect); + + // Fits as much of the receiving rectangle into the supplied rectangle as + // possible, becoming the result. For example, if the receiver had + // a x-location of 2 and a width of 4, and the supplied rectangle had + // an x-location of 0 with a width of 5, the returned rectangle would have + // an x-location of 1 with a width of 4. + void AdjustToFit(const Rect& rect); + + // Returns the center of this rectangle. + Point CenterPoint() const; + + // Becomes a rectangle that has the same center point but with a size capped + // at given |size|. + void ClampToCenteredSize(const Size& size); + + // Splits |this| in two halves, |left_half| and |right_half|. + void SplitVertically(Rect* left_half, Rect* right_half) const; + + // Returns true if this rectangle shares an entire edge (i.e., same width or + // same height) with the given rectangle, and the rectangles do not overlap. + bool SharesEdgeWith(const Rect& rect) const; + + // Returns the manhattan distance from the rect to the point. If the point is + // inside the rect, returns 0. + int ManhattanDistanceToPoint(const Point& point) const; + + // Returns the manhattan distance between the contents of this rect and the + // contents of the given rect. That is, if the intersection of the two rects + // is non-empty then the function returns 0. If the rects share a side, it + // returns the smallest non-zero value appropriate for int. + int ManhattanInternalDistance(const Rect& rect) const; + + std::string ToString() const; + + bool ApproximatelyEqual(const Rect& rect, int tolerance) const; + + private: + gfx::Point origin_; + gfx::Size size_; + + // Returns true iff a+b would overflow max int. + static constexpr bool AddWouldOverflow(int a, int b) { + // In this function, GCC tries to make optimizations that would only work if + // max - a wouldn't overflow but it isn't smart enough to notice that a > 0. + // So cast everything to unsigned to avoid this. As it is guaranteed that + // max - a and b are both already positive, the cast is a noop. + // + // This is intended to be: a > 0 && max - a < b + return a > 0 && b > 0 && + static_cast<unsigned>(std::numeric_limits<int>::max() - a) < + static_cast<unsigned>(b); + } + + // Clamp the size to avoid integer overflow in bottom() and right(). + // This returns the width given an origin and a width. + // TODO(enne): this should probably use base::SaturatedAddition, but that + // function is not a constexpr. + static constexpr int GetClampedValue(int origin, int size) { + return AddWouldOverflow(origin, size) + ? std::numeric_limits<int>::max() - origin + : size; + } +}; + +inline bool operator==(const Rect& lhs, const Rect& rhs) { + return lhs.origin() == rhs.origin() && lhs.size() == rhs.size(); +} + +inline bool operator!=(const Rect& lhs, const Rect& rhs) { + return !(lhs == rhs); +} + +GFX_EXPORT Rect operator+(const Rect& lhs, const Vector2d& rhs); +GFX_EXPORT Rect operator-(const Rect& lhs, const Vector2d& rhs); + +inline Rect operator+(const Vector2d& lhs, const Rect& rhs) { + return rhs + lhs; +} + +GFX_EXPORT Rect IntersectRects(const Rect& a, const Rect& b); +GFX_EXPORT Rect UnionRects(const Rect& a, const Rect& b); +GFX_EXPORT Rect SubtractRects(const Rect& a, const Rect& b); + +// Constructs a rectangle with |p1| and |p2| as opposite corners. +// +// This could also be thought of as "the smallest rect that contains both +// points", except that we consider points on the right/bottom edges of the +// rect to be outside the rect. So technically one or both points will not be +// contained within the rect, because they will appear on one of these edges. +GFX_EXPORT Rect BoundingRect(const Point& p1, const Point& p2); + +// Scales the rect and returns the enclosing rect. Use this only the inputs are +// known to not overflow. Use ScaleToEnclosingRectSafe if the inputs are +// unknown and need to use saturated math. +inline Rect ScaleToEnclosingRect(const Rect& rect, + float x_scale, + float y_scale) { + if (x_scale == 1.f && y_scale == 1.f) + return rect; + // These next functions cast instead of using e.g. ToFlooredInt() because we + // haven't checked to ensure that the clamping behavior of the helper + // functions doesn't degrade performance, and callers shouldn't be passing + // values that cause overflow anyway. + DCHECK(base::IsValueInRangeForNumericType<int>( + std::floor(rect.x() * x_scale))); + DCHECK(base::IsValueInRangeForNumericType<int>( + std::floor(rect.y() * y_scale))); + DCHECK(base::IsValueInRangeForNumericType<int>( + std::ceil(rect.right() * x_scale))); + DCHECK(base::IsValueInRangeForNumericType<int>( + std::ceil(rect.bottom() * y_scale))); + int x = static_cast<int>(std::floor(rect.x() * x_scale)); + int y = static_cast<int>(std::floor(rect.y() * y_scale)); + int r = rect.width() == 0 ? + x : static_cast<int>(std::ceil(rect.right() * x_scale)); + int b = rect.height() == 0 ? + y : static_cast<int>(std::ceil(rect.bottom() * y_scale)); + return Rect(x, y, r - x, b - y); +} + +inline Rect ScaleToEnclosingRect(const Rect& rect, float scale) { + return ScaleToEnclosingRect(rect, scale, scale); +} + +// ScaleToEnclosingRect but clamping instead of asserting if the resulting rect +// would overflow. +inline Rect ScaleToEnclosingRectSafe(const Rect& rect, + float x_scale, + float y_scale) { + if (x_scale == 1.f && y_scale == 1.f) + return rect; + int x = base::saturated_cast<int>(std::floor(rect.x() * x_scale)); + int y = base::saturated_cast<int>(std::floor(rect.y() * y_scale)); + int w = base::saturated_cast<int>(std::ceil(rect.width() * x_scale)); + int h = base::saturated_cast<int>(std::ceil(rect.height() * y_scale)); + return Rect(x, y, w, h); +} + +inline Rect ScaleToEnclosingRectSafe(const Rect& rect, float scale) { + return ScaleToEnclosingRectSafe(rect, scale, scale); +} + +inline Rect ScaleToEnclosedRect(const Rect& rect, + float x_scale, + float y_scale) { + if (x_scale == 1.f && y_scale == 1.f) + return rect; + DCHECK(base::IsValueInRangeForNumericType<int>( + std::ceil(rect.x() * x_scale))); + DCHECK(base::IsValueInRangeForNumericType<int>( + std::ceil(rect.y() * y_scale))); + DCHECK(base::IsValueInRangeForNumericType<int>( + std::floor(rect.right() * x_scale))); + DCHECK(base::IsValueInRangeForNumericType<int>( + std::floor(rect.bottom() * y_scale))); + int x = static_cast<int>(std::ceil(rect.x() * x_scale)); + int y = static_cast<int>(std::ceil(rect.y() * y_scale)); + int r = rect.width() == 0 ? + x : static_cast<int>(std::floor(rect.right() * x_scale)); + int b = rect.height() == 0 ? + y : static_cast<int>(std::floor(rect.bottom() * y_scale)); + return Rect(x, y, r - x, b - y); +} + +inline Rect ScaleToEnclosedRect(const Rect& rect, float scale) { + return ScaleToEnclosedRect(rect, scale, scale); +} + +// This is declared here for use in gtest-based unit tests but is defined in +// the //ui/gfx:test_support target. Depend on that to use this in your unit +// test. This should not be used in production code - call ToString() instead. +void PrintTo(const Rect& rect, ::std::ostream* os); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_RECT_H_ diff --git a/ui/gfx/geometry/rect_f.cc b/ui/gfx/geometry/rect_f.cc new file mode 100644 index 0000000000..a08e384776 --- /dev/null +++ b/ui/gfx/geometry/rect_f.cc @@ -0,0 +1,259 @@ +// Copyright (c) 2012 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/gfx/geometry/rect_f.h" + +#include <algorithm> + +#if defined(OS_IOS) +#include <CoreGraphics/CoreGraphics.h> +#elif defined(OS_MACOSX) +#include <ApplicationServices/ApplicationServices.h> +#endif + +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "ui/gfx/geometry/insets_f.h" +#include "ui/gfx/geometry/safe_integer_conversions.h" + +namespace gfx { + +static void AdjustAlongAxis(float dst_origin, + float dst_size, + float* origin, + float* size) { + *size = std::min(dst_size, *size); + if (*origin < dst_origin) + *origin = dst_origin; + else + *origin = std::min(dst_origin + dst_size, *origin + *size) - *size; +} + +#if defined(OS_MACOSX) +RectF::RectF(const CGRect& r) + : origin_(r.origin.x, r.origin.y), size_(r.size.width, r.size.height) { +} + +CGRect RectF::ToCGRect() const { + return CGRectMake(x(), y(), width(), height()); +} +#endif + +void RectF::Inset(const InsetsF& insets) { + Inset(insets.left(), insets.top(), insets.right(), insets.bottom()); +} + +void RectF::Inset(float left, float top, float right, float bottom) { + origin_ += Vector2dF(left, top); + set_width(std::max(width() - left - right, static_cast<float>(0))); + set_height(std::max(height() - top - bottom, static_cast<float>(0))); +} + +void RectF::Offset(float horizontal, float vertical) { + origin_ += Vector2dF(horizontal, vertical); +} + +void RectF::operator+=(const Vector2dF& offset) { + origin_ += offset; +} + +void RectF::operator-=(const Vector2dF& offset) { + origin_ -= offset; +} + +InsetsF RectF::InsetsFrom(const RectF& inner) const { + return InsetsF(inner.y() - y(), + inner.x() - x(), + bottom() - inner.bottom(), + right() - inner.right()); +} + +bool RectF::operator<(const RectF& other) const { + if (origin_ == other.origin_) { + if (width() == other.width()) { + return height() < other.height(); + } else { + return width() < other.width(); + } + } else { + return origin_ < other.origin_; + } +} + +bool RectF::Contains(float point_x, float point_y) const { + return (point_x >= x()) && (point_x < right()) && (point_y >= y()) && + (point_y < bottom()); +} + +bool RectF::Contains(const RectF& rect) const { + return (rect.x() >= x() && rect.right() <= right() && rect.y() >= y() && + rect.bottom() <= bottom()); +} + +bool RectF::Intersects(const RectF& rect) const { + return !(IsEmpty() || rect.IsEmpty() || rect.x() >= right() || + rect.right() <= x() || rect.y() >= bottom() || rect.bottom() <= y()); +} + +void RectF::Intersect(const RectF& rect) { + if (IsEmpty() || rect.IsEmpty()) { + SetRect(0, 0, 0, 0); + return; + } + + float rx = std::max(x(), rect.x()); + float ry = std::max(y(), rect.y()); + float rr = std::min(right(), rect.right()); + float rb = std::min(bottom(), rect.bottom()); + + if (rx >= rr || ry >= rb) + rx = ry = rr = rb = 0; // non-intersecting + + SetRect(rx, ry, rr - rx, rb - ry); +} + +void RectF::Union(const RectF& rect) { + if (IsEmpty()) { + *this = rect; + return; + } + if (rect.IsEmpty()) + return; + + float rx = std::min(x(), rect.x()); + float ry = std::min(y(), rect.y()); + float rr = std::max(right(), rect.right()); + float rb = std::max(bottom(), rect.bottom()); + + SetRect(rx, ry, rr - rx, rb - ry); +} + +void RectF::Subtract(const RectF& rect) { + if (!Intersects(rect)) + return; + if (rect.Contains(*static_cast<const RectF*>(this))) { + SetRect(0, 0, 0, 0); + return; + } + + float rx = x(); + float ry = y(); + float rr = right(); + float rb = bottom(); + + if (rect.y() <= y() && rect.bottom() >= bottom()) { + // complete intersection in the y-direction + if (rect.x() <= x()) { + rx = rect.right(); + } else if (rect.right() >= right()) { + rr = rect.x(); + } + } else if (rect.x() <= x() && rect.right() >= right()) { + // complete intersection in the x-direction + if (rect.y() <= y()) { + ry = rect.bottom(); + } else if (rect.bottom() >= bottom()) { + rb = rect.y(); + } + } + SetRect(rx, ry, rr - rx, rb - ry); +} + +void RectF::AdjustToFit(const RectF& rect) { + float new_x = x(); + float new_y = y(); + float new_width = width(); + float new_height = height(); + AdjustAlongAxis(rect.x(), rect.width(), &new_x, &new_width); + AdjustAlongAxis(rect.y(), rect.height(), &new_y, &new_height); + SetRect(new_x, new_y, new_width, new_height); +} + +PointF RectF::CenterPoint() const { + return PointF(x() + width() / 2, y() + height() / 2); +} + +void RectF::ClampToCenteredSize(const SizeF& size) { + float new_width = std::min(width(), size.width()); + float new_height = std::min(height(), size.height()); + float new_x = x() + (width() - new_width) / 2; + float new_y = y() + (height() - new_height) / 2; + SetRect(new_x, new_y, new_width, new_height); +} + +void RectF::SplitVertically(RectF* left_half, RectF* right_half) const { + DCHECK(left_half); + DCHECK(right_half); + + left_half->SetRect(x(), y(), width() / 2, height()); + right_half->SetRect( + left_half->right(), y(), width() - left_half->width(), height()); +} + +bool RectF::SharesEdgeWith(const RectF& rect) const { + return (y() == rect.y() && height() == rect.height() && + (x() == rect.right() || right() == rect.x())) || + (x() == rect.x() && width() == rect.width() && + (y() == rect.bottom() || bottom() == rect.y())); +} + +float RectF::ManhattanDistanceToPoint(const PointF& point) const { + float x_distance = + std::max<float>(0, std::max(x() - point.x(), point.x() - right())); + float y_distance = + std::max<float>(0, std::max(y() - point.y(), point.y() - bottom())); + + return x_distance + y_distance; +} + +float RectF::ManhattanInternalDistance(const RectF& rect) const { + RectF c(*this); + c.Union(rect); + + static const float kEpsilon = std::numeric_limits<float>::epsilon(); + float x = std::max(0.f, c.width() - width() - rect.width() + kEpsilon); + float y = std::max(0.f, c.height() - height() - rect.height() + kEpsilon); + return x + y; +} + +bool RectF::IsExpressibleAsRect() const { + return IsExpressibleAsInt(x()) && IsExpressibleAsInt(y()) && + IsExpressibleAsInt(width()) && IsExpressibleAsInt(height()) && + IsExpressibleAsInt(right()) && IsExpressibleAsInt(bottom()); +} + +std::string RectF::ToString() const { + return base::StringPrintf("%s %s", + origin().ToString().c_str(), + size().ToString().c_str()); +} + +RectF IntersectRects(const RectF& a, const RectF& b) { + RectF result = a; + result.Intersect(b); + return result; +} + +RectF UnionRects(const RectF& a, const RectF& b) { + RectF result = a; + result.Union(b); + return result; +} + +RectF SubtractRects(const RectF& a, const RectF& b) { + RectF result = a; + result.Subtract(b); + return result; +} + +RectF BoundingRect(const PointF& p1, const PointF& p2) { + float rx = std::min(p1.x(), p2.x()); + float ry = std::min(p1.y(), p2.y()); + float rr = std::max(p1.x(), p2.x()); + float rb = std::max(p1.y(), p2.y()); + return RectF(rx, ry, rr - rx, rb - ry); +} + +} // namespace gfx diff --git a/ui/gfx/geometry/rect_f.h b/ui/gfx/geometry/rect_f.h new file mode 100644 index 0000000000..9d99052c4a --- /dev/null +++ b/ui/gfx/geometry/rect_f.h @@ -0,0 +1,242 @@ +// Copyright (c) 2012 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_GEOMETRY_RECT_F_H_ +#define UI_GFX_GEOMETRY_RECT_F_H_ + +#include <iosfwd> +#include <string> + +#include "build/build_config.h" +#include "ui/gfx/geometry/point_f.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size_f.h" +#include "ui/gfx/geometry/vector2d_f.h" + +#if defined(OS_MACOSX) +typedef struct CGRect CGRect; +#endif + +namespace gfx { + +class InsetsF; + +// A floating version of gfx::Rect. +class GFX_EXPORT RectF { + public: + constexpr RectF() = default; + constexpr RectF(float width, float height) : size_(width, height) {} + constexpr RectF(float x, float y, float width, float height) + : origin_(x, y), size_(width, height) {} + constexpr explicit RectF(const SizeF& size) : size_(size) {} + constexpr RectF(const PointF& origin, const SizeF& size) + : origin_(origin), size_(size) {} + + constexpr explicit RectF(const Rect& r) + : RectF(static_cast<float>(r.x()), + static_cast<float>(r.y()), + static_cast<float>(r.width()), + static_cast<float>(r.height())) {} + +#if defined(OS_MACOSX) + explicit RectF(const CGRect& r); + // Construct an equivalent CoreGraphics object. + CGRect ToCGRect() const; +#endif + + constexpr float x() const { return origin_.x(); } + void set_x(float x) { origin_.set_x(x); } + + constexpr float y() const { return origin_.y(); } + void set_y(float y) { origin_.set_y(y); } + + constexpr float width() const { return size_.width(); } + void set_width(float width) { size_.set_width(width); } + + constexpr float height() const { return size_.height(); } + void set_height(float height) { size_.set_height(height); } + + constexpr const PointF& origin() const { return origin_; } + void set_origin(const PointF& origin) { origin_ = origin; } + + constexpr const SizeF& size() const { return size_; } + void set_size(const SizeF& size) { size_ = size; } + + constexpr float right() const { return x() + width(); } + constexpr float bottom() const { return y() + height(); } + + constexpr PointF top_right() const { return PointF(right(), y()); } + constexpr PointF bottom_left() const { return PointF(x(), bottom()); } + constexpr PointF bottom_right() const { return PointF(right(), bottom()); } + + Vector2dF OffsetFromOrigin() const { return Vector2dF(x(), y()); } + + void SetRect(float x, float y, float width, float height) { + origin_.SetPoint(x, y); + size_.SetSize(width, height); + } + + // Shrink the rectangle by a horizontal and vertical distance on all sides. + void Inset(float horizontal, float vertical) { + Inset(horizontal, vertical, horizontal, vertical); + } + + // Shrink the rectangle by the given insets. + void Inset(const InsetsF& insets); + + // Shrink the rectangle by the specified amount on each side. + void Inset(float left, float top, float right, float bottom); + + // Move the rectangle by a horizontal and vertical distance. + void Offset(float horizontal, float vertical); + void Offset(const Vector2dF& distance) { Offset(distance.x(), distance.y()); } + void operator+=(const Vector2dF& offset); + void operator-=(const Vector2dF& offset); + + InsetsF InsetsFrom(const RectF& inner) const; + + // Returns true if the area of the rectangle is zero. + bool IsEmpty() const { return size_.IsEmpty(); } + + // A rect is less than another rect if its origin is less than + // the other rect's origin. If the origins are equal, then the + // shortest rect is less than the other. If the origin and the + // height are equal, then the narrowest rect is less than. + // This comparison is required to use Rects in sets, or sorted + // vectors. + bool operator<(const RectF& other) const; + + // Returns true if the point identified by point_x and point_y falls inside + // this rectangle. The point (x, y) is inside the rectangle, but the + // point (x + width, y + height) is not. + bool Contains(float point_x, float point_y) const; + + // Returns true if the specified point is contained by this rectangle. + bool Contains(const PointF& point) const { + return Contains(point.x(), point.y()); + } + + // Returns true if this rectangle contains the specified rectangle. + bool Contains(const RectF& rect) const; + + // Returns true if this rectangle intersects the specified rectangle. + // An empty rectangle doesn't intersect any rectangle. + bool Intersects(const RectF& rect) const; + + // Computes the intersection of this rectangle with the given rectangle. + void Intersect(const RectF& rect); + + // Computes the union of this rectangle with the given rectangle. The union + // is the smallest rectangle containing both rectangles. + void Union(const RectF& rect); + + // Computes the rectangle resulting from subtracting |rect| from |*this|, + // i.e. the bounding rect of |Region(*this) - Region(rect)|. + void Subtract(const RectF& rect); + + // Fits as much of the receiving rectangle into the supplied rectangle as + // possible, becoming the result. For example, if the receiver had + // a x-location of 2 and a width of 4, and the supplied rectangle had + // an x-location of 0 with a width of 5, the returned rectangle would have + // an x-location of 1 with a width of 4. + void AdjustToFit(const RectF& rect); + + // Returns the center of this rectangle. + PointF CenterPoint() const; + + // Becomes a rectangle that has the same center point but with a size capped + // at given |size|. + void ClampToCenteredSize(const SizeF& size); + + // Splits |this| in two halves, |left_half| and |right_half|. + void SplitVertically(RectF* left_half, RectF* right_half) const; + + // Returns true if this rectangle shares an entire edge (i.e., same width or + // same height) with the given rectangle, and the rectangles do not overlap. + bool SharesEdgeWith(const RectF& rect) const; + + // Returns the manhattan distance from the rect to the point. If the point is + // inside the rect, returns 0. + float ManhattanDistanceToPoint(const PointF& point) const; + + // Returns the manhattan distance between the contents of this rect and the + // contents of the given rect. That is, if the intersection of the two rects + // is non-empty then the function returns 0. If the rects share a side, it + // returns the smallest non-zero value appropriate for float. + float ManhattanInternalDistance(const RectF& rect) const; + + // Scales the rectangle by |scale|. + void Scale(float scale) { + Scale(scale, scale); + } + + void Scale(float x_scale, float y_scale) { + set_origin(ScalePoint(origin(), x_scale, y_scale)); + set_size(ScaleSize(size(), x_scale, y_scale)); + } + + // This method reports if the RectF can be safely converted to an integer + // Rect. When it is false, some dimension of the RectF is outside the bounds + // of what an integer can represent, and converting it to a Rect will require + // clamping. + bool IsExpressibleAsRect() const; + + std::string ToString() const; + + private: + PointF origin_; + SizeF size_; +}; + +inline bool operator==(const RectF& lhs, const RectF& rhs) { + return lhs.origin() == rhs.origin() && lhs.size() == rhs.size(); +} + +inline bool operator!=(const RectF& lhs, const RectF& rhs) { + return !(lhs == rhs); +} + +inline RectF operator+(const RectF& lhs, const Vector2dF& rhs) { + return RectF(lhs.x() + rhs.x(), lhs.y() + rhs.y(), + lhs.width(), lhs.height()); +} + +inline RectF operator-(const RectF& lhs, const Vector2dF& rhs) { + return RectF(lhs.x() - rhs.x(), lhs.y() - rhs.y(), + lhs.width(), lhs.height()); +} + +inline RectF operator+(const Vector2dF& lhs, const RectF& rhs) { + return rhs + lhs; +} + +GFX_EXPORT RectF IntersectRects(const RectF& a, const RectF& b); +GFX_EXPORT RectF UnionRects(const RectF& a, const RectF& b); +GFX_EXPORT RectF SubtractRects(const RectF& a, const RectF& b); + +inline RectF ScaleRect(const RectF& r, float x_scale, float y_scale) { + return RectF(r.x() * x_scale, r.y() * y_scale, + r.width() * x_scale, r.height() * y_scale); +} + +inline RectF ScaleRect(const RectF& r, float scale) { + return ScaleRect(r, scale, scale); +} + +// Constructs a rectangle with |p1| and |p2| as opposite corners. +// +// This could also be thought of as "the smallest rect that contains both +// points", except that we consider points on the right/bottom edges of the +// rect to be outside the rect. So technically one or both points will not be +// contained within the rect, because they will appear on one of these edges. +GFX_EXPORT RectF BoundingRect(const PointF& p1, const PointF& p2); + +// This is declared here for use in gtest-based unit tests but is defined in +// the //ui/gfx:test_support target. Depend on that to use this in your unit +// test. This should not be used in production code - call ToString() instead. +void PrintTo(const RectF& rect, ::std::ostream* os); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_RECT_F_H_ diff --git a/ui/gfx/geometry/safe_integer_conversions.h b/ui/gfx/geometry/safe_integer_conversions.h new file mode 100644 index 0000000000..5efe134f07 --- /dev/null +++ b/ui/gfx/geometry/safe_integer_conversions.h @@ -0,0 +1,62 @@ +// Copyright (c) 2012 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_GEOMETRY_SAFE_INTEGER_CONVERSIONS_H_ +#define UI_GFX_GEOMETRY_SAFE_INTEGER_CONVERSIONS_H_ + +#include <cmath> +#include <limits> + +#include "base/numerics/safe_conversions.h" +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +inline int ToFlooredInt(float value) { + return base::saturated_cast<int>(std::floor(value)); +} + +inline int ToCeiledInt(float value) { + return base::saturated_cast<int>(std::ceil(value)); +} + +inline int ToFlooredInt(double value) { + return base::saturated_cast<int>(std::floor(value)); +} + +inline int ToCeiledInt(double value) { + return base::saturated_cast<int>(std::ceil(value)); +} + +inline int ToRoundedInt(float value) { + float rounded; + if (value >= 0.0f) + rounded = std::floor(value + 0.5f); + else + rounded = std::ceil(value - 0.5f); + return base::saturated_cast<int>(rounded); +} + +inline int ToRoundedInt(double value) { + double rounded; + if (value >= 0.0) + rounded = std::floor(value + 0.5); + else + rounded = std::ceil(value - 0.5); + return base::saturated_cast<int>(rounded); +} + +inline bool IsExpressibleAsInt(float value) { + if (value != value) + return false; // no int NaN. + if (value > std::numeric_limits<int>::max()) + return false; + if (value < std::numeric_limits<int>::min()) + return false; + return true; +} + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_SAFE_INTEGER_CONVERSIONS_H_ diff --git a/ui/gfx/geometry/size.cc b/ui/gfx/geometry/size.cc new file mode 100644 index 0000000000..69486723a1 --- /dev/null +++ b/ui/gfx/geometry/size.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2012 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/gfx/geometry/size.h" + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(OS_IOS) +#include <CoreGraphics/CoreGraphics.h> +#elif defined(OS_MACOSX) +#include <ApplicationServices/ApplicationServices.h> +#endif + +#include "base/numerics/safe_math.h" +#include "base/numerics/saturated_arithmetic.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "ui/gfx/geometry/safe_integer_conversions.h" +#include "ui/gfx/geometry/size_conversions.h" + +namespace gfx { + +#if defined(OS_MACOSX) +Size::Size(const CGSize& s) + : width_(s.width < 0 ? 0 : s.width), + height_(s.height < 0 ? 0 : s.height) { +} + +Size& Size::operator=(const CGSize& s) { + set_width(s.width); + set_height(s.height); + return *this; +} +#endif + +#if defined(OS_WIN) +SIZE Size::ToSIZE() const { + SIZE s; + s.cx = width(); + s.cy = height(); + return s; +} +#elif defined(OS_MACOSX) +CGSize Size::ToCGSize() const { + return CGSizeMake(width(), height()); +} +#endif + +int Size::GetArea() const { + return GetCheckedArea().ValueOrDie(); +} + +base::CheckedNumeric<int> Size::GetCheckedArea() const { + base::CheckedNumeric<int> checked_area = width(); + checked_area *= height(); + return checked_area; +} + +void Size::Enlarge(int grow_width, int grow_height) { + SetSize(base::SaturatedAddition(width(), grow_width), + base::SaturatedAddition(height(), grow_height)); +} + +void Size::SetToMin(const Size& other) { + width_ = width() <= other.width() ? width() : other.width(); + height_ = height() <= other.height() ? height() : other.height(); +} + +void Size::SetToMax(const Size& other) { + width_ = width() >= other.width() ? width() : other.width(); + height_ = height() >= other.height() ? height() : other.height(); +} + +std::string Size::ToString() const { + return base::StringPrintf("%dx%d", width(), height()); +} + +Size ScaleToCeiledSize(const Size& size, float x_scale, float y_scale) { + if (x_scale == 1.f && y_scale == 1.f) + return size; + return ToCeiledSize(ScaleSize(gfx::SizeF(size), x_scale, y_scale)); +} + +Size ScaleToCeiledSize(const Size& size, float scale) { + if (scale == 1.f) + return size; + return ToCeiledSize(ScaleSize(gfx::SizeF(size), scale, scale)); +} + +Size ScaleToFlooredSize(const Size& size, float x_scale, float y_scale) { + if (x_scale == 1.f && y_scale == 1.f) + return size; + return ToFlooredSize(ScaleSize(gfx::SizeF(size), x_scale, y_scale)); +} + +Size ScaleToFlooredSize(const Size& size, float scale) { + if (scale == 1.f) + return size; + return ToFlooredSize(ScaleSize(gfx::SizeF(size), scale, scale)); +} + +Size ScaleToRoundedSize(const Size& size, float x_scale, float y_scale) { + if (x_scale == 1.f && y_scale == 1.f) + return size; + return ToRoundedSize(ScaleSize(gfx::SizeF(size), x_scale, y_scale)); +} + +Size ScaleToRoundedSize(const Size& size, float scale) { + if (scale == 1.f) + return size; + return ToRoundedSize(ScaleSize(gfx::SizeF(size), scale, scale)); +} + +} // namespace gfx diff --git a/ui/gfx/geometry/size.h b/ui/gfx/geometry/size.h new file mode 100644 index 0000000000..8ce4178b3c --- /dev/null +++ b/ui/gfx/geometry/size.h @@ -0,0 +1,103 @@ +// Copyright (c) 2012 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_GEOMETRY_SIZE_H_ +#define UI_GFX_GEOMETRY_SIZE_H_ + +#include <iosfwd> +#include <string> + +#include "base/compiler_specific.h" +#include "base/numerics/safe_math.h" +#include "build/build_config.h" +#include "ui/gfx/gfx_export.h" + +#if defined(OS_WIN) +typedef struct tagSIZE SIZE; +#elif defined(OS_MACOSX) +typedef struct CGSize CGSize; +#endif + +namespace gfx { + +// A size has width and height values. +class GFX_EXPORT Size { + public: + constexpr Size() : width_(0), height_(0) {} + constexpr Size(int width, int height) + : width_(width < 0 ? 0 : width), height_(height < 0 ? 0 : height) {} +#if defined(OS_MACOSX) + explicit Size(const CGSize& s); +#endif + +#if defined(OS_MACOSX) + Size& operator=(const CGSize& s); +#endif + +#if defined(OS_WIN) + SIZE ToSIZE() const; +#elif defined(OS_MACOSX) + CGSize ToCGSize() const; +#endif + + constexpr int width() const { return width_; } + constexpr int height() const { return height_; } + + void set_width(int width) { width_ = width < 0 ? 0 : width; } + void set_height(int height) { height_ = height < 0 ? 0 : height; } + + // This call will CHECK if the area of this size would overflow int. + int GetArea() const; + // Returns a checked numeric representation of the area. + base::CheckedNumeric<int> GetCheckedArea() const; + + void SetSize(int width, int height) { + set_width(width); + set_height(height); + } + + void Enlarge(int grow_width, int grow_height); + + void SetToMin(const Size& other); + void SetToMax(const Size& other); + + bool IsEmpty() const { return !width() || !height(); } + + std::string ToString() const; + + private: + int width_; + int height_; +}; + +inline bool operator==(const Size& lhs, const Size& rhs) { + return lhs.width() == rhs.width() && lhs.height() == rhs.height(); +} + +inline bool operator!=(const Size& lhs, const Size& rhs) { + return !(lhs == rhs); +} + +// This is declared here for use in gtest-based unit tests but is defined in +// the //ui/gfx:test_support target. Depend on that to use this in your unit +// test. This should not be used in production code - call ToString() instead. +void PrintTo(const Size& size, ::std::ostream* os); + +// Helper methods to scale a gfx::Size to a new gfx::Size. +GFX_EXPORT Size ScaleToCeiledSize(const Size& size, + float x_scale, + float y_scale); +GFX_EXPORT Size ScaleToCeiledSize(const Size& size, float scale); +GFX_EXPORT Size ScaleToFlooredSize(const Size& size, + float x_scale, + float y_scale); +GFX_EXPORT Size ScaleToFlooredSize(const Size& size, float scale); +GFX_EXPORT Size ScaleToRoundedSize(const Size& size, + float x_scale, + float y_scale); +GFX_EXPORT Size ScaleToRoundedSize(const Size& size, float scale); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_SIZE_H_ diff --git a/ui/gfx/geometry/size_conversions.cc b/ui/gfx/geometry/size_conversions.cc new file mode 100644 index 0000000000..c924e86c9a --- /dev/null +++ b/ui/gfx/geometry/size_conversions.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2012 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/gfx/geometry/size_conversions.h" + +#include "ui/gfx/geometry/safe_integer_conversions.h" + +namespace gfx { + +Size ToFlooredSize(const SizeF& size) { + int w = ToFlooredInt(size.width()); + int h = ToFlooredInt(size.height()); + return Size(w, h); +} + +Size ToCeiledSize(const SizeF& size) { + int w = ToCeiledInt(size.width()); + int h = ToCeiledInt(size.height()); + return Size(w, h); +} + +Size ToRoundedSize(const SizeF& size) { + int w = ToRoundedInt(size.width()); + int h = ToRoundedInt(size.height()); + return Size(w, h); +} + +} // namespace gfx + diff --git a/ui/gfx/geometry/size_conversions.h b/ui/gfx/geometry/size_conversions.h new file mode 100644 index 0000000000..96fb79f93c --- /dev/null +++ b/ui/gfx/geometry/size_conversions.h @@ -0,0 +1,24 @@ +// Copyright (c) 2012 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_GEOMETRY_SIZE_CONVERSIONS_H_ +#define UI_GFX_GEOMETRY_SIZE_CONVERSIONS_H_ + +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/size_f.h" + +namespace gfx { + +// Returns a Size with each component from the input SizeF floored. +GFX_EXPORT Size ToFlooredSize(const SizeF& size); + +// Returns a Size with each component from the input SizeF ceiled. +GFX_EXPORT Size ToCeiledSize(const SizeF& size); + +// Returns a Size with each component from the input SizeF rounded. +GFX_EXPORT Size ToRoundedSize(const SizeF& size); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_SIZE_CONVERSIONS_H_ diff --git a/ui/gfx/geometry/size_f.cc b/ui/gfx/geometry/size_f.cc new file mode 100644 index 0000000000..6d08e18c62 --- /dev/null +++ b/ui/gfx/geometry/size_f.cc @@ -0,0 +1,39 @@ +// Copyright (c) 2012 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/gfx/geometry/size_f.h" + +#include "base/strings/stringprintf.h" + +namespace gfx { + +float SizeF::GetArea() const { + return width() * height(); +} + +void SizeF::Enlarge(float grow_width, float grow_height) { + SetSize(width() + grow_width, height() + grow_height); +} + +void SizeF::SetToMin(const SizeF& other) { + width_ = width() <= other.width() ? width() : other.width(); + height_ = height() <= other.height() ? height() : other.height(); +} + +void SizeF::SetToMax(const SizeF& other) { + width_ = width() >= other.width() ? width() : other.width(); + height_ = height() >= other.height() ? height() : other.height(); +} + +std::string SizeF::ToString() const { + return base::StringPrintf("%fx%f", width(), height()); +} + +SizeF ScaleSize(const SizeF& s, float x_scale, float y_scale) { + SizeF scaled_s(s); + scaled_s.Scale(x_scale, y_scale); + return scaled_s; +} + +} // namespace gfx diff --git a/ui/gfx/geometry/size_f.h b/ui/gfx/geometry/size_f.h new file mode 100644 index 0000000000..0757ef6481 --- /dev/null +++ b/ui/gfx/geometry/size_f.h @@ -0,0 +1,97 @@ +// Copyright (c) 2012 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_GEOMETRY_SIZE_F_H_ +#define UI_GFX_GEOMETRY_SIZE_F_H_ + +#include <iosfwd> +#include <string> + +#include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +FORWARD_DECLARE_TEST(SizeTest, TrivialDimensionTests); +FORWARD_DECLARE_TEST(SizeTest, ClampsToZero); +FORWARD_DECLARE_TEST(SizeTest, ConsistentClamping); + +// A floating version of gfx::Size. +class GFX_EXPORT SizeF { + public: + constexpr SizeF() : width_(0.f), height_(0.f) {} + constexpr SizeF(float width, float height) + : width_(clamp(width)), height_(clamp(height)) {} + + constexpr explicit SizeF(const Size& size) + : SizeF(static_cast<float>(size.width()), + static_cast<float>(size.height())) {} + + constexpr float width() const { return width_; } + constexpr float height() const { return height_; } + + void set_width(float width) { width_ = clamp(width); } + void set_height(float height) { height_ = clamp(height); } + + float GetArea() const; + + void SetSize(float width, float height) { + set_width(width); + set_height(height); + } + + void Enlarge(float grow_width, float grow_height); + + void SetToMin(const SizeF& other); + void SetToMax(const SizeF& other); + + bool IsEmpty() const { return !width() || !height(); } + + void Scale(float scale) { + Scale(scale, scale); + } + + void Scale(float x_scale, float y_scale) { + SetSize(width() * x_scale, height() * y_scale); + } + + std::string ToString() const; + + private: + FRIEND_TEST_ALL_PREFIXES(SizeTest, TrivialDimensionTests); + FRIEND_TEST_ALL_PREFIXES(SizeTest, ClampsToZero); + FRIEND_TEST_ALL_PREFIXES(SizeTest, ConsistentClamping); + + static constexpr float kTrivial = 8.f * std::numeric_limits<float>::epsilon(); + + static constexpr float clamp(float f) { return f > kTrivial ? f : 0.f; } + + float width_; + float height_; +}; + +inline bool operator==(const SizeF& lhs, const SizeF& rhs) { + return lhs.width() == rhs.width() && lhs.height() == rhs.height(); +} + +inline bool operator!=(const SizeF& lhs, const SizeF& rhs) { + return !(lhs == rhs); +} + +GFX_EXPORT SizeF ScaleSize(const SizeF& p, float x_scale, float y_scale); + +inline SizeF ScaleSize(const SizeF& p, float scale) { + return ScaleSize(p, scale, scale); +} + +// This is declared here for use in gtest-based unit tests but is defined in +// the //ui/gfx:test_support target. Depend on that to use this in your unit +// test. This should not be used in production code - call ToString() instead. +void PrintTo(const SizeF& size, ::std::ostream* os); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_SIZE_F_H_ diff --git a/ui/gfx/geometry/vector2d.cc b/ui/gfx/geometry/vector2d.cc new file mode 100644 index 0000000000..2b4875c39c --- /dev/null +++ b/ui/gfx/geometry/vector2d.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2012 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/gfx/geometry/vector2d.h" + +#include <cmath> + +#include "base/numerics/saturated_arithmetic.h" +#include "base/strings/stringprintf.h" + +namespace gfx { + +bool Vector2d::IsZero() const { + return x_ == 0 && y_ == 0; +} + +void Vector2d::Add(const Vector2d& other) { + x_ = base::SaturatedAddition(other.x_, x_); + y_ = base::SaturatedAddition(other.y_, y_); +} + +void Vector2d::Subtract(const Vector2d& other) { + x_ = base::SaturatedSubtraction(x_, other.x_); + y_ = base::SaturatedSubtraction(y_, other.y_); +} + +int64_t Vector2d::LengthSquared() const { + return static_cast<int64_t>(x_) * x_ + static_cast<int64_t>(y_) * y_; +} + +float Vector2d::Length() const { + return static_cast<float>(std::sqrt(static_cast<double>(LengthSquared()))); +} + +std::string Vector2d::ToString() const { + return base::StringPrintf("[%d %d]", x_, y_); +} + +} // namespace gfx diff --git a/ui/gfx/geometry/vector2d.h b/ui/gfx/geometry/vector2d.h new file mode 100644 index 0000000000..4b45667adf --- /dev/null +++ b/ui/gfx/geometry/vector2d.h @@ -0,0 +1,100 @@ +// Copyright (c) 2012 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. + +// Defines a simple integer vector class. This class is used to indicate a +// distance in two dimensions between two points. Subtracting two points should +// produce a vector, and adding a vector to a point produces the point at the +// vector's distance from the original point. + +#ifndef UI_GFX_GEOMETRY_VECTOR2D_H_ +#define UI_GFX_GEOMETRY_VECTOR2D_H_ + +#include <stdint.h> + +#include <iosfwd> +#include <string> + +#include "ui/gfx/geometry/vector2d_f.h" +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +class GFX_EXPORT Vector2d { + public: + constexpr Vector2d() : x_(0), y_(0) {} + constexpr Vector2d(int x, int y) : x_(x), y_(y) {} + + constexpr int x() const { return x_; } + void set_x(int x) { x_ = x; } + + constexpr int y() const { return y_; } + void set_y(int y) { y_ = y; } + + // True if both components of the vector are 0. + bool IsZero() const; + + // Add the components of the |other| vector to the current vector. + void Add(const Vector2d& other); + // Subtract the components of the |other| vector from the current vector. + void Subtract(const Vector2d& other); + + void operator+=(const Vector2d& other) { Add(other); } + void operator-=(const Vector2d& other) { Subtract(other); } + + void SetToMin(const Vector2d& other) { + x_ = x_ <= other.x_ ? x_ : other.x_; + y_ = y_ <= other.y_ ? y_ : other.y_; + } + + void SetToMax(const Vector2d& other) { + x_ = x_ >= other.x_ ? x_ : other.x_; + y_ = y_ >= other.y_ ? y_ : other.y_; + } + + // Gives the square of the diagonal length of the vector. Since this is + // cheaper to compute than Length(), it is useful when you want to compare + // relative lengths of different vectors without needing the actual lengths. + int64_t LengthSquared() const; + // Gives the diagonal length of the vector. + float Length() const; + + std::string ToString() const; + + operator Vector2dF() const { + return Vector2dF(static_cast<float>(x()), static_cast<float>(y())); + } + + private: + int x_; + int y_; +}; + +inline bool operator==(const Vector2d& lhs, const Vector2d& rhs) { + return lhs.x() == rhs.x() && lhs.y() == rhs.y(); +} + +inline Vector2d operator-(const Vector2d& v) { + return Vector2d(-v.x(), -v.y()); +} + +inline Vector2d operator+(const Vector2d& lhs, const Vector2d& rhs) { + Vector2d result = lhs; + result.Add(rhs); + return result; +} + +inline Vector2d operator-(const Vector2d& lhs, const Vector2d& rhs) { + Vector2d result = lhs; + result.Add(-rhs); + return result; +} + +// This is declared here for use in gtest-based unit tests but is defined in +// the //ui/gfx:test_support target. Depend on that to use this in your unit +// test. This should not be used in production code - call ToString() instead. +void PrintTo(const Vector2d& vector, ::std::ostream* os); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_VECTOR2D_H_ diff --git a/ui/gfx/geometry/vector2d_f.cc b/ui/gfx/geometry/vector2d_f.cc new file mode 100644 index 0000000000..ccb15ae0c4 --- /dev/null +++ b/ui/gfx/geometry/vector2d_f.cc @@ -0,0 +1,60 @@ +// Copyright (c) 2012 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/gfx/geometry/vector2d_f.h" + +#include <cmath> + +#include "base/strings/stringprintf.h" + +namespace gfx { + +std::string Vector2dF::ToString() const { + return base::StringPrintf("[%f %f]", x_, y_); +} + +bool Vector2dF::IsZero() const { + return x_ == 0 && y_ == 0; +} + +void Vector2dF::Add(const Vector2dF& other) { + x_ += other.x_; + y_ += other.y_; +} + +void Vector2dF::Subtract(const Vector2dF& other) { + x_ -= other.x_; + y_ -= other.y_; +} + +double Vector2dF::LengthSquared() const { + return static_cast<double>(x_) * x_ + static_cast<double>(y_) * y_; +} + +float Vector2dF::Length() const { + return static_cast<float>(std::sqrt(LengthSquared())); +} + +void Vector2dF::Scale(float x_scale, float y_scale) { + x_ *= x_scale; + y_ *= y_scale; +} + +double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs) { + return static_cast<double>(lhs.x()) * rhs.y() - + static_cast<double>(lhs.y()) * rhs.x(); +} + +double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs) { + return static_cast<double>(lhs.x()) * rhs.x() + + static_cast<double>(lhs.y()) * rhs.y(); +} + +Vector2dF ScaleVector2d(const Vector2dF& v, float x_scale, float y_scale) { + Vector2dF scaled_v(v); + scaled_v.Scale(x_scale, y_scale); + return scaled_v; +} + +} // namespace gfx diff --git a/ui/gfx/geometry/vector2d_f.h b/ui/gfx/geometry/vector2d_f.h new file mode 100644 index 0000000000..92f7f87753 --- /dev/null +++ b/ui/gfx/geometry/vector2d_f.h @@ -0,0 +1,118 @@ +// Copyright (c) 2012 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. + +// Defines a simple float vector class. This class is used to indicate a +// distance in two dimensions between two points. Subtracting two points should +// produce a vector, and adding a vector to a point produces the point at the +// vector's distance from the original point. + +#ifndef UI_GFX_GEOMETRY_VECTOR2D_F_H_ +#define UI_GFX_GEOMETRY_VECTOR2D_F_H_ + +#include <iosfwd> +#include <string> + +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +class GFX_EXPORT Vector2dF { + public: + constexpr Vector2dF() : x_(0), y_(0) {} + constexpr Vector2dF(float x, float y) : x_(x), y_(y) {} + + constexpr float x() const { return x_; } + void set_x(float x) { x_ = x; } + + constexpr float y() const { return y_; } + void set_y(float y) { y_ = y; } + + // True if both components of the vector are 0. + bool IsZero() const; + + // Add the components of the |other| vector to the current vector. + void Add(const Vector2dF& other); + // Subtract the components of the |other| vector from the current vector. + void Subtract(const Vector2dF& other); + + void operator+=(const Vector2dF& other) { Add(other); } + void operator-=(const Vector2dF& other) { Subtract(other); } + + void SetToMin(const Vector2dF& other) { + x_ = x_ <= other.x_ ? x_ : other.x_; + y_ = y_ <= other.y_ ? y_ : other.y_; + } + + void SetToMax(const Vector2dF& other) { + x_ = x_ >= other.x_ ? x_ : other.x_; + y_ = y_ >= other.y_ ? y_ : other.y_; + } + + // Gives the square of the diagonal length of the vector. + double LengthSquared() const; + // Gives the diagonal length of the vector. + float Length() const; + + // Scale the x and y components of the vector by |scale|. + void Scale(float scale) { Scale(scale, scale); } + // Scale the x and y components of the vector by |x_scale| and |y_scale| + // respectively. + void Scale(float x_scale, float y_scale); + + std::string ToString() const; + + private: + float x_; + float y_; +}; + +inline bool operator==(const Vector2dF& lhs, const Vector2dF& rhs) { + return lhs.x() == rhs.x() && lhs.y() == rhs.y(); +} + +inline bool operator!=(const Vector2dF& lhs, const Vector2dF& rhs) { + return !(lhs == rhs); +} + +inline Vector2dF operator-(const Vector2dF& v) { + return Vector2dF(-v.x(), -v.y()); +} + +inline Vector2dF operator+(const Vector2dF& lhs, const Vector2dF& rhs) { + Vector2dF result = lhs; + result.Add(rhs); + return result; +} + +inline Vector2dF operator-(const Vector2dF& lhs, const Vector2dF& rhs) { + Vector2dF result = lhs; + result.Add(-rhs); + return result; +} + +// Return the cross product of two vectors. +GFX_EXPORT double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs); + +// Return the dot product of two vectors. +GFX_EXPORT double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs); + +// Return a vector that is |v| scaled by the given scale factors along each +// axis. +GFX_EXPORT Vector2dF ScaleVector2d(const Vector2dF& v, + float x_scale, + float y_scale); + +// Return a vector that is |v| scaled by the given scale factor. +inline Vector2dF ScaleVector2d(const Vector2dF& v, float scale) { + return ScaleVector2d(v, scale, scale); +} + +// This is declared here for use in gtest-based unit tests but is defined in +// the //ui/gfx:test_support target. Depend on that to use this in your unit +// test. This should not be used in production code - call ToString() instead. +void PrintTo(const Vector2dF& vector, ::std::ostream* os); + +} // namespace gfx + +#endif // UI_GFX_GEOMETRY_VECTOR2D_F_H_ diff --git a/ui/gfx/gfx_export.h b/ui/gfx/gfx_export.h new file mode 100644 index 0000000000..20c8bb1681 --- /dev/null +++ b/ui/gfx/gfx_export.h @@ -0,0 +1,29 @@ +// Copyright (c) 2013 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_GFX_EXPORT_H_ +#define UI_GFX_GFX_EXPORT_H_ + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(GFX_IMPLEMENTATION) +#define GFX_EXPORT __declspec(dllexport) +#else +#define GFX_EXPORT __declspec(dllimport) +#endif // defined(GFX_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(GFX_IMPLEMENTATION) +#define GFX_EXPORT __attribute__((visibility("default"))) +#else +#define GFX_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define GFX_EXPORT +#endif + +#endif // UI_GFX_GFX_EXPORT_H_ diff --git a/ui/gfx/range/BUILD.gn b/ui/gfx/range/BUILD.gn new file mode 100644 index 0000000000..0a8d8b2338 --- /dev/null +++ b/ui/gfx/range/BUILD.gn @@ -0,0 +1,33 @@ +# Copyright 2016 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. + +component("range") { + sources = [ + "gfx_range_export.h", + "range.cc", + "range.h", + "range_f.cc", + "range_f.h", + "range_mac.mm", + "range_win.cc", + ] + + if (is_ios) { + set_sources_assignment_filter([]) + sources += [ "range_mac.mm" ] + set_sources_assignment_filter(sources_assignment_filter) + } + + configs += [ + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + "//build/config/compiler:no_size_t_to_int_warning", + ] + + defines = [ "GFX_RANGE_IMPLEMENTATION" ] + + deps = [ + "//base", + "//ui/gfx:gfx_export", + ] +} diff --git a/ui/gfx/range/gfx_range_export.h b/ui/gfx/range/gfx_range_export.h new file mode 100644 index 0000000000..5634c49770 --- /dev/null +++ b/ui/gfx/range/gfx_range_export.h @@ -0,0 +1,29 @@ +// Copyright 2016 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 GFX_RANGE_EXPORT_H_ +#define GFX_RANGE_EXPORT_H_ + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(GFX_RANGE_IMPLEMENTATION) +#define GFX_RANGE_EXPORT __declspec(dllexport) +#else +#define GFX_RANGE_EXPORT __declspec(dllimport) +#endif // defined(GFX_RANGE_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(GFX_RANGE_IMPLEMENTATION) +#define GFX_RANGE_EXPORT __attribute__((visibility("default"))) +#else +#define GFX_RANGE_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define GFX_RANGE_EXPORT +#endif + +#endif // GFX_RANGE_EXPORT_H_ diff --git a/ui/gfx/range/range.cc b/ui/gfx/range/range.cc new file mode 100644 index 0000000000..fa837d0070 --- /dev/null +++ b/ui/gfx/range/range.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2012 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/gfx/range/range.h" + +#include <inttypes.h> + +#include <algorithm> + +#include "base/logging.h" +#include "base/strings/stringprintf.h" + +namespace gfx { + +Range Range::Intersect(const Range& range) const { + uint32_t min = std::max(GetMin(), range.GetMin()); + uint32_t max = std::min(GetMax(), range.GetMax()); + + if (min >= max) // No intersection. + return InvalidRange(); + + return Range(min, max); +} + +std::string Range::ToString() const { + return base::StringPrintf("{%" PRIu32 ",%" PRIu32 "}", start(), end()); +} + +std::ostream& operator<<(std::ostream& os, const Range& range) { + return os << range.ToString(); +} + +} // namespace gfx diff --git a/ui/gfx/range/range.h b/ui/gfx/range/range.h new file mode 100644 index 0000000000..e785eb6c70 --- /dev/null +++ b/ui/gfx/range/range.h @@ -0,0 +1,139 @@ +// Copyright (c) 2012 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_RANGE_H_ +#define UI_GFX_RANGE_RANGE_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <limits> +#include <ostream> +#include <string> + +#include "build/build_config.h" +#include "ui/gfx/range/gfx_range_export.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 gfx { + +// 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 GFX_RANGE_EXPORT Range { + public: + // Creates an empty range {0,0}. + constexpr Range() : Range(0) {} + + // Initializes the range with a start and end. + constexpr Range(uint32_t start, uint32_t end) : start_(start), end_(end) {} + + // Initializes the range with the same start and end positions. + constexpr explicit Range(uint32_t position) : Range(position, 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 {UINT32_MAX,UINT32_MAX}. + static constexpr Range InvalidRange() { + return Range(std::numeric_limits<uint32_t>::max()); + } + + // Checks if the range is valid through comparison to InvalidRange(). + constexpr bool IsValid() const { return *this != InvalidRange(); } + + // Getters and setters. + constexpr uint32_t start() const { return start_; } + void set_start(uint32_t start) { start_ = start; } + + constexpr uint32_t end() const { return end_; } + void set_end(uint32_t end) { end_ = end; } + + // Returns the absolute value of the length. + constexpr uint32_t length() const { return GetMax() - GetMin(); } + + constexpr bool is_reversed() const { return start() > end(); } + constexpr bool is_empty() const { return start() == end(); } + + // Returns the minimum and maximum values. + constexpr uint32_t GetMin() const { + return start() < end() ? start() : end(); + } + constexpr uint32_t GetMax() const { + return start() > end() ? start() : end(); + } + + constexpr bool operator==(const Range& other) const { + return start() == other.start() && end() == other.end(); + } + constexpr bool operator!=(const Range& other) const { + return !(*this == other); + } + constexpr bool EqualsIgnoringDirection(const Range& other) const { + return GetMin() == other.GetMin() && GetMax() == other.GetMax(); + } + + // Returns true if this range intersects the specified |range|. + constexpr bool Intersects(const Range& range) const { + return IsValid() && range.IsValid() && + !(range.GetMax() < GetMin() || range.GetMin() >= GetMax()); + } + + // Returns true if this range contains the specified |range|. + constexpr bool Contains(const Range& range) const { + return IsValid() && range.IsValid() && GetMin() <= range.GetMin() && + range.GetMax() <= GetMax(); + } + + // Computes the intersection of this range with the given |range|. + // If they don't intersect, it returns an InvalidRange(). + // The returned range is always empty or forward (never reversed). + Range Intersect(const Range& range) 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. + + std::string ToString() const; + + private: + // Note: we use uint32_t instead of size_t because this struct is sent over + // IPC which could span 32 & 64 bit processes. This is fine since text spans + // shouldn't exceed UINT32_MAX even on 64 bit builds. + uint32_t start_; + uint32_t end_; +}; + +GFX_RANGE_EXPORT std::ostream& operator<<(std::ostream& os, const Range& range); + +} // namespace gfx + +#endif // UI_GFX_RANGE_RANGE_H_ diff --git a/ui/gfx/range/range_f.cc b/ui/gfx/range/range_f.cc new file mode 100644 index 0000000000..b3bfc69569 --- /dev/null +++ b/ui/gfx/range/range_f.cc @@ -0,0 +1,58 @@ +// Copyright 2015 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/gfx/range/range_f.h" + +#include <stddef.h> + +#include <algorithm> +#include <cmath> + +#include "base/format_macros.h" +#include "base/strings/stringprintf.h" + +namespace gfx { + +RangeF RangeF::Intersect(const RangeF& range) const { + float min = std::max(GetMin(), range.GetMin()); + float max = std::min(GetMax(), range.GetMax()); + + if (min >= max) // No intersection. + return InvalidRange(); + + return RangeF(min, max); +} + +RangeF RangeF::Intersect(const Range& range) const { + RangeF range_f(range.start(), range.end()); + return Intersect(range_f); +} + +Range RangeF::Floor() const { + uint32_t start = start_ > 0 ? static_cast<uint32_t>(std::floor(start_)) : 0; + uint32_t end = end_ > 0 ? static_cast<uint32_t>(std::floor(end_)) : 0; + return Range(start, end); +} + +Range RangeF::Ceil() const { + uint32_t start = start_ > 0 ? static_cast<uint32_t>(std::ceil(start_)) : 0; + uint32_t end = end_ > 0 ? static_cast<uint32_t>(std::ceil(end_)) : 0; + return Range(start, end); +} + +Range RangeF::Round() const { + uint32_t start = start_ > 0 ? static_cast<uint32_t>(std::round(start_)) : 0; + uint32_t end = end_ > 0 ? static_cast<uint32_t>(std::round(end_)) : 0; + return Range(start, end); +} + +std::string RangeF::ToString() const { + return base::StringPrintf("{%f,%f}", start(), end()); +} + +std::ostream& operator<<(std::ostream& os, const RangeF& range) { + return os << range.ToString(); +} + +} // namespace gfx diff --git a/ui/gfx/range/range_f.h b/ui/gfx/range/range_f.h new file mode 100644 index 0000000000..1d58ad4c9f --- /dev/null +++ b/ui/gfx/range/range_f.h @@ -0,0 +1,101 @@ +// Copyright 2015 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_RANGE_F_H_ +#define UI_GFX_RANGE_RANGE_F_H_ + +#include <limits> +#include <ostream> +#include <string> + +#include "ui/gfx/range/gfx_range_export.h" +#include "ui/gfx/range/range.h" + +namespace gfx { + +// A float version of Range. RangeF is made of a start and end position; when +// they are the same, the range is empty. Note that |start_| can be greater +// than |end_| to respect the directionality of the range. +class GFX_RANGE_EXPORT RangeF { + public: + // Creates an empty range {0,0}. + constexpr RangeF() : RangeF(0.f) {} + + // Initializes the range with a start and end. + constexpr RangeF(float start, float end) : start_(start), end_(end) {} + + // Initializes the range with the same start and end positions. + constexpr explicit RangeF(float position) : RangeF(position, position) {} + + // Returns a range that is invalid, which is {float_max,float_max}. + static constexpr RangeF InvalidRange() { + return RangeF(std::numeric_limits<float>::max()); + } + + // Checks if the range is valid through comparison to InvalidRange(). + constexpr bool IsValid() const { return *this != InvalidRange(); } + + // Getters and setters. + constexpr float start() const { return start_; } + void set_start(float start) { start_ = start; } + + constexpr float end() const { return end_; } + void set_end(float end) { end_ = end; } + + // Returns the absolute value of the length. + constexpr float length() const { return GetMax() - GetMin(); } + + constexpr bool is_reversed() const { return start() > end(); } + constexpr bool is_empty() const { return start() == end(); } + + // Returns the minimum and maximum values. + constexpr float GetMin() const { return start() < end() ? start() : end(); } + constexpr float GetMax() const { return start() > end() ? start() : end(); } + + constexpr bool operator==(const RangeF& other) const { + return start() == other.start() && end() == other.end(); + } + constexpr bool operator!=(const RangeF& other) const { + return !(*this == other); + } + constexpr bool EqualsIgnoringDirection(const RangeF& other) const { + return GetMin() == other.GetMin() && GetMax() == other.GetMax(); + } + + // Returns true if this range intersects the specified |range|. + constexpr bool Intersects(const RangeF& range) const { + return IsValid() && range.IsValid() && + !(range.GetMax() < GetMin() || range.GetMin() >= GetMax()); + } + + // Returns true if this range contains the specified |range|. + constexpr bool Contains(const RangeF& range) const { + return IsValid() && range.IsValid() && GetMin() <= range.GetMin() && + range.GetMax() <= GetMax(); + } + + // Computes the intersection of this range with the given |range|. + // If they don't intersect, it returns an InvalidRange(). + // The returned range is always empty or forward (never reversed). + RangeF Intersect(const RangeF& range) const; + RangeF Intersect(const Range& range) const; + + // Floor/Ceil/Round the start and end values of the given RangeF. + Range Floor() const; + Range Ceil() const; + Range Round() const; + + std::string ToString() const; + + private: + float start_; + float end_; +}; + +GFX_RANGE_EXPORT std::ostream& operator<<(std::ostream& os, + const RangeF& range); + +} // namespace gfx + +#endif // UI_GFX_RANGE_RANGE_F_H_ diff --git a/ui/gfx/range/range_unittest.cc b/ui/gfx/range/range_unittest.cc new file mode 100644 index 0000000000..4ae7a67c4f --- /dev/null +++ b/ui/gfx/range/range_unittest.cc @@ -0,0 +1,266 @@ +// 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 <sstream> + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/range/range.h" +#include "ui/gfx/range/range_f.h" + +namespace { + +template <typename T> +class RangeTest : public testing::Test { +}; + +typedef testing::Types<gfx::Range, gfx::RangeF> RangeTypes; +TYPED_TEST_CASE(RangeTest, RangeTypes); + +template <typename T> +void TestContainsAndIntersects(const T& r1, + const T& r2, + const T& r3) { + EXPECT_TRUE(r1.Intersects(r1)); + EXPECT_TRUE(r1.Contains(r1)); + EXPECT_EQ(T(10, 12), r1.Intersect(r1)); + + EXPECT_FALSE(r1.Intersects(r2)); + EXPECT_FALSE(r1.Contains(r2)); + EXPECT_TRUE(r1.Intersect(r2).is_empty()); + EXPECT_FALSE(r2.Intersects(r1)); + EXPECT_FALSE(r2.Contains(r1)); + EXPECT_TRUE(r2.Intersect(r1).is_empty()); + + EXPECT_TRUE(r1.Intersects(r3)); + EXPECT_TRUE(r3.Intersects(r1)); + EXPECT_TRUE(r3.Contains(r1)); + EXPECT_FALSE(r1.Contains(r3)); + EXPECT_EQ(T(10, 12), r1.Intersect(r3)); + EXPECT_EQ(T(10, 12), r3.Intersect(r1)); + + EXPECT_TRUE(r2.Intersects(r3)); + EXPECT_TRUE(r3.Intersects(r2)); + EXPECT_FALSE(r3.Contains(r2)); + EXPECT_FALSE(r2.Contains(r3)); + EXPECT_EQ(T(5, 8), r2.Intersect(r3)); + EXPECT_EQ(T(5, 8), r3.Intersect(r2)); +} + +} // namespace + +TYPED_TEST(RangeTest, EmptyInit) { + TypeParam 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()); +} + +TYPED_TEST(RangeTest, StartEndInit) { + TypeParam 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()); +} + +TYPED_TEST(RangeTest, StartEndReversedInit) { + TypeParam 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()); +} + +TYPED_TEST(RangeTest, PositionInit) { + TypeParam 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()); +} + +TYPED_TEST(RangeTest, InvalidRange) { + TypeParam r(TypeParam::InvalidRange()); + EXPECT_EQ(0U, r.length()); + EXPECT_EQ(r.start(), r.end()); + EXPECT_EQ(r.GetMax(), r.GetMin()); + EXPECT_FALSE(r.is_reversed()); + EXPECT_TRUE(r.is_empty()); + EXPECT_FALSE(r.IsValid()); + EXPECT_EQ(r, TypeParam::InvalidRange()); + EXPECT_TRUE(r.EqualsIgnoringDirection(TypeParam::InvalidRange())); +} + +TYPED_TEST(RangeTest, Equality) { + TypeParam r1(10, 4); + TypeParam r2(10, 4); + TypeParam r3(10, 2); + EXPECT_EQ(r1, r2); + EXPECT_NE(r1, r3); + EXPECT_NE(r2, r3); + + TypeParam r4(11, 4); + EXPECT_NE(r1, r4); + EXPECT_NE(r2, r4); + EXPECT_NE(r3, r4); + + TypeParam r5(12, 5); + EXPECT_NE(r1, r5); + EXPECT_NE(r2, r5); + EXPECT_NE(r3, r5); +} + +TYPED_TEST(RangeTest, EqualsIgnoringDirection) { + TypeParam r1(10, 5); + TypeParam r2(5, 10); + EXPECT_TRUE(r1.EqualsIgnoringDirection(r2)); +} + +TYPED_TEST(RangeTest, SetStart) { + TypeParam 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()); +} + +TYPED_TEST(RangeTest, SetEnd) { + TypeParam 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()); +} + +TYPED_TEST(RangeTest, SetStartAndEnd) { + TypeParam 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()); +} + +TYPED_TEST(RangeTest, ReversedRange) { + TypeParam 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()); +} + +TYPED_TEST(RangeTest, SetReversedRange) { + TypeParam 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()); +} + +TYPED_TEST(RangeTest, ContainAndIntersect) { + { + SCOPED_TRACE("contain and intersect"); + TypeParam r1(10, 12); + TypeParam r2(1, 8); + TypeParam r3(5, 12); + TestContainsAndIntersects(r1, r2, r3); + } + { + SCOPED_TRACE("contain and intersect: reversed"); + TypeParam r1(12, 10); + TypeParam r2(8, 1); + TypeParam r3(12, 5); + TestContainsAndIntersects(r1, r2, r3); + } + // Invalid rect tests + TypeParam r1(10, 12); + TypeParam r2(8, 1); + TypeParam invalid = r1.Intersect(r2); + EXPECT_FALSE(invalid.IsValid()); + EXPECT_FALSE(invalid.Contains(invalid)); + EXPECT_FALSE(invalid.Contains(r1)); + EXPECT_FALSE(invalid.Intersects(invalid)); + EXPECT_FALSE(invalid.Intersects(r1)); + EXPECT_FALSE(r1.Contains(invalid)); + EXPECT_FALSE(r1.Intersects(invalid)); +} + +TEST(RangeTest, RangeFConverterTest) { + gfx::RangeF range_f(1.2f, 3.9f); + gfx::Range range = range_f.Floor(); + EXPECT_EQ(1U, range.start()); + EXPECT_EQ(3U, range.end()); + + range = range_f.Ceil(); + EXPECT_EQ(2U, range.start()); + EXPECT_EQ(4U, range.end()); + + range = range_f.Round(); + EXPECT_EQ(1U, range.start()); + EXPECT_EQ(4U, range.end()); + + // Test for negative values. + range_f.set_start(-1.2f); + range_f.set_end(-3.8f); + range = range_f.Floor(); + EXPECT_EQ(0U, range.start()); + EXPECT_EQ(0U, range.end()); + + range = range_f.Ceil(); + EXPECT_EQ(0U, range.start()); + EXPECT_EQ(0U, range.end()); + + range = range_f.Round(); + EXPECT_EQ(0U, range.start()); + EXPECT_EQ(0U, range.end()); +} + +TEST(RangeTest, ToString) { + gfx::Range range(4, 7); + EXPECT_EQ("{4,7}", range.ToString()); + + range = gfx::Range::InvalidRange(); + std::ostringstream expected; + expected << "{" << range.start() << "," << range.end() << "}"; + EXPECT_EQ(expected.str(), range.ToString()); +} |