Snap for 4509671 from 7c4d9a1153b656823d9b40168054a6aecf4c2c2a to pi-release

Change-Id: I0fbac461756439085d9792550f833946aab55f5d
diff --git a/Android.mk b/Android.mk
index 80bf5a9..a61dbe1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,6 +23,8 @@
 	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 @@
 	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 @@
 	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/base/android/jni_android.cc b/base/android/jni_android.cc
index 56dc5c2..abc37d5 100644
--- a/base/android/jni_android.cc
+++ b/base/android/jni_android.cc
@@ -240,7 +240,16 @@
   }
 
   // Now, feel good about it and die.
-  LOG(FATAL) << "Please include Java exception stack in crash report";
+  // TODO(lhchavez): Remove this hack. See b/28814913 for details.
+  // We're using BuildInfo's java_exception_info() instead of storing the
+  // exception info a few lines above to avoid extra copies. It will be
+  // truncated to 1024 bytes anyways.
+  const char* exception_string =
+      base::android::BuildInfo::GetInstance()->java_exception_info();
+  if (exception_string)
+    LOG(FATAL) << exception_string;
+  else
+    LOG(FATAL) << "Unhandled exception";
 }
 
 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
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 @@
 # 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/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java
index a278cc5..aebc9e2 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java
@@ -171,20 +171,23 @@
         assert messageWithHeader.getHeader().hasFlag(MessageHeader.MESSAGE_EXPECTS_RESPONSE_FLAG);
 
         // Compute a request id for being able to route the response.
-        long requestId = mNextRequestId++;
-        // Reserve 0 in case we want it to convey special meaning in the future.
-        if (requestId == 0) {
-            requestId = mNextRequestId++;
+        // TODO(lhchavez): Remove this hack. See b/28986534 for details.
+        synchronized (mResponders) {
+            long requestId = mNextRequestId++;
+            // Reserve 0 in case we want it to convey special meaning in the future.
+            if (requestId == 0) {
+                requestId = mNextRequestId++;
+            }
+            if (mResponders.containsKey(requestId)) {
+                throw new IllegalStateException("Unable to find a new request identifier.");
+            }
+            messageWithHeader.setRequestId(requestId);
+            if (!mConnector.accept(messageWithHeader)) {
+                return false;
+            }
+            // Only keep the responder is the message has been accepted.
+            mResponders.put(requestId, responder);
         }
-        if (mResponders.containsKey(requestId)) {
-            throw new IllegalStateException("Unable to find a new request identifier.");
-        }
-        messageWithHeader.setRequestId(requestId);
-        if (!mConnector.accept(messageWithHeader)) {
-            return false;
-        }
-        // Only keep the responder is the message has been accepted.
-        mResponders.put(requestId, responder);
         return true;
     }
 
@@ -227,11 +230,15 @@
             return false;
         } else if (header.hasFlag(MessageHeader.MESSAGE_IS_RESPONSE_FLAG)) {
             long requestId = header.getRequestId();
-            MessageReceiver responder = mResponders.get(requestId);
-            if (responder == null) {
-                return false;
+            MessageReceiver responder;
+            // TODO(lhchavez): Remove this hack. See b/28986534 for details.
+            synchronized (mResponders) {
+                responder = mResponders.get(requestId);
+                if (responder == null) {
+                    return false;
+                }
+                mResponders.remove(requestId);
             }
-            mResponders.remove(requestId);
             return responder.accept(message);
         } else {
             if (mIncomingMessageReceiver != null) {
diff --git a/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
index c7dcbbc..ba31186 100644
--- a/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/java_templates/interface_definition.tmpl
@@ -113,7 +113,12 @@
 {%       else %}
             {{request_struct|name}}.deserialize(messageWithHeader.getPayload());
 {%       endif %}
-            getImpl().{{method|name}}({{run_callback('data', method.parameters)}}{% if with_response %}{% if method.parameters %}, {% endif %}new {{response_struct|name}}ProxyToResponder(getCore(), receiver, header.getRequestId()){% endif %});
+            try {
+                getImpl().{{method|name}}({{run_callback('data', method.parameters)}}{% if with_response %}{% if method.parameters %}, {% endif %}new {{response_struct|name}}ProxyToResponder(getCore(), receiver, header.getRequestId()){% endif %});
+            } catch (RuntimeException e) {
+                // TODO(lhchavez): Remove this hack. See b/28814913 for details.
+                android.util.Log.wtf("{{namespace}}.{{interface.name}}", "Uncaught runtime exception", e);
+            }
             return true;
         }
 {%     endif %}
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);
+}