Skip to content

Commit

Permalink
Add gfx::Transform::[Inverse]MapRect(const gfx::Rect&)
Browse files Browse the repository at this point in the history
This follows blink::TransformationMatrix(const gfx::Rect&), to
prepare for combination of gfx::Transform and
blink::TransformationMatrix.

Code like the following
  gfx::RectF rect_f(rect);
  transform.TransformRect(&rect_f);
  gfx::Rect out_rect = gfx::ToEnclosingRect(rect_f);
is replaced with
  gfx::Rect out_rect = gfx::MapRect(rect);

Code in some unittests using gfx::ToRoundedRect(),
gfx::ToEnclosedRect() or gfx::ToNearestRect() instead of
gfx::ToEnclosingRect() as the last step are also replace with
the new code as long as the tests still pass. Similar code in
production code is kept as-is.

Bug: 1359528
Change-Id: Ic86333d48da459fc571240d80d513ca5efded699
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3935017
Owners-Override: danakj <danakj@chromium.org>
Reviewed-by: danakj <danakj@chromium.org>
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1055517}
  • Loading branch information
wangxianzhu authored and Chromium LUCI CQ committed Oct 5, 2022
1 parent 9dac27a commit 901b935
Show file tree
Hide file tree
Showing 32 changed files with 157 additions and 169 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
16 changes: 7 additions & 9 deletions ash/app_list/views/app_drag_icon_proxy_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
};

Expand Down
5 changes: 2 additions & 3 deletions ash/host/ash_window_tree_host_platform.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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_);
}
Expand Down
5 changes: 1 addition & 4 deletions ash/screen_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
14 changes: 6 additions & 8 deletions ash/shelf/home_to_overview_nudge_controller_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
5 changes: 2 additions & 3 deletions ash/shelf/hotseat_widget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 2 additions & 3 deletions ash/shelf/shelf_widget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions ash/wm/desks/desks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 1 addition & 3 deletions ash/wm/desks/root_window_desk_switch_animator_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 2 additions & 3 deletions ash/wm/overview/overview_session_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
Expand Down
4 changes: 1 addition & 3 deletions ash/wm/overview/overview_test_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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) {
Expand Down
7 changes: 3 additions & 4 deletions components/exo/surface_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -1258,16 +1258,15 @@ 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 {
EXPECT_EQ(expected_transform,
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);
}
}
Expand Down
23 changes: 9 additions & 14 deletions components/viz/service/display/dc_layer_overlay.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 =
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
14 changes: 6 additions & 8 deletions components/viz/service/display/overlay_strategy_underlay_cast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}
}

Expand Down
11 changes: 5 additions & 6 deletions components/viz/service/display/surface_aggregator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2406,24 +2406,23 @@ 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) {
auto target_id = AggregatedRenderPassId(uint64_t{
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));
Expand Down
7 changes: 2 additions & 5 deletions content/browser/renderer_host/render_widget_host_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
4 changes: 1 addition & 3 deletions content/browser/site_per_process_hit_test_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
9 changes: 2 additions & 7 deletions third_party/blink/renderer/core/frame/local_frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
6 changes: 2 additions & 4 deletions ui/aura/window_occlusion_tracker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
4 changes: 1 addition & 3 deletions ui/aura/window_tree_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 901b935

Please sign in to comment.