diff --git a/ash/accessibility/magnifier/fullscreen_magnifier_controller_unittest.cc b/ash/accessibility/magnifier/fullscreen_magnifier_controller_unittest.cc
index 69af39c488c7e..44b321f3907b4 100644
--- a/ash/accessibility/magnifier/fullscreen_magnifier_controller_unittest.cc
+++ b/ash/accessibility/magnifier/fullscreen_magnifier_controller_unittest.cc
@@ -98,9 +98,12 @@ class FullscreenMagnifierControllerTest : public AshTestBase {
   }
 
   gfx::Rect GetViewport() const {
-    gfx::RectF bounds(0, 0, kRootWidth, kRootHeight);
-    GetRootWindow()->layer()->transform().TransformRectReverse(&bounds);
-    return gfx::ToEnclosingRect(bounds);
+    gfx::Rect bounds(0, 0, kRootWidth, kRootHeight);
+    return GetRootWindow()
+        ->layer()
+        ->transform()
+        .InverseMapRect(bounds)
+        .value_or(bounds);
   }
 
   std::string CurrentPointOfInterest() const {
diff --git a/ash/app_list/views/app_drag_icon_proxy_unittest.cc b/ash/app_list/views/app_drag_icon_proxy_unittest.cc
index 5f9e0c80a7085..4ee4c7482f9f2 100644
--- a/ash/app_list/views/app_drag_icon_proxy_unittest.cc
+++ b/ash/app_list/views/app_drag_icon_proxy_unittest.cc
@@ -28,17 +28,15 @@ class AppDragIconProxyTest : public AshTestBase {
   ~AppDragIconProxyTest() override = default;
 
   gfx::Rect GetTargetAppDragIconImageBounds(AppDragIconProxy* drag_icon_proxy) {
-    gfx::RectF layer_target_position(
-        drag_icon_proxy->GetImageLayerForTesting()->GetTargetBounds());
-    drag_icon_proxy->GetImageLayerForTesting()
-        ->GetTargetTransform()
-        .TransformRect(&layer_target_position);
+    gfx::Rect layer_target_position =
+        drag_icon_proxy->GetImageLayerForTesting()
+            ->GetTargetTransform()
+            .MapRect(
+                drag_icon_proxy->GetImageLayerForTesting()->GetTargetBounds());
     gfx::Rect widget_target_bounds =
         drag_icon_proxy->GetWidgetForTesting()->GetLayer()->GetTargetBounds();
-    layer_target_position.set_origin(
-        gfx::PointF(layer_target_position.x() + widget_target_bounds.x(),
-                    layer_target_position.y() + widget_target_bounds.y()));
-    return gfx::ToNearestRect(layer_target_position);
+    layer_target_position.Offset(widget_target_bounds.OffsetFromOrigin());
+    return layer_target_position;
   }
 };
 
diff --git a/ash/host/ash_window_tree_host_platform.cc b/ash/host/ash_window_tree_host_platform.cc
index 8c7504c1eed9f..e431008d32fc5 100644
--- a/ash/host/ash_window_tree_host_platform.cc
+++ b/ash/host/ash_window_tree_host_platform.cc
@@ -90,9 +90,8 @@ void AshWindowTreeHostPlatform::ConfineCursorToBoundsInRoot(
   if (!allow_confine_cursor())
     return;
 
-  gfx::RectF bounds_f(bounds_in_root);
-  GetRootTransform().TransformRect(&bounds_f);
-  last_cursor_confine_bounds_in_pixels_ = gfx::ToEnclosingRect(bounds_f);
+  last_cursor_confine_bounds_in_pixels_ =
+      GetRootTransform().MapRect(bounds_in_root);
   platform_window()->ConfineCursorToBounds(
       last_cursor_confine_bounds_in_pixels_);
 }
diff --git a/ash/screen_util.cc b/ash/screen_util.cc
index 729d90d650a3e..6a2be08d93a82 100644
--- a/ash/screen_util.cc
+++ b/ash/screen_util.cc
@@ -108,14 +108,11 @@ gfx::Rect GetDisplayBoundsWithShelf(aura::Window* window) {
           ->display_configuration_controller()
           ->GetPrimaryMirroringDisplayForUnifiedDesktop();
   DCHECK_NE(shelf_display.id(), display::kInvalidDisplayId);
-  gfx::RectF shelf_display_screen_bounds(shelf_display.bounds());
 
   // Transform the bounds back to the unified host's coordinates.
   auto inverse_unified_transform =
       window->GetRootWindow()->GetHost()->GetInverseRootTransform();
-  inverse_unified_transform.TransformRect(&shelf_display_screen_bounds);
-
-  return gfx::ToEnclosingRect(shelf_display_screen_bounds);
+  return inverse_unified_transform.MapRect(shelf_display.bounds());
 }
 
 gfx::Rect SnapBoundsToDisplayEdge(const gfx::Rect& bounds,
diff --git a/ash/shelf/home_to_overview_nudge_controller_unittest.cc b/ash/shelf/home_to_overview_nudge_controller_unittest.cc
index 9b30379ee7e49..c94786be0adea 100644
--- a/ash/shelf/home_to_overview_nudge_controller_unittest.cc
+++ b/ash/shelf/home_to_overview_nudge_controller_unittest.cc
@@ -130,16 +130,14 @@ class HomeToOverviewNudgeControllerTest : public AshTestBase {
     ASSERT_TRUE(nudge_widget);
     EXPECT_TRUE(nudge_widget->IsVisible());
 
-    gfx::RectF nudge_bounds_f(
-        nudge_widget->GetNativeWindow()->GetTargetBounds());
-    nudge_widget->GetLayer()->transform().TransformRect(&nudge_bounds_f);
-    const gfx::Rect nudge_bounds = gfx::ToEnclosingRect(nudge_bounds_f);
+    const gfx::Rect nudge_bounds =
+        nudge_widget->GetLayer()->transform().MapRect(
+            nudge_widget->GetNativeWindow()->GetTargetBounds());
 
     HotseatWidget* const hotseat = GetHotseatWidget();
-    gfx::RectF hotseat_bounds_f(hotseat->GetNativeWindow()->GetTargetBounds());
-    hotseat->GetLayerForNudgeAnimation()->transform().TransformRect(
-        &hotseat_bounds_f);
-    const gfx::Rect hotseat_bounds = gfx::ToEnclosingRect(hotseat_bounds_f);
+    const gfx::Rect hotseat_bounds =
+        hotseat->GetLayerForNudgeAnimation()->transform().MapRect(
+            hotseat->GetNativeWindow()->GetTargetBounds());
 
     // Nudge and hotseat should have the same transform.
     EXPECT_EQ(hotseat->GetLayerForNudgeAnimation()->transform(),
diff --git a/ash/shelf/hotseat_widget.cc b/ash/shelf/hotseat_widget.cc
index 06a7012c02c40..6fddd10760475 100644
--- a/ash/shelf/hotseat_widget.cc
+++ b/ash/shelf/hotseat_widget.cc
@@ -1180,9 +1180,8 @@ void HotseatWidget::LayoutHotseatByAnimation(double target_opacity,
   // between hidden and extended state use transform to animate. Clear any
   // transform that may have been set by the previous animation, and update
   // current bounds to match it.
-  gfx::RectF current_bounds_f(GetNativeView()->GetBoundsInScreen());
-  hotseat_layer->transform().TransformRect(&current_bounds_f);
-  gfx::Rect current_bounds = gfx::ToEnclosingRect(current_bounds_f);
+  gfx::Rect current_bounds =
+      hotseat_layer->transform().MapRect(GetNativeView()->GetBoundsInScreen());
 
   // If the bounds size has not changed, set the target bounds immediately, and
   // animate using transform.
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index ccd0948237be0..a5ff33b9fad1e 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -1024,9 +1024,8 @@ void ShelfWidget::UpdateLayout(bool animate) {
     // When the |shelf_widget_| needs to reverse the direction of the current
     // animation, we must take into account the transform when calculating the
     // current shelf widget bounds.
-    gfx::RectF transformed_bounds(current_shelf_bounds);
-    GetLayer()->transform().TransformRect(&transformed_bounds);
-    current_shelf_bounds = gfx::ToEnclosedRect(transformed_bounds);
+    current_shelf_bounds =
+        GetLayer()->transform().MapRect(current_shelf_bounds);
   }
 
   gfx::Transform shelf_widget_target_transform;
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index 4dd74d1f198ef..f6e050d1a0394 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -3256,9 +3256,9 @@ TEST_F(DesksTest, AutohiddenShelfAnimatesAfterDeskSwitch) {
 
   // Since the layer transform animation is just starting, the transformed
   // bounds should still be hidden. If this fails, the change was not animated.
-  gfx::RectF transformed_bounds(shelf_widget->GetWindowBoundsInScreen());
-  shelf_widget->GetLayer()->transform().TransformRect(&transformed_bounds);
-  EXPECT_EQ(gfx::ToEnclosedRect(transformed_bounds), hidden_shelf_bounds);
+  gfx::Rect transformed_bounds = shelf_widget->GetLayer()->transform().MapRect(
+      shelf_widget->GetWindowBoundsInScreen());
+  EXPECT_EQ(transformed_bounds, hidden_shelf_bounds);
   EXPECT_EQ(shelf_widget->GetWindowBoundsInScreen(), shown_shelf_bounds);
 
   // Let's wait until the shelf animates to a fully shown state.
diff --git a/ash/wm/desks/root_window_desk_switch_animator_unittest.cc b/ash/wm/desks/root_window_desk_switch_animator_unittest.cc
index db4c18dd2fb06..7585414b211a8 100644
--- a/ash/wm/desks/root_window_desk_switch_animator_unittest.cc
+++ b/ash/wm/desks/root_window_desk_switch_animator_unittest.cc
@@ -53,9 +53,7 @@ gfx::Rect GetVisibleBounds(ui::Layer* child_layer,
       use_target_transform ? animating_layer->GetTargetTransform()
                            : animating_layer->transform();
   DCHECK(animating_layer_transform.IsIdentityOr2DTranslation());
-  gfx::RectF bounds(child_layer->bounds());
-  animating_layer_transform.TransformRect(&bounds);
-  return gfx::ToRoundedRect(bounds);
+  return animating_layer_transform.MapRect(child_layer->bounds());
 }
 
 gfx::Rect GetTargetVisibleBounds(ui::Layer* child_layer,
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index d4bbeff7b69e0..a920de852b3e4 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -4797,9 +4797,8 @@ TEST_F(SplitViewOverviewSessionTest, Clipping) {
     EXPECT_FALSE(preview_layer->clip_rect().IsEmpty());
     EXPECT_FALSE(preview_layer->transform().IsIdentity());
     // The clip rect is affected by |preview_layer|'s transform so apply it.
-    gfx::RectF clip_rect3_f(preview_layer->clip_rect());
-    preview_layer->transform().TransformRect(&clip_rect3_f);
-    const gfx::Rect clip_rects3 = gfx::ToEnclosedRect(clip_rect3_f);
+    const gfx::Rect clip_rects3 =
+        preview_layer->transform().MapRect(preview_layer->clip_rect());
     EXPECT_TRUE(aspect_ratio_near(clip_rects3, split_view_bounds_right));
     EXPECT_TRUE(aspect_ratio_near(
         gfx::ToEnclosedRect(item3->GetWindowTargetBoundsWithInsets()),
diff --git a/ash/wm/overview/overview_test_base.cc b/ash/wm/overview/overview_test_base.cc
index 98bb7b4980c8b..365459763052b 100644
--- a/ash/wm/overview/overview_test_base.cc
+++ b/ash/wm/overview/overview_test_base.cc
@@ -99,7 +99,6 @@ gfx::Rect OverviewTestBase::GetTransformedTargetBounds(aura::Window* window) {
 
 gfx::Rect OverviewTestBase::GetTransformedBoundsInRootWindow(
     aura::Window* window) {
-  gfx::RectF bounds = gfx::RectF(gfx::SizeF(window->bounds().size()));
   aura::Window* root = window->GetRootWindow();
   CHECK(window->layer());
   CHECK(root->layer());
@@ -108,8 +107,7 @@ gfx::Rect OverviewTestBase::GetTransformedBoundsInRootWindow(
                                                      &transform)) {
     return gfx::Rect();
   }
-  transform.TransformRect(&bounds);
-  return gfx::ToEnclosingRect(bounds);
+  return transform.MapRect(gfx::Rect(window->bounds().size()));
 }
 
 OverviewItem* OverviewTestBase::GetDropTarget(int grid_index) {
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index 3afac7b9a264c..c354c204aa904 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -1244,7 +1244,7 @@ TEST_P(SurfaceTest, ScaledSurfaceQuad) {
                   ->quad_list.back()
                   ->shared_quad_state->clip_rect);
 
-    auto testing_rect = gfx::RectF(gfx::PointF(0, 0), gfx::SizeF(256, 256));
+    gfx::Rect testing_rect(256, 256);
     // To get 32,32 -> 160,160 into the correct position it must be translated
     // backwards and scaled 0.5x in Y, then everything is scaled by the scale
     // factor.
@@ -1258,8 +1258,7 @@ TEST_P(SurfaceTest, ScaledSurfaceQuad) {
     if (gfx::Transform() == frame.render_pass_list.back()
                                 ->quad_list.back()
                                 ->shared_quad_state->quad_to_target_transform) {
-      expected_transform.TransformRect(&testing_rect);
-      auto expected_rect = gfx::ToNearestRect(testing_rect);
+      auto expected_rect = expected_transform.MapRect(testing_rect);
       EXPECT_EQ(expected_rect,
                 frame.render_pass_list.back()->quad_list.back()->rect);
     } else {
@@ -1267,7 +1266,7 @@ TEST_P(SurfaceTest, ScaledSurfaceQuad) {
                 frame.render_pass_list.back()
                     ->quad_list.back()
                     ->shared_quad_state->quad_to_target_transform);
-      EXPECT_EQ(gfx::ToNearestRect(testing_rect),
+      EXPECT_EQ(testing_rect,
                 frame.render_pass_list.back()->quad_list.back()->rect);
     }
   }
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc
index 359f95d1c6aa0..e85b4bfc6014e 100644
--- a/components/viz/service/display/dc_layer_overlay.cc
+++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -152,9 +152,8 @@ void FromYUVQuad(const YUVVideoDrawQuad* quad,
   if (quad->shared_quad_state->clip_rect) {
     // Clip rect is in quad target space, and must be transformed to root target
     // space.
-    gfx::RectF clip_rect = gfx::RectF(*quad->shared_quad_state->clip_rect);
-    transform_to_root_target.TransformRect(&clip_rect);
-    dc_layer->clip_rect = gfx::ToEnclosingRect(clip_rect);
+    dc_layer->clip_rect =
+        transform_to_root_target.MapRect(*quad->shared_quad_state->clip_rect);
   }
   dc_layer->color_space = quad->video_color_space;
   dc_layer->protected_video_type = quad->protected_video_type;
@@ -214,10 +213,8 @@ void FromTextureQuad(const TextureDrawQuad* quad,
   if (quad->shared_quad_state->clip_rect) {
     // Clip rect is in quad target space, and must be transformed to root target
     // space.
-    gfx::RectF clip_rect =
-        gfx::RectF(quad->shared_quad_state->clip_rect.value_or(gfx::Rect()));
-    transform_to_root_target.TransformRect(&clip_rect);
-    dc_layer->clip_rect = gfx::ToEnclosingRect(clip_rect);
+    dc_layer->clip_rect = transform_to_root_target.MapRect(
+        quad->shared_quad_state->clip_rect.value_or(gfx::Rect()));
   }
 
   dc_layer->color_space = gfx::ColorSpace::CreateSRGB();
@@ -627,10 +624,9 @@ void DCLayerOverlayProcessor::InsertDebugBorderDrawQuad(
 
   // Add debug borders for overlays/underlays
   for (const auto& dc_layer : *dc_layer_overlays) {
-    gfx::RectF overlay_rect(dc_layer.quad_rect);
-    dc_layer.transform.TransformRect(&overlay_rect);
+    gfx::Rect overlay_rect = dc_layer.transform.MapRect(dc_layer.quad_rect);
     if (dc_layer.clip_rect)
-      overlay_rect.Intersect(gfx::RectF(*dc_layer.clip_rect));
+      overlay_rect.Intersect(*dc_layer.clip_rect);
 
     // Overlay:red, Underlay:blue.
     SkColor4f border_color =
@@ -640,10 +636,9 @@ void DCLayerOverlayProcessor::InsertDebugBorderDrawQuad(
             quad_list.begin(), 1u);
     auto* debug_quad = static_cast<DebugBorderDrawQuad*>(*it);
 
-    gfx::Rect rect = gfx::ToEnclosingRect(overlay_rect);
-    rect.Inset(kDCLayerDebugBorderInsets);
-    debug_quad->SetNew(shared_quad_state, rect, rect, border_color,
-                       kDCLayerDebugBorderWidth);
+    overlay_rect.Inset(kDCLayerDebugBorderInsets);
+    debug_quad->SetNew(shared_quad_state, overlay_rect, overlay_rect,
+                       border_color, kDCLayerDebugBorderWidth);
   }
 
   // Mark the entire output as damaged because the border quads might not be
diff --git a/components/viz/service/display/overlay_processor_surface_control.cc b/components/viz/service/display/overlay_processor_surface_control.cc
index a62a33088e3f6..e0c4aecf61dc5 100644
--- a/components/viz/service/display/overlay_processor_surface_control.cc
+++ b/components/viz/service/display/overlay_processor_surface_control.cc
@@ -145,9 +145,7 @@ gfx::Rect OverlayProcessorSurfaceControl::GetOverlayDamageRectForOutputSurface(
                                                 viewport_size_.width());
   auto transform = gfx::OverlayTransformToTransform(
       display_transform_, gfx::SizeF(viewport_size_pre_display_transform));
-  gfx::RectF transformed_rect(candidate.display_rect);
-  transform.TransformRect(&transformed_rect);
-  return gfx::ToEnclosedRect(transformed_rect);
+  return transform.MapRect(gfx::ToEnclosingRect(candidate.display_rect));
 }
 
 void OverlayProcessorSurfaceControl::SetDisplayTransformHint(
diff --git a/components/viz/service/display/overlay_strategy_underlay_cast.cc b/components/viz/service/display/overlay_strategy_underlay_cast.cc
index 844eda33f8ebf..e140b523c9e03 100644
--- a/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -66,8 +66,7 @@ bool OverlayStrategyUnderlayCast::Attempt(
       continue;
 
     const auto& transform = quad->shared_quad_state->quad_to_target_transform;
-    gfx::RectF quad_rect = gfx::RectF(quad->rect);
-    transform.TransformRect(&quad_rect);
+    gfx::Rect quad_rect = transform.MapRect(quad->rect);
 
     bool is_underlay = false;
     if (!found_underlay) {
@@ -93,9 +92,9 @@ bool OverlayStrategyUnderlayCast::Attempt(
     }
 
     if (is_underlay) {
-      content_rect.Subtract(gfx::ToEnclosedRect(quad_rect));
+      content_rect.Subtract(quad_rect);
     } else {
-      content_rect.Union(gfx::ToEnclosingRect(quad_rect));
+      content_rect.Union(quad_rect);
     }
   }
 
@@ -197,8 +196,7 @@ bool OverlayStrategyUnderlayCast::AttemptPrioritized(
       continue;
 
     const auto& transform = quad->shared_quad_state->quad_to_target_transform;
-    gfx::RectF quad_rect = gfx::RectF(quad->rect);
-    transform.TransformRect(&quad_rect);
+    gfx::Rect quad_rect = transform.MapRect(quad->rect);
 
     bool is_underlay = false;
     if (!found_underlay) {
@@ -224,9 +222,9 @@ bool OverlayStrategyUnderlayCast::AttemptPrioritized(
     }
 
     if (is_underlay) {
-      content_rect.Subtract(gfx::ToEnclosedRect(quad_rect));
+      content_rect.Subtract(quad_rect);
     } else {
-      content_rect.Union(gfx::ToEnclosingRect(quad_rect));
+      content_rect.Union(quad_rect);
     }
   }
 
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 4bca65fae922c..789887de049d6 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -2406,7 +2406,7 @@ void SurfaceAggregator::CreateDeJellyRenderPassQuads(
 
   // Compute the required renderpass rect in target space.
   // First, find the un-transformed visible rect.
-  gfx::RectF render_pass_visible_rect_f(state->visible_quad_layer_rect);
+  gfx::Rect render_pass_visible_rect = state->visible_quad_layer_rect;
   // Next, if this is a RenderPass quad, find any filters and expand the
   // visible rect.
   if (quad->material == DrawQuad::Material::kCompositorRenderPass) {
@@ -2414,16 +2414,15 @@ void SurfaceAggregator::CreateDeJellyRenderPassQuads(
         CompositorRenderPassDrawQuad::MaterialCast(quad)->render_pass_id});
     for (auto& rp : *dest_pass_list_) {
       if (rp->id == target_id) {
-        render_pass_visible_rect_f = gfx::RectF(
-            rp->filters.MapRect(state->visible_quad_layer_rect, SkMatrix()));
+        render_pass_visible_rect =
+            rp->filters.MapRect(state->visible_quad_layer_rect, SkMatrix());
         break;
       }
     }
   }
   // Next, find the enclosing Rect for the transformed target space RectF.
-  state->quad_to_target_transform.TransformRect(&render_pass_visible_rect_f);
-  gfx::Rect render_pass_visible_rect =
-      gfx::ToEnclosingRect(render_pass_visible_rect_f);
+  render_pass_visible_rect =
+      state->quad_to_target_transform.MapRect(render_pass_visible_rect);
   // Finally, expand by our un_clip amounts.
   render_pass_visible_rect.Inset(
       gfx::Insets::TLBR(-un_clip_top, 0, -un_clip_bottom, 0));
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index f65b55c56ca9d..0133090585389 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -3763,11 +3763,8 @@ bool TransformPointAndRectToRootView(RenderWidgetHostViewBase* view,
   if (transformed_point)
     *transformed_point = transform_to_main_frame.MapPoint(*transformed_point);
 
-  if (transformed_rect) {
-    gfx::RectF transformed_rect_f(*transformed_rect);
-    transform_to_main_frame.TransformRect(&transformed_rect_f);
-    *transformed_rect = gfx::ToEnclosingRect(transformed_rect_f);
-  }
+  if (transformed_rect)
+    *transformed_rect = transform_to_main_frame.MapRect(*transformed_rect);
 
   return true;
 }
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 5c6d72f583cf7..2a6780a93e87b 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -6938,9 +6938,7 @@ class SitePerProcessHitTestDataGenerationBrowserTest
   gfx::Rect AxisAlignedLayoutRectFromHitTest(
       const viz::AggregatedHitTestRegion& hit_test_region) {
     DCHECK(hit_test_region.transform.Preserves2dAxisAlignment());
-    gfx::RectF rect(hit_test_region.rect);
-    hit_test_region.transform.TransformRect(&rect);
-    return gfx::ToEnclosingRect(rect);
+    return hit_test_region.transform.MapRect(hit_test_region.rect);
   }
 
  public:
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 5a0c482e866a1..2a46b51f572fc 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -2104,13 +2104,8 @@ void LocalFrame::SetViewportIntersectionFromParent(
           intersection_state.main_frame_intersection ||
       intersection_state_.main_frame_transform !=
           intersection_state.main_frame_transform) {
-    gfx::RectF transform_rect =
-        gfx::RectF(gfx::Rect(intersection_state.main_frame_intersection));
-
-    intersection_state.main_frame_transform.TransformRect(&transform_rect);
-    gfx::Rect rect = ToEnclosingRect(
-        gfx::RectF(transform_rect.x(), transform_rect.y(),
-                   transform_rect.width(), transform_rect.height()));
+    gfx::Rect rect = intersection_state.main_frame_transform.MapRect(
+        intersection_state.main_frame_intersection);
 
     // Return <0, 0, 0, 0> if there is no area.
     if (rect.IsEmpty())
diff --git a/ui/aura/window_occlusion_tracker.cc b/ui/aura/window_occlusion_tracker.cc
index dc5501f4cedff..9f87b6c442e6c 100644
--- a/ui/aura/window_occlusion_tracker.cc
+++ b/ui/aura/window_occlusion_tracker.cc
@@ -100,10 +100,8 @@ SkIRect ComputeClippedAndTransformedBounds(
     const gfx::Transform& transform_relative_to_root,
     const SkIRect* clipped_bounds) {
   DCHECK(transform_relative_to_root.Preserves2dAxisAlignment());
-  gfx::RectF transformed_bounds(bounds);
-  transform_relative_to_root.TransformRect(&transformed_bounds);
-  SkIRect skirect_bounds =
-      gfx::RectToSkIRect(gfx::ToEnclosedRect(transformed_bounds));
+  gfx::Rect transformed_bounds = transform_relative_to_root.MapRect(bounds);
+  SkIRect skirect_bounds = gfx::RectToSkIRect(transformed_bounds);
   // If necessary, clip the bounds.
   if (clipped_bounds && !skirect_bounds.intersect(*clipped_bounds))
     return SkIRect::MakeEmpty();
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 33a15c199c05e..f6f713ae0b1f1 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -736,9 +736,7 @@ void WindowTreeHost::OnDisplayMetricsChanged(const display::Display& display,
 
 gfx::Rect WindowTreeHost::GetTransformedRootWindowBoundsFromPixelSize(
     const gfx::Size& size_in_pixels) const {
-  gfx::RectF new_bounds = gfx::RectF(gfx::Rect(size_in_pixels));
-  GetInverseRootTransform().TransformRect(&new_bounds);
-  return gfx::ToEnclosingRect(new_bounds);
+  return GetInverseRootTransform().MapRect(gfx::Rect(size_in_pixels));
 }
 
 void WindowTreeHost::SetNativeWindowOcclusionEnabled(bool enable) {
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc
index 68e10832f5f49..dc0314b457bb4 100644
--- a/ui/aura/window_unittest.cc
+++ b/ui/aura/window_unittest.cc
@@ -3752,9 +3752,7 @@ class WindowActualScreenBoundsTest
 
   void OnTranslationAnimationProgressed(const gfx::Rect& child_initial_bounds,
                                         const gfx::Transform& transform) const {
-    gfx::RectF current_screen_bounds(child_initial_bounds);
-    transform.TransformRect(&current_screen_bounds);
-    EXPECT_EQ(gfx::ToEnclosedRect(current_screen_bounds),
+    EXPECT_EQ(transform.MapRect(child_initial_bounds),
               child_->GetActualBoundsInScreen());
   }
 
diff --git a/ui/gfx/geometry/transform.cc b/ui/gfx/geometry/transform.cc
index 8f6f224d99d13..6c629efad7bba 100644
--- a/ui/gfx/geometry/transform.cc
+++ b/ui/gfx/geometry/transform.cc
@@ -13,6 +13,7 @@
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/quaternion.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/rrect_f.h"
 #include "ui/gfx/geometry/skia_conversions.h"
 #include "ui/gfx/geometry/transform_util.h"
@@ -496,6 +497,15 @@ void Transform::TransformRect(RectF* rect) const {
   *rect = SkRectToRectF(src);
 }
 
+Rect Transform::MapRect(const Rect& rect) const {
+  if (IsIdentity())
+    return rect;
+
+  RectF rect_f(rect);
+  TransformRect(&rect_f);
+  return ToEnclosingRect(rect_f);
+}
+
 bool Transform::TransformRectReverse(RectF* rect) const {
   if (IsIdentity())
     return true;
@@ -510,6 +520,16 @@ bool Transform::TransformRectReverse(RectF* rect) const {
   return true;
 }
 
+absl::optional<Rect> Transform::InverseMapRect(const Rect& rect) const {
+  if (IsIdentity())
+    return rect;
+
+  RectF rect_f(rect);
+  if (TransformRectReverse(&rect_f))
+    return ToEnclosingRect(rect_f);
+  return absl::nullopt;
+}
+
 bool Transform::TransformRRectF(RRectF* rrect) const {
   // We want this to fail only in cases where our
   // Transform::Preserves2dAxisAlignment returns false.  However,
diff --git a/ui/gfx/geometry/transform.h b/ui/gfx/geometry/transform.h
index 0f52cbbd3507f..2892251c47e91 100644
--- a/ui/gfx/geometry/transform.h
+++ b/ui/gfx/geometry/transform.h
@@ -18,6 +18,7 @@ namespace gfx {
 
 class AxisTransform2d;
 class BoxF;
+class Rect;
 class RectF;
 class RRectF;
 class Point;
@@ -334,12 +335,14 @@ class GEOMETRY_SKIA_EXPORT Transform {
   // |rect| will be the smallest axis aligned bounding rect containing the
   // transformed rect.
   void TransformRect(RectF* rect) const;
+  [[nodiscard]] Rect MapRect(const Rect& rect) const;
 
   // Applies the reverse transformation on the given rect. After the function
   // completes, |rect| will be the smallest axis aligned bounding rect
   // containing the transformed rect. Returns false if the matrix cannot be
   // inverted.
   bool TransformRectReverse(RectF* rect) const;
+  [[nodiscard]] absl::optional<Rect> InverseMapRect(const Rect& rect) const;
 
   // Applies transformation on the given |rrect|. Returns false if the transform
   // matrix cannot be applied to rrect.
diff --git a/ui/gfx/geometry/transform_unittest.cc b/ui/gfx/geometry/transform_unittest.cc
index b755a78b3bf92..d9c4ccd447b62 100644
--- a/ui/gfx/geometry/transform_unittest.cc
+++ b/ui/gfx/geometry/transform_unittest.cc
@@ -2752,27 +2752,56 @@ TEST(XFormTest, To2dTranslation) {
 }
 
 TEST(XFormTest, TransformRect) {
-  Transform translation;
-  translation.Translate(3.f, 7.f);
-  RectF rect(1.f, 2.f, 3.f, 4.f);
-  RectF expected(4.f, 9.f, 3.f, 4.f);
+  auto translation = Transform::MakeTranslation(3.25f, 7.75f);
+  RectF rect(1.25f, 2.5f, 3.75f, 4.f);
+  RectF expected(4.5f, 10.25f, 3.75f, 4.f);
   translation.TransformRect(&rect);
-  EXPECT_EQ(expected.ToString(), rect.ToString());
+  EXPECT_EQ(expected, rect);
+
+  expected = rect;
+  Transform().TransformRect(&rect);
+  EXPECT_EQ(expected, rect);
+
+  auto singular = Transform::MakeScale(0.f);
+  singular.TransformRect(&rect);
+  EXPECT_EQ(RectF(0, 0, 0, 0), rect);
+}
+
+TEST(XFormTest, MapIntRect) {
+  auto translation = Transform::MakeTranslation(3.25f, 7.75f);
+  EXPECT_EQ(Rect(4, 9, 4, 5), translation.MapRect(Rect(1, 2, 3, 4)));
+
+  EXPECT_EQ(Rect(1, 2, 3, 4), Transform().MapRect(Rect(1, 2, 3, 4)));
+
+  auto singular = Transform::MakeScale(0.f);
+  EXPECT_EQ(Rect(0, 0, 0, 0), singular.MapRect(Rect(1, 2, 3, 4)));
 }
 
 TEST(XFormTest, TransformRectReverse) {
-  Transform translation;
-  translation.Translate(3.f, 7.f);
-  RectF rect(1.f, 2.f, 3.f, 4.f);
-  RectF expected(-2.f, -5.f, 3.f, 4.f);
+  auto translation = Transform::MakeTranslation(3.25f, 7.75f);
+  RectF rect(1.25f, 2.5f, 3.75f, 4.f);
+  RectF expected(-2.f, -5.25f, 3.75f, 4.f);
   EXPECT_TRUE(translation.TransformRectReverse(&rect));
   EXPECT_EQ(expected.ToString(), rect.ToString());
 
-  Transform singular;
-  singular.Scale3d(0.f, 0.f, 0.f);
+  expected = rect;
+  EXPECT_TRUE(Transform().TransformRectReverse(&rect));
+  EXPECT_EQ(expected, rect);
+
+  auto singular = Transform::MakeScale(0.f);
   EXPECT_FALSE(singular.TransformRectReverse(&rect));
 }
 
+TEST(XFormTest, InverseMapIntRect) {
+  auto translation = Transform::MakeTranslation(3.25f, 7.75f);
+  EXPECT_EQ(Rect(-3, -6, 4, 5), translation.InverseMapRect(Rect(1, 2, 3, 4)));
+
+  EXPECT_EQ(Rect(1, 2, 3, 4), Transform().InverseMapRect(Rect(1, 2, 3, 4)));
+
+  auto singular = Transform::MakeScale(0.f);
+  EXPECT_FALSE(singular.InverseMapRect(Rect(1, 2, 3, 4)));
+}
+
 TEST(XFormTest, TransformRRectF) {
   Transform translation;
   translation.Translate(-3.f, -7.f);
diff --git a/ui/gl/direct_composition_surface_win_unittest.cc b/ui/gl/direct_composition_surface_win_unittest.cc
index 44df45d043289..e38985f4909fe 100644
--- a/ui/gl/direct_composition_surface_win_unittest.cc
+++ b/ui/gl/direct_composition_surface_win_unittest.cc
@@ -1232,9 +1232,7 @@ TEST_F(DirectCompositionPixelTest, ResizeVideoLayer) {
   // chain to |new_on_screen_rect| which fits the monitor.
   surface_->GetSwapChainVisualInfoForTesting(0, &transform, &offset,
                                              &clip_rect);
-  gfx::RectF new_on_screen_rect = gfx::RectF(100, 100);
-  transform.TransformRect(&new_on_screen_rect);
-  EXPECT_EQ(gfx::Rect(monitor_size), gfx::ToEnclosingRect(new_on_screen_rect));
+  EXPECT_EQ(gfx::Rect(monitor_size), transform.MapRect(gfx::Rect(100, 100)));
 }
 
 TEST_F(DirectCompositionPixelTest, SwapChainImage) {
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc
index 93accd11657e0..1e9729597af9e 100644
--- a/ui/gl/swap_chain_presenter.cc
+++ b/ui/gl/swap_chain_presenter.cc
@@ -568,15 +568,11 @@ bool SwapChainPresenter::AdjustSwapChainToFullScreenSizeIfNeeded(
     visual_transform->PostTranslate(-new_origin.OffsetFromOrigin());
   }
 
-#if DCHECK_IS_ON()
   // The new transform matrix should transform the swap chain to the monitor
   // rect.
-  gfx::Rect new_swap_chain_rect = gfx::Rect(*swap_chain_size);
-  new_swap_chain_rect.set_origin(params.quad_rect.origin());
-  gfx::RectF new_onscreen_rect(new_swap_chain_rect);
-  visual_transform->TransformRect(&new_onscreen_rect);
-  DCHECK_EQ(gfx::ToEnclosingRect(new_onscreen_rect), gfx::Rect(monitor_size));
-#endif
+  DCHECK_EQ(visual_transform->MapRect(
+                gfx::Rect(params.quad_rect.origin(), *swap_chain_size)),
+            gfx::Rect(monitor_size));
 
   return true;
 }
@@ -655,11 +651,8 @@ void SwapChainPresenter::AdjustSwapChainForFullScreenLetterboxing(
 
 #if DCHECK_IS_ON()
   // The new transform matrix should transform the swap chain correctly
-  gfx::Rect new_swap_chain_rect = gfx::Rect(*swap_chain_size);
-  new_swap_chain_rect.set_origin(params.quad_rect.origin());
-  gfx::RectF new_onscreen_rect(new_swap_chain_rect);
-  visual_transform->TransformRect(&new_onscreen_rect);
-  gfx::Rect result_rect = gfx::ToEnclosingRect(new_onscreen_rect);
+  gfx::Rect new_swap_chain_rect(params.quad_rect.origin(), *swap_chain_size);
+  gfx::Rect result_rect = visual_transform->MapRect(new_swap_chain_rect);
   if (IsWithinMargin(clipped_onscreen_rect.x(), 0)) {
     DCHECK_EQ(result_rect.x(), 0);
     DCHECK_EQ(result_rect.width(), monitor_size.width());
@@ -683,11 +676,9 @@ gfx::Size SwapChainPresenter::CalculateSwapChainSize(
   gfx::Size swap_chain_size = params.content_rect.size();
   if (swap_chain_size.IsEmpty())
     return gfx::Size();
-  gfx::RectF bounds(params.quad_rect);
-  if (bounds.IsEmpty())
+  if (params.quad_rect.IsEmpty())
     return gfx::Size();
-  params.transform.TransformRect(&bounds);
-  gfx::Rect overlay_onscreen_rect = gfx::ToEnclosingRect(bounds);
+  gfx::Rect overlay_onscreen_rect = params.transform.MapRect(params.quad_rect);
 
   // If transform isn't a scale or translation then swap chain can't be promoted
   // to an overlay so avoid blitting to a large surface unnecessarily.  Also,
@@ -1266,9 +1257,7 @@ bool SwapChainPresenter::PresentDCOMPSurface(
   dcomp_surface_proxy->SetParentWindow(layer_tree_->window());
 
   // Apply transform to video and notify DCOMPTexture.
-  gfx::RectF on_screen_bounds(params.quad_rect);
-  params.transform.TransformRect(&on_screen_bounds);
-  dcomp_surface_proxy->SetRect(gfx::ToEnclosingRect(on_screen_bounds));
+  dcomp_surface_proxy->SetRect(params.transform.MapRect(params.quad_rect));
 
   // If |dcomp_surface_proxy| size is {1, 1}, the texture was initialized
   // without knowledge of output size; reset |content_| so it's not added to the
diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index cad8cc8cd38b7..8f73732bd7351 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -2123,9 +2123,7 @@ TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScale) {
         const int32_t effective_scale = entered_output.output->GetScale();
         gfx::Transform transform;
         transform.Scale(effective_scale, effective_scale);
-        gfx::RectF rect_in_pixels = gfx::RectF(bounds_dip);
-        transform.TransformRect(&rect_in_pixels);
-        gfx::Rect wayland_popup_bounds = gfx::ToEnclosingRect(rect_in_pixels);
+        gfx::Rect wayland_popup_bounds = transform.MapRect(bounds_dip);
 
         std::unique_ptr<WaylandWindow> wayland_popup =
             CreateWaylandWindowWithParams(PlatformWindowType::kMenu,
diff --git a/ui/snapshot/snapshot_win.cc b/ui/snapshot/snapshot_win.cc
index 54da0be80035c..2e7f469bb4cdc 100644
--- a/ui/snapshot/snapshot_win.cc
+++ b/ui/snapshot/snapshot_win.cc
@@ -106,13 +106,10 @@ bool GrabWindowSnapshot(gfx::NativeWindow window_handle,
   DCHECK(host);
   HWND hwnd = host->GetAcceleratedWidget();
 
-  gfx::RectF window_bounds_in_pixels(window_bounds);
-  host->GetRootTransform().TransformRect(&window_bounds_in_pixels);
-  gfx::RectF snapshot_bounds_in_pixels(snapshot_bounds);
-  host->GetRootTransform().TransformRect(&snapshot_bounds_in_pixels);
-
+  gfx::Rect snapshot_bounds_in_pixels =
+      host->GetRootTransform().MapRect(snapshot_bounds);
   gfx::Rect expanded_window_bounds_in_pixels =
-      gfx::ToEnclosingRect(window_bounds_in_pixels);
+      host->GetRootTransform().MapRect(window_bounds);
   RECT client_area;
   ::GetClientRect(hwnd, &client_area);
   gfx::Rect client_area_rect(client_area);
@@ -120,9 +117,8 @@ bool GrabWindowSnapshot(gfx::NativeWindow window_handle,
 
   expanded_window_bounds_in_pixels.Intersect(client_area_rect);
 
-  return internal::GrabHwndSnapshot(
-      hwnd, gfx::ToEnclosingRect(snapshot_bounds_in_pixels),
-      expanded_window_bounds_in_pixels, image);
+  return internal::GrabHwndSnapshot(hwnd, snapshot_bounds_in_pixels,
+                                    expanded_window_bounds_in_pixels, image);
 }
 
 void GrabWindowSnapshotAsync(gfx::NativeWindow window,
diff --git a/ui/views/view.cc b/ui/views/view.cc
index fdf06c84f3c60..05f6fd843c228 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -514,11 +514,10 @@ gfx::Rect View::GetVisibleBounds() const {
   }
   if (vis_bounds.IsEmpty())
     return vis_bounds;
-  // Convert back to this views coordinate system.
-  gfx::RectF views_vis_bounds(vis_bounds);
-  transform.TransformRectReverse(&views_vis_bounds);
-  // Partially visible pixels should be considered visible.
-  return gfx::ToEnclosingRect(views_vis_bounds);
+  // Convert back to this views coordinate system. This mapping returns the
+  // enclosing rect, which is good because partially visible pixels should
+  // be considered visible.
+  return transform.InverseMapRect(vis_bounds).value_or(vis_bounds);
 }
 
 gfx::Rect View::GetBoundsInScreen() const {
@@ -1114,11 +1113,11 @@ void View::ConvertRectToScreen(const View* src, gfx::Rect* rect) {
 }
 
 gfx::Rect View::ConvertRectToParent(const gfx::Rect& rect) const {
-  gfx::RectF x_rect = gfx::RectF(rect);
-  GetTransform().TransformRect(&x_rect);
+  // This mapping returns the enclosing rect, which is good because pixels that
+  // partially occupy in the parent should be included.
+  gfx::Rect x_rect = GetTransform().MapRect(rect);
   x_rect.Offset(GetMirroredPosition().OffsetFromOrigin());
-  // Pixels we partially occupy in the parent should be included.
-  return gfx::ToEnclosingRect(x_rect);
+  return x_rect;
 }
 
 gfx::Rect View::ConvertRectToWidget(const gfx::Rect& rect) const {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index ba4389755c4f5..774a2d23a87a6 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -952,16 +952,14 @@ void DesktopWindowTreeHostPlatform::OnWorkspaceChanged() {
 
 gfx::Rect DesktopWindowTreeHostPlatform::ToDIPRect(
     const gfx::Rect& rect_in_pixels) const {
-  gfx::RectF rect_in_dip = gfx::RectF(rect_in_pixels);
-  GetRootTransform().TransformRectReverse(&rect_in_dip);
-  return gfx::ToEnclosingRect(rect_in_dip);
+  return GetRootTransform()
+      .InverseMapRect(rect_in_pixels)
+      .value_or(rect_in_pixels);
 }
 
 gfx::Rect DesktopWindowTreeHostPlatform::ToPixelRect(
     const gfx::Rect& rect_in_dip) const {
-  gfx::RectF rect_in_pixels = gfx::RectF(rect_in_dip);
-  GetRootTransform().TransformRect(&rect_in_pixels);
-  return gfx::ToEnclosingRect(rect_in_pixels);
+  return GetRootTransform().MapRect(rect_in_dip);
 }
 
 Widget* DesktopWindowTreeHostPlatform::GetWidget() {
diff --git a/ui/wm/core/window_animations.cc b/ui/wm/core/window_animations.cc
index eefc96316babd..7a4fcde8588fb 100644
--- a/ui/wm/core/window_animations.cc
+++ b/ui/wm/core/window_animations.cc
@@ -248,10 +248,7 @@ gfx::Rect GetLayerWorldBoundsAfterTransform(ui::Layer* layer,
   gfx::Transform in_world = transform;
   GetTransformRelativeToRoot(layer, &in_world);
 
-  gfx::RectF transformed = gfx::RectF(layer->bounds());
-  in_world.TransformRect(&transformed);
-
-  return gfx::ToEnclosingRect(transformed);
+  return in_world.MapRect(layer->bounds());
 }
 
 // Augment the host window so that the enclosing bounds of the full