1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/compositor/dip_util.h"
6
7#include "base/command_line.h"
8#include "cc/layers/layer.h"
9#include "ui/compositor/compositor.h"
10#include "ui/compositor/compositor_switches.h"
11#include "ui/compositor/layer.h"
12#include "ui/gfx/display.h"
13#include "ui/gfx/geometry/safe_integer_conversions.h"
14#include "ui/gfx/point.h"
15#include "ui/gfx/point_conversions.h"
16#include "ui/gfx/rect.h"
17#include "ui/gfx/rect_conversions.h"
18#include "ui/gfx/size.h"
19#include "ui/gfx/size_conversions.h"
20
21#if DCHECK_IS_ON
22#include "ui/compositor/layer_animator.h"
23#endif
24
25namespace ui {
26
27float GetDeviceScaleFactor(const Layer* layer) {
28  return layer->device_scale_factor();
29}
30
31gfx::Point ConvertPointToDIP(const Layer* layer,
32                             const gfx::Point& point_in_pixel) {
33  return gfx::ToFlooredPoint(
34      gfx::ScalePoint(point_in_pixel, 1.0f / GetDeviceScaleFactor(layer)));
35}
36
37gfx::PointF ConvertPointToDIP(const Layer* layer,
38                              const gfx::PointF& point_in_pixel) {
39  return gfx::ScalePoint(point_in_pixel, 1.0f / GetDeviceScaleFactor(layer));
40}
41
42gfx::Size ConvertSizeToDIP(const Layer* layer,
43                           const gfx::Size& size_in_pixel) {
44  return gfx::ToFlooredSize(
45      gfx::ScaleSize(size_in_pixel, 1.0f / GetDeviceScaleFactor(layer)));
46}
47
48gfx::Rect ConvertRectToDIP(const Layer* layer,
49                           const gfx::Rect& rect_in_pixel) {
50  float scale = 1.0f / GetDeviceScaleFactor(layer);
51  return gfx::ToFlooredRectDeprecated(gfx::ScaleRect(rect_in_pixel, scale));
52}
53
54gfx::Point ConvertPointToPixel(const Layer* layer,
55                               const gfx::Point& point_in_dip) {
56  return gfx::ToFlooredPoint(
57      gfx::ScalePoint(point_in_dip, GetDeviceScaleFactor(layer)));
58}
59
60gfx::Size ConvertSizeToPixel(const Layer* layer,
61                             const gfx::Size& size_in_dip) {
62  return gfx::ToFlooredSize(
63      gfx::ScaleSize(size_in_dip, GetDeviceScaleFactor(layer)));
64}
65
66gfx::Rect ConvertRectToPixel(const Layer* layer,
67                             const gfx::Rect& rect_in_dip) {
68  float scale = GetDeviceScaleFactor(layer);
69  // Use ToEnclosingRect() to ensure we paint all the possible pixels
70  // touched. ToEnclosingRect() floors the origin, and ceils the max
71  // coordinate. To do otherwise (such as flooring the size) potentially
72  // results in rounding down and not drawing all the pixels that are
73  // touched.
74  return gfx::ToEnclosingRect(
75      gfx::RectF(gfx::ScalePoint(rect_in_dip.origin(), scale),
76                 gfx::ScaleSize(rect_in_dip.size(), scale)));
77}
78
79#if DCHECK_IS_ON
80namespace {
81
82void CheckSnapped(float snapped_position) {
83  const float kEplison = 0.0001f;
84  float diff = std::abs(snapped_position - gfx::ToRoundedInt(snapped_position));
85  DCHECK_LT(diff, kEplison);
86}
87
88}  // namespace
89#endif
90
91void SnapLayerToPhysicalPixelBoundary(ui::Layer* snapped_layer,
92                                      ui::Layer* layer_to_snap) {
93  DCHECK_NE(snapped_layer, layer_to_snap);
94  DCHECK(snapped_layer);
95  DCHECK(snapped_layer->Contains(layer_to_snap));
96
97  gfx::Point view_offset_dips = layer_to_snap->GetTargetBounds().origin();
98  ui::Layer::ConvertPointToLayer(
99      layer_to_snap->parent(), snapped_layer, &view_offset_dips);
100  gfx::PointF view_offset = view_offset_dips;
101
102  float scale_factor = GetDeviceScaleFactor(layer_to_snap);
103  view_offset.Scale(scale_factor);
104  gfx::PointF view_offset_snapped(gfx::ToRoundedInt(view_offset.x()),
105                                  gfx::ToRoundedInt(view_offset.y()));
106
107  gfx::Vector2dF fudge = view_offset_snapped - view_offset;
108  fudge.Scale(1.0 / scale_factor);
109  layer_to_snap->SetSubpixelPositionOffset(fudge);
110#if DCHECK_IS_ON
111  gfx::Point layer_offset;
112  gfx::PointF origin;
113  Layer::ConvertPointToLayer(
114      layer_to_snap->parent(), snapped_layer, &layer_offset);
115  if (layer_to_snap->GetAnimator()->is_animating()) {
116    origin = layer_to_snap->GetTargetBounds().origin() +
117             layer_to_snap->subpixel_position_offset();
118  } else {
119    cc::Layer* cc_layer = layer_to_snap->cc_layer();
120    origin = cc_layer->position();
121  }
122  CheckSnapped((layer_offset.x() + origin.x()) * scale_factor);
123  CheckSnapped((layer_offset.y() + origin.y()) * scale_factor);
124#endif
125}
126
127}  // namespace ui
128