diff options
author | Luis Hector Chavez <lhchavez@google.com> | 2017-12-14 21:17:47 -0800 |
---|---|---|
committer | Luis Hector Chavez <lhchavez@google.com> | 2017-12-18 10:00:00 -0800 |
commit | 2256d987b3a5bffb7da4a7212a2e482d45785957 (patch) | |
tree | 265a4118e7d55b940cce5f0c62ae662e3eba241e | |
parent | 3033949ebb841470a2cb165e8c50c7b413b0417c (diff) | |
download | libmojo-2256d987b3a5bffb7da4a7212a2e482d45785957.tar.gz |
libmojo: Add additional files to support more typemaps
This change adds some more files (in device/ and ui/gfx/) to support
ARC's typemaps.
Bug: 38318511
Test: m
Change-Id: I5b9cb98d7f35b302e0d9605c5cd35c9f745fe07c
61 files changed, 4954 insertions, 2 deletions
@@ -23,6 +23,8 @@ LOCAL_MOJOM_FILES := \ mojo/common/version.mojom \ mojo/public/interfaces/bindings/interface_control_messages.mojom \ mojo/public/interfaces/bindings/pipe_control_messages.mojom \ + ui/gfx/geometry/mojo/geometry.mojom \ + ui/gfx/range/mojo/range.mojom \ # This file was copied from out/Release in a Chrome checkout. # TODO(lhchavez): Generate this file instead of hardcoding it. @@ -72,6 +74,9 @@ LOCAL_SRC_FILES := \ base/trace_event/java_heap_dump_provider_android.cc \ base/trace_event/trace_event_android.cc \ base/unguessable_token.cc \ + device/bluetooth/bluetooth_advertisement.cc \ + device/bluetooth/bluetooth_uuid.cc \ + device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.cc \ ipc/ipc_message.cc \ ipc/ipc_message_attachment.cc \ ipc/ipc_message_attachment_set.cc \ @@ -158,6 +163,20 @@ LOCAL_SRC_FILES := \ mojo/public/cpp/system/buffer.cc \ mojo/public/cpp/system/platform_handle.cc \ mojo/public/cpp/system/watcher.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 \ LOCAL_CFLAGS := \ -Wall \ diff --git a/build_mojom.mk b/build_mojom.mk index 2af9e49..478c79c 100644 --- a/build_mojom.mk +++ b/build_mojom.mk @@ -28,8 +28,10 @@ mojom_bindings_generator_flags := $$(LOCAL_MOJOM_BINDINGS_GENERATOR_FLAGS) # TODO(lhchavez): Generate these files instead of expecting them to be there. mojom_type_mappings := ifneq ($$(LOCAL_MOJOM_TYPE_MAPPINGS),) - mojom_type_mappings := $$(local_path)/$$(LOCAL_MOJOM_TYPE_MAPPINGS) - mojom_bindings_generator_flags += --typemap $$(abspath $$(mojom_type_mappings)) + mojom_type_mappings := \ + $$(foreach mapping,$$(LOCAL_MOJOM_TYPE_MAPPINGS),$$(local_path)/$$(mapping)) + mojom_bindings_generator_flags += \ + $$(foreach path,$$(mojom_type_mappings),--typemap $$(abspath $$(path))) endif diff --git a/device/bluetooth/bluetooth_advertisement.cc b/device/bluetooth/bluetooth_advertisement.cc new file mode 100644 index 0000000..05b0e52 --- /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 0000000..412baa7 --- /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 0000000..6045980 --- /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 0000000..90cc58c --- /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 0000000..b35094d --- /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 0000000..8487f6a --- /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 0000000..2c484c1 --- /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::MakeUnique<base::Value>()) {} + +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 0000000..fdd291a --- /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/ui/gfx/geometry/insets.cc b/ui/gfx/geometry/insets.cc new file mode 100644 index 0000000..9acc6e0 --- /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 0000000..a88bae3 --- /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 0000000..c1bc27e --- /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 0000000..30c2ff2 --- /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/mojo/BUILD.gn b/ui/gfx/geometry/mojo/BUILD.gn new file mode 100644 index 0000000..1fcd39f --- /dev/null +++ b/ui/gfx/geometry/mojo/BUILD.gn @@ -0,0 +1,52 @@ +# 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. + +import("//mojo/public/tools/bindings/mojom.gni") + +# This target does NOT depend on skia. One can depend on this target to avoid +# picking up a dependency on skia. +mojom("mojo") { + sources = [ + "geometry.mojom", + ] + + # TODO(crbug.com/699569): Convert to use the new JS bindings. + use_new_js_bindings = false +} + +mojom("test_interfaces") { + sources = [ + "geometry_traits_test_service.mojom", + ] + + public_deps = [ + ":mojo", + ] +} + +source_set("unit_test") { + testonly = true + + sources = [ + "geometry_struct_traits_unittest.cc", + ] + + deps = [ + ":test_interfaces", + "//base", + "//mojo/public/cpp/bindings", + "//testing/gtest", + "//ui/gfx/geometry", + ] +} + +source_set("struct_traits") { + sources = [ + "geometry_struct_traits.h", + ] + public_deps = [ + ":mojo_shared_cpp_sources", + "//ui/gfx/geometry", + ] +} diff --git a/ui/gfx/geometry/mojo/DEPS b/ui/gfx/geometry/mojo/DEPS new file mode 100644 index 0000000..3ad6543 --- /dev/null +++ b/ui/gfx/geometry/mojo/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+mojo/public", + "+ui/gfx/geometry", +] diff --git a/ui/gfx/geometry/mojo/geometry.mojom b/ui/gfx/geometry/mojo/geometry.mojom new file mode 100644 index 0000000..9714386 --- /dev/null +++ b/ui/gfx/geometry/mojo/geometry.mojom @@ -0,0 +1,63 @@ +// 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. + +module gfx.mojom; + +struct Point { + int32 x; + int32 y; +}; + +struct PointF { + float x; + float y; +}; + +struct Size { + int32 width; + int32 height; +}; + +struct SizeF { + float width; + float height; +}; + +struct Rect { + int32 x; + int32 y; + int32 width; + int32 height; +}; + +struct RectF { + float x; + float y; + float width; + float height; +}; + +struct Insets { + int32 top; + int32 left; + int32 bottom; + int32 right; +}; + +struct InsetsF { + float top; + float left; + float bottom; + float right; +}; + +struct Vector2d { + int32 x; + int32 y; +}; + +struct Vector2dF { + float x; + float y; +}; diff --git a/ui/gfx/geometry/mojo/geometry.typemap b/ui/gfx/geometry/mojo/geometry.typemap new file mode 100644 index 0000000..686ea05 --- /dev/null +++ b/ui/gfx/geometry/mojo/geometry.typemap @@ -0,0 +1,32 @@ +# 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. + +mojom = "//ui/gfx/geometry/mojo/geometry.mojom" +public_headers = [ + "//ui/gfx/geometry/point.h", + "//ui/gfx/geometry/point_f.h", + "//ui/gfx/geometry/size.h", + "//ui/gfx/geometry/rect.h", + "//ui/gfx/geometry/rect_f.h", + "//ui/gfx/geometry/safe_integer_conversions.h", + "//ui/gfx/geometry/insets.h", + "//ui/gfx/geometry/vector2d.h", + "//ui/gfx/geometry/vector2d_f.h", +] +traits_headers = [ "//ui/gfx/geometry/mojo/geometry_struct_traits.h" ] +deps = [ + "//ui/gfx/geometry/mojo:struct_traits", +] +type_mappings = [ + "gfx.mojom.Point=gfx::Point", + "gfx.mojom.PointF=gfx::PointF", + "gfx.mojom.Size=gfx::Size", + "gfx.mojom.SizeF=gfx::SizeF", + "gfx.mojom.Rect=gfx::Rect", + "gfx.mojom.RectF=gfx::RectF", + "gfx.mojom.Insets=gfx::Insets", + "gfx.mojom.InsetsF=gfx::InsetsF", + "gfx.mojom.Vector2d=gfx::Vector2d", + "gfx.mojom.Vector2dF=gfx::Vector2dF", +] diff --git a/ui/gfx/geometry/mojo/geometry_struct_traits.h b/ui/gfx/geometry/mojo/geometry_struct_traits.h new file mode 100644 index 0000000..a31d738 --- /dev/null +++ b/ui/gfx/geometry/mojo/geometry_struct_traits.h @@ -0,0 +1,146 @@ +// 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 UI_GFX_GEOMETRY_MOJO_GEOMETRY_STRUCT_TRAITS_H_ +#define UI_GFX_GEOMETRY_MOJO_GEOMETRY_STRUCT_TRAITS_H_ + +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/insets_f.h" +#include "ui/gfx/geometry/mojo/geometry.mojom-shared.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/point_f.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/size_f.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/geometry/vector2d_f.h" + +namespace mojo { + +template <> +struct StructTraits<gfx::mojom::InsetsDataView, gfx::Insets> { + static int top(const gfx::Insets& p) { return p.top(); } + static int left(const gfx::Insets& p) { return p.left(); } + static int bottom(const gfx::Insets& p) { return p.bottom(); } + static int right(const gfx::Insets& p) { return p.right(); } + static bool Read(gfx::mojom::InsetsDataView data, gfx::Insets* out) { + out->Set(data.top(), data.left(), data.bottom(), data.right()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::InsetsFDataView, gfx::InsetsF> { + static float top(const gfx::InsetsF& p) { return p.top(); } + static float left(const gfx::InsetsF& p) { return p.left(); } + static float bottom(const gfx::InsetsF& p) { return p.bottom(); } + static float right(const gfx::InsetsF& p) { return p.right(); } + static bool Read(gfx::mojom::InsetsFDataView data, gfx::InsetsF* out) { + out->Set(data.top(), data.left(), data.bottom(), data.right()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::PointDataView, gfx::Point> { + static int x(const gfx::Point& p) { return p.x(); } + static int y(const gfx::Point& p) { return p.y(); } + static bool Read(gfx::mojom::PointDataView data, gfx::Point* out) { + out->SetPoint(data.x(), data.y()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::PointFDataView, gfx::PointF> { + static float x(const gfx::PointF& p) { return p.x(); } + static float y(const gfx::PointF& p) { return p.y(); } + static bool Read(gfx::mojom::PointFDataView data, gfx::PointF* out) { + out->SetPoint(data.x(), data.y()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::RectDataView, gfx::Rect> { + static int x(const gfx::Rect& p) { return p.x(); } + static int y(const gfx::Rect& p) { return p.y(); } + static int width(const gfx::Rect& p) { return p.width(); } + static int height(const gfx::Rect& p) { return p.height(); } + static bool Read(gfx::mojom::RectDataView data, gfx::Rect* out) { + if (data.width() < 0 || data.height() < 0) + return false; + + out->SetRect(data.x(), data.y(), data.width(), data.height()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::RectFDataView, gfx::RectF> { + static float x(const gfx::RectF& p) { return p.x(); } + static float y(const gfx::RectF& p) { return p.y(); } + static float width(const gfx::RectF& p) { return p.width(); } + static float height(const gfx::RectF& p) { return p.height(); } + static bool Read(gfx::mojom::RectFDataView data, gfx::RectF* out) { + if (data.width() < 0 || data.height() < 0) + return false; + + out->SetRect(data.x(), data.y(), data.width(), data.height()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::SizeDataView, gfx::Size> { + static int width(const gfx::Size& p) { return p.width(); } + static int height(const gfx::Size& p) { return p.height(); } + static bool Read(gfx::mojom::SizeDataView data, gfx::Size* out) { + if (data.width() < 0 || data.height() < 0) + return false; + + out->SetSize(data.width(), data.height()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::SizeFDataView, gfx::SizeF> { + static float width(const gfx::SizeF& p) { return p.width(); } + static float height(const gfx::SizeF& p) { return p.height(); } + static bool Read(gfx::mojom::SizeFDataView data, gfx::SizeF* out) { + if (data.width() < 0 || data.height() < 0) + return false; + + out->SetSize(data.width(), data.height()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::Vector2dDataView, gfx::Vector2d> { + static int x(const gfx::Vector2d& v) { return v.x(); } + static int y(const gfx::Vector2d& v) { return v.y(); } + static bool Read(gfx::mojom::Vector2dDataView data, gfx::Vector2d* out) { + out->set_x(data.x()); + out->set_y(data.y()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::Vector2dFDataView, gfx::Vector2dF> { + static float x(const gfx::Vector2dF& v) { return v.x(); } + static float y(const gfx::Vector2dF& v) { return v.y(); } + static bool Read(gfx::mojom::Vector2dFDataView data, gfx::Vector2dF* out) { + out->set_x(data.x()); + out->set_y(data.y()); + return true; + } +}; + +} // namespace mojo + +#endif // UI_GFX_GEOMETRY_MOJO_GEOMETRY_STRUCT_TRAITS_H_ diff --git a/ui/gfx/geometry/mojo/geometry_struct_traits_unittest.cc b/ui/gfx/geometry/mojo/geometry_struct_traits_unittest.cc new file mode 100644 index 0000000..2be935b --- /dev/null +++ b/ui/gfx/geometry/mojo/geometry_struct_traits_unittest.cc @@ -0,0 +1,206 @@ +// 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 <utility> + +#include "base/message_loop/message_loop.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/mojo/geometry_traits_test_service.mojom.h" +#include "ui/gfx/geometry/point.h" + +namespace gfx { + +namespace { + +class GeometryStructTraitsTest : public testing::Test, + public mojom::GeometryTraitsTestService { + public: + GeometryStructTraitsTest() {} + + protected: + mojom::GeometryTraitsTestServicePtr GetTraitsTestProxy() { + mojom::GeometryTraitsTestServicePtr proxy; + traits_test_bindings_.AddBinding(this, mojo::MakeRequest(&proxy)); + return proxy; + } + + private: + // GeometryTraitsTestService: + void EchoPoint(const Point& p, EchoPointCallback callback) override { + std::move(callback).Run(p); + } + + void EchoPointF(const PointF& p, EchoPointFCallback callback) override { + std::move(callback).Run(p); + } + + void EchoSize(const Size& s, EchoSizeCallback callback) override { + std::move(callback).Run(s); + } + + void EchoSizeF(const SizeF& s, EchoSizeFCallback callback) override { + std::move(callback).Run(s); + } + + void EchoRect(const Rect& r, EchoRectCallback callback) override { + std::move(callback).Run(r); + } + + void EchoRectF(const RectF& r, EchoRectFCallback callback) override { + std::move(callback).Run(r); + } + + void EchoInsets(const Insets& i, EchoInsetsCallback callback) override { + std::move(callback).Run(i); + } + + void EchoInsetsF(const InsetsF& i, EchoInsetsFCallback callback) override { + std::move(callback).Run(i); + } + + void EchoVector2d(const Vector2d& v, EchoVector2dCallback callback) override { + std::move(callback).Run(v); + } + + void EchoVector2dF(const Vector2dF& v, + EchoVector2dFCallback callback) override { + std::move(callback).Run(v); + } + + base::MessageLoop loop_; + mojo::BindingSet<GeometryTraitsTestService> traits_test_bindings_; + + DISALLOW_COPY_AND_ASSIGN(GeometryStructTraitsTest); +}; + +} // namespace + +TEST_F(GeometryStructTraitsTest, Point) { + const int32_t x = 1234; + const int32_t y = -5678; + gfx::Point input(x, y); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::Point output; + proxy->EchoPoint(input, &output); + EXPECT_EQ(x, output.x()); + EXPECT_EQ(y, output.y()); +} + +TEST_F(GeometryStructTraitsTest, PointF) { + const float x = 1234.5f; + const float y = 6789.6f; + gfx::PointF input(x, y); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::PointF output; + proxy->EchoPointF(input, &output); + EXPECT_EQ(x, output.x()); + EXPECT_EQ(y, output.y()); +} + +TEST_F(GeometryStructTraitsTest, Size) { + const int32_t width = 1234; + const int32_t height = 5678; + gfx::Size input(width, height); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::Size output; + proxy->EchoSize(input, &output); + EXPECT_EQ(width, output.width()); + EXPECT_EQ(height, output.height()); +} + +TEST_F(GeometryStructTraitsTest, SizeF) { + const float width = 1234.5f; + const float height = 6789.6f; + gfx::SizeF input(width, height); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::SizeF output; + proxy->EchoSizeF(input, &output); + EXPECT_EQ(width, output.width()); + EXPECT_EQ(height, output.height()); +} + +TEST_F(GeometryStructTraitsTest, Rect) { + const int32_t x = 1234; + const int32_t y = 5678; + const int32_t width = 4321; + const int32_t height = 8765; + gfx::Rect input(x, y, width, height); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::Rect output; + proxy->EchoRect(input, &output); + EXPECT_EQ(x, output.x()); + EXPECT_EQ(y, output.y()); + EXPECT_EQ(width, output.width()); + EXPECT_EQ(height, output.height()); +} + +TEST_F(GeometryStructTraitsTest, RectF) { + const float x = 1234.1f; + const float y = 5678.2f; + const float width = 4321.3f; + const float height = 8765.4f; + gfx::RectF input(x, y, width, height); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::RectF output; + proxy->EchoRectF(input, &output); + EXPECT_EQ(x, output.x()); + EXPECT_EQ(y, output.y()); + EXPECT_EQ(width, output.width()); + EXPECT_EQ(height, output.height()); +} + +TEST_F(GeometryStructTraitsTest, Insets) { + const int32_t top = 1234; + const int32_t left = 5678; + const int32_t bottom = 4321; + const int32_t right = 8765; + gfx::Insets input(top, left, bottom, right); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::Insets output; + proxy->EchoInsets(input, &output); + EXPECT_EQ(top, output.top()); + EXPECT_EQ(left, output.left()); + EXPECT_EQ(bottom, output.bottom()); + EXPECT_EQ(right, output.right()); +} + +TEST_F(GeometryStructTraitsTest, InsetsF) { + const float top = 1234.1f; + const float left = 5678.2f; + const float bottom = 4321.3f; + const float right = 8765.4f; + gfx::InsetsF input(top, left, bottom, right); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::InsetsF output; + proxy->EchoInsetsF(input, &output); + EXPECT_EQ(top, output.top()); + EXPECT_EQ(left, output.left()); + EXPECT_EQ(bottom, output.bottom()); + EXPECT_EQ(right, output.right()); +} + +TEST_F(GeometryStructTraitsTest, Vector2d) { + const int32_t x = 1234; + const int32_t y = -5678; + gfx::Vector2d input(x, y); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::Vector2d output; + proxy->EchoVector2d(input, &output); + EXPECT_EQ(x, output.x()); + EXPECT_EQ(y, output.y()); +} + +TEST_F(GeometryStructTraitsTest, Vector2dF) { + const float x = 1234.5f; + const float y = 6789.6f; + gfx::Vector2dF input(x, y); + mojom::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::Vector2dF output; + proxy->EchoVector2dF(input, &output); + EXPECT_EQ(x, output.x()); + EXPECT_EQ(y, output.y()); +} + +} // namespace gfx diff --git a/ui/gfx/geometry/mojo/geometry_traits_test_service.mojom b/ui/gfx/geometry/mojo/geometry_traits_test_service.mojom new file mode 100644 index 0000000..8d4fb94 --- /dev/null +++ b/ui/gfx/geometry/mojo/geometry_traits_test_service.mojom @@ -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. + +module gfx.mojom; + +import "ui/gfx/geometry/mojo/geometry.mojom"; + +// All functions on this interface echo their arguments to test StructTraits +// serialization and deserialization. +interface GeometryTraitsTestService { + [Sync] + EchoPoint(Point p) => (Point pass); + + [Sync] + EchoPointF(PointF p) => (PointF pass); + + [Sync] + EchoSize(Size s) => (Size pass); + + [Sync] + EchoSizeF(SizeF s) => (SizeF pass); + + [Sync] + EchoRect(Rect r) => (Rect pass); + + [Sync] + EchoRectF(RectF r) => (RectF pass); + + [Sync] + EchoInsets(Insets i) => (Insets pass); + + [Sync] + EchoInsetsF(InsetsF i) => (InsetsF pass); + + [Sync] + EchoVector2d(Vector2d v) => (Vector2d pass); + + [Sync] + EchoVector2dF(Vector2dF v) => (Vector2dF pass); +}; diff --git a/ui/gfx/geometry/point.cc b/ui/gfx/geometry/point.cc new file mode 100644 index 0000000..285b208 --- /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 0000000..bb248d5 --- /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 0000000..0613e7a --- /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 0000000..bfab9e4 --- /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 0000000..0d15394 --- /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 0000000..5d92b11 --- /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 0000000..b5ceda5 --- /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 0000000..1858d44 --- /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 0000000..a08e384 --- /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 0000000..9d99052 --- /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 0000000..5efe134 --- /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 0000000..6948672 --- /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 0000000..8ce4178 --- /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 0000000..c924e86 --- /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 0000000..96fb79f --- /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 0000000..6d08e18 --- /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 0000000..0757ef6 --- /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 0000000..2b4875c --- /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 0000000..4b45667 --- /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 0000000..ccb15ae --- /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 0000000..92f7f87 --- /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 0000000..20c8bb1 --- /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 0000000..0a8d8b2 --- /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 0000000..5634c49 --- /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/mojo/BUILD.gn b/ui/gfx/range/mojo/BUILD.gn new file mode 100644 index 0000000..b6d458d --- /dev/null +++ b/ui/gfx/range/mojo/BUILD.gn @@ -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. + +import("//mojo/public/tools/bindings/mojom.gni") + +# This target does NOT depend on skia. One can depend on this target to avoid +# picking up a dependency on skia. +mojom("mojo") { + sources = [ + "range.mojom", + ] +} + +mojom("test_interfaces") { + sources = [ + "range_traits_test_service.mojom", + ] + + public_deps = [ + ":mojo", + ] +} + +source_set("unit_test") { + testonly = true + + sources = [ + "range_struct_traits_unittest.cc", + ] + + deps = [ + ":test_interfaces", + "//base", + "//mojo/public/cpp/bindings", + "//testing/gtest", + "//ui/gfx/range", + ] +} + +source_set("struct_traits") { + sources = [ + "range_struct_traits.h", + ] + public_deps = [ + ":mojo_shared_cpp_sources", + "//ui/gfx/range", + ] +} diff --git a/ui/gfx/range/mojo/DEPS b/ui/gfx/range/mojo/DEPS new file mode 100644 index 0000000..418fc69 --- /dev/null +++ b/ui/gfx/range/mojo/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+mojo/public", + "+ui/gfx/range", +] diff --git a/ui/gfx/range/mojo/range.mojom b/ui/gfx/range/mojo/range.mojom new file mode 100644 index 0000000..079c146 --- /dev/null +++ b/ui/gfx/range/mojo/range.mojom @@ -0,0 +1,15 @@ +// 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. + +module gfx.mojom; + +struct Range { + uint32 start; + uint32 end; +}; + +struct RangeF { + float start; + float end; +}; diff --git a/ui/gfx/range/mojo/range.typemap b/ui/gfx/range/mojo/range.typemap new file mode 100644 index 0000000..ebf07d1 --- /dev/null +++ b/ui/gfx/range/mojo/range.typemap @@ -0,0 +1,17 @@ +# 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. + +mojom = "//ui/gfx/range/mojo/range.mojom" +public_headers = [ + "//ui/gfx/range/range.h", + "//ui/gfx/range/range_f.h", +] +traits_headers = [ "//ui/gfx/range/mojo/range_struct_traits.h" ] +deps = [ + "//ui/gfx/range/mojo:struct_traits", +] +type_mappings = [ + "gfx.mojom.Range=gfx::Range", + "gfx.mojom.RangeF=gfx::RangeF", +] diff --git a/ui/gfx/range/mojo/range_struct_traits.h b/ui/gfx/range/mojo/range_struct_traits.h new file mode 100644 index 0000000..e717d41 --- /dev/null +++ b/ui/gfx/range/mojo/range_struct_traits.h @@ -0,0 +1,38 @@ +// 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 UI_GFX_RANGE_MOJO_RANGE_STRUCT_TRAITS_H_ +#define UI_GFX_RANGE_MOJO_RANGE_STRUCT_TRAITS_H_ + +#include "ui/gfx/range/mojo/range.mojom-shared.h" +#include "ui/gfx/range/range.h" +#include "ui/gfx/range/range_f.h" + +namespace mojo { + +template <> +struct StructTraits<gfx::mojom::RangeDataView, gfx::Range> { + static uint32_t start(const gfx::Range& r) { return r.start(); } + static uint32_t end(const gfx::Range& r) { return r.end(); } + static bool Read(gfx::mojom::RangeDataView data, gfx::Range* out) { + out->set_start(data.start()); + out->set_end(data.end()); + return true; + } +}; + +template <> +struct StructTraits<gfx::mojom::RangeFDataView, gfx::RangeF> { + static float start(const gfx::RangeF& r) { return r.start(); } + static float end(const gfx::RangeF& r) { return r.end(); } + static bool Read(gfx::mojom::RangeFDataView data, gfx::RangeF* out) { + out->set_start(data.start()); + out->set_end(data.end()); + return true; + } +}; + +} // namespace mojo + +#endif // UI_GFX_RANGE_MOJO_RANGE_STRUCT_TRAITS_H_ diff --git a/ui/gfx/range/mojo/range_struct_traits_unittest.cc b/ui/gfx/range/mojo/range_struct_traits_unittest.cc new file mode 100644 index 0000000..31705ca --- /dev/null +++ b/ui/gfx/range/mojo/range_struct_traits_unittest.cc @@ -0,0 +1,68 @@ +// 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 <utility> + +#include "base/message_loop/message_loop.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/range/mojo/range_traits_test_service.mojom.h" + +namespace gfx { + +namespace { + +class RangeStructTraitsTest : public testing::Test, + public mojom::RangeTraitsTestService { + public: + RangeStructTraitsTest() {} + + protected: + mojom::RangeTraitsTestServicePtr GetTraitsTestProxy() { + mojom::RangeTraitsTestServicePtr proxy; + traits_test_bindings_.AddBinding(this, mojo::MakeRequest(&proxy)); + return proxy; + } + + private: + // RangeTraitsTestService: + void EchoRange(const Range& p, EchoRangeCallback callback) override { + std::move(callback).Run(p); + } + + void EchoRangeF(const RangeF& p, EchoRangeFCallback callback) override { + std::move(callback).Run(p); + } + + base::MessageLoop loop_; + mojo::BindingSet<RangeTraitsTestService> traits_test_bindings_; + + DISALLOW_COPY_AND_ASSIGN(RangeStructTraitsTest); +}; + +} // namespace + +TEST_F(RangeStructTraitsTest, Range) { + const uint32_t start = 1234; + const uint32_t end = 5678; + gfx::Range input(start, end); + mojom::RangeTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::Range output; + proxy->EchoRange(input, &output); + EXPECT_EQ(start, output.start()); + EXPECT_EQ(end, output.end()); +} + +TEST_F(RangeStructTraitsTest, RangeF) { + const float start = 1234.5f; + const float end = 6789.6f; + gfx::RangeF input(start, end); + mojom::RangeTraitsTestServicePtr proxy = GetTraitsTestProxy(); + gfx::RangeF output; + proxy->EchoRangeF(input, &output); + EXPECT_EQ(start, output.start()); + EXPECT_EQ(end, output.end()); +} + +} // namespace gfx diff --git a/ui/gfx/range/mojo/range_traits_test_service.mojom b/ui/gfx/range/mojo/range_traits_test_service.mojom new file mode 100644 index 0000000..3cde75c --- /dev/null +++ b/ui/gfx/range/mojo/range_traits_test_service.mojom @@ -0,0 +1,17 @@ +// 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. + +module gfx.mojom; + +import "ui/gfx/range/mojo/range.mojom"; + +// All functions on this interface echo their arguments to test StructTraits +// serialization and deserialization. +interface RangeTraitsTestService { + [Sync] + EchoRange(Range p) => (Range pass); + + [Sync] + EchoRangeF(RangeF p) => (RangeF pass); +}; diff --git a/ui/gfx/range/range.cc b/ui/gfx/range/range.cc new file mode 100644 index 0000000..fa837d0 --- /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 0000000..e785eb6 --- /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 0000000..b3bfc69 --- /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 0000000..1d58ad4 --- /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_mac.mm b/ui/gfx/range/range_mac.mm new file mode 100644 index 0000000..ad7ea6a --- /dev/null +++ b/ui/gfx/range/range_mac.mm @@ -0,0 +1,38 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/range/range.h" + +#include <stddef.h> + +#include <limits> + +#include "base/logging.h" + +namespace gfx { + +Range::Range(const NSRange& range) { + *this = range; +} + +Range& Range::operator=(const NSRange& range) { + if (range.location == NSNotFound) { + DCHECK_EQ(0U, range.length); + *this = InvalidRange(); + } else { + set_start(range.location); + // Don't overflow |end_|. + DCHECK_LE(range.length, std::numeric_limits<size_t>::max() - start()); + set_end(start() + range.length); + } + return *this; +} + +NSRange Range::ToNSRange() const { + if (!IsValid()) + return NSMakeRange(NSNotFound, 0); + return NSMakeRange(GetMin(), length()); +} + +} // namespace gfx diff --git a/ui/gfx/range/range_mac_unittest.mm b/ui/gfx/range/range_mac_unittest.mm new file mode 100644 index 0000000..85323f2 --- /dev/null +++ b/ui/gfx/range/range_mac_unittest.mm @@ -0,0 +1,43 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/range/range.h" + +TEST(RangeTest, FromNSRange) { + NSRange nsr = NSMakeRange(10, 3); + gfx::Range r(nsr); + EXPECT_EQ(nsr.location, r.start()); + EXPECT_EQ(13U, r.end()); + EXPECT_EQ(nsr.length, r.length()); + EXPECT_FALSE(r.is_reversed()); + EXPECT_TRUE(r.IsValid()); +} + +TEST(RangeTest, ToNSRange) { + gfx::Range r(10, 12); + NSRange nsr = r.ToNSRange(); + EXPECT_EQ(10U, nsr.location); + EXPECT_EQ(2U, nsr.length); +} + +TEST(RangeTest, ReversedToNSRange) { + gfx::Range r(20, 10); + NSRange nsr = r.ToNSRange(); + EXPECT_EQ(10U, nsr.location); + EXPECT_EQ(10U, nsr.length); +} + +TEST(RangeTest, FromNSRangeInvalid) { + NSRange nsr = NSMakeRange(NSNotFound, 0); + gfx::Range r(nsr); + EXPECT_FALSE(r.IsValid()); +} + +TEST(RangeTest, ToNSRangeInvalid) { + gfx::Range r(gfx::Range::InvalidRange()); + NSRange nsr = r.ToNSRange(); + EXPECT_EQ(static_cast<NSUInteger>(NSNotFound), nsr.location); + EXPECT_EQ(0U, nsr.length); +} diff --git a/ui/gfx/range/range_unittest.cc b/ui/gfx/range/range_unittest.cc new file mode 100644 index 0000000..4ae7a67 --- /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()); +} diff --git a/ui/gfx/range/range_win.cc b/ui/gfx/range/range_win.cc new file mode 100644 index 0000000..1180e1b --- /dev/null +++ b/ui/gfx/range/range_win.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/range/range.h" + +#include <limits> + +#include "base/logging.h" + +namespace gfx { + +Range::Range(const CHARRANGE& range, LONG total_length) { + // Check if this is an invalid range. + if (range.cpMin == -1 && range.cpMax == -1) { + *this = InvalidRange(); + } else { + DCHECK_GE(range.cpMin, 0); + set_start(range.cpMin); + // {0,-1} is the "whole range" but that doesn't mean much out of context, + // so use the |total_length| parameter. + if (range.cpMax == -1) { + DCHECK_EQ(0, range.cpMin); + DCHECK_NE(-1, total_length); + set_end(total_length); + } else { + set_end(range.cpMax); + } + } +} + +CHARRANGE Range::ToCHARRANGE() const { + CHARRANGE r = { -1, -1 }; + if (!IsValid()) + return r; + + const LONG kLONGMax = std::numeric_limits<LONG>::max(); + CHECK_LE(static_cast<LONG>(start()), kLONGMax); + CHECK_LE(static_cast<LONG>(end()), kLONGMax); + r.cpMin = static_cast<LONG>(start()); + r.cpMax = static_cast<LONG>(end()); + return r; +} + +} // namespace gfx diff --git a/ui/gfx/range/range_win_unittest.cc b/ui/gfx/range/range_win_unittest.cc new file mode 100644 index 0000000..d15375b --- /dev/null +++ b/ui/gfx/range/range_win_unittest.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/range/range.h" + +TEST(RangeTest, FromCHARRANGE) { + CHARRANGE cr = { 10, 32 }; + gfx::Range r(cr, 50); + EXPECT_EQ(10U, r.start()); + EXPECT_EQ(32U, r.end()); + EXPECT_EQ(22U, r.length()); + EXPECT_FALSE(r.is_reversed()); + EXPECT_TRUE(r.IsValid()); +} + +TEST(RangeTest, FromReversedCHARRANGE) { + CHARRANGE cr = { 20, 10 }; + gfx::Range r(cr, 40); + EXPECT_EQ(20U, r.start()); + EXPECT_EQ(10U, r.end()); + EXPECT_EQ(10U, r.length()); + EXPECT_TRUE(r.is_reversed()); + EXPECT_TRUE(r.IsValid()); +} + +TEST(RangeTest, FromCHARRANGETotal) { + CHARRANGE cr = { 0, -1 }; + gfx::Range r(cr, 20); + EXPECT_EQ(0U, r.start()); + EXPECT_EQ(20U, r.end()); + EXPECT_EQ(20U, r.length()); + EXPECT_FALSE(r.is_reversed()); + EXPECT_TRUE(r.IsValid()); +} + +TEST(RangeTest, ToCHARRANGE) { + gfx::Range r(10, 30); + CHARRANGE cr = r.ToCHARRANGE(); + EXPECT_EQ(10, cr.cpMin); + EXPECT_EQ(30, cr.cpMax); +} + +TEST(RangeTest, ReversedToCHARRANGE) { + gfx::Range r(20, 10); + CHARRANGE cr = r.ToCHARRANGE(); + EXPECT_EQ(20, cr.cpMin); + EXPECT_EQ(10, cr.cpMax); +} + +TEST(RangeTest, FromCHARRANGEInvalid) { + CHARRANGE cr = { -1, -1 }; + gfx::Range r(cr, 30); + EXPECT_FALSE(r.IsValid()); +} + +TEST(RangeTest, ToCHARRANGEInvalid) { + gfx::Range r(gfx::Range::InvalidRange()); + CHARRANGE cr = r.ToCHARRANGE(); + EXPECT_EQ(-1, cr.cpMin); + EXPECT_EQ(-1, cr.cpMax); +} |