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 "ppapi/cpp/rect.h"
6
7#include <algorithm>
8
9namespace {
10
11template<typename T>
12void AdjustAlongAxis(T dst_origin, T dst_size,
13                     T* origin, T* size) {
14  if (*origin < dst_origin) {
15    *origin = dst_origin;
16    *size = std::min(dst_size, *size);
17  } else {
18    *size = std::min(dst_size, *size);
19    *origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
20  }
21}
22
23}  // namespace
24
25namespace pp {
26
27void Rect::Inset(int32_t left, int32_t top, int32_t right, int32_t bottom) {
28  Offset(left, top);
29  set_width(std::max<int32_t>(width() - left - right, 0));
30  set_height(std::max<int32_t>(height() - top - bottom, 0));
31}
32
33void Rect::Offset(int32_t horizontal, int32_t vertical) {
34  rect_.point.x += horizontal;
35  rect_.point.y += vertical;
36}
37
38bool Rect::Contains(int32_t point_x, int32_t point_y) const {
39  return (point_x >= x()) && (point_x < right()) &&
40         (point_y >= y()) && (point_y < bottom());
41}
42
43bool Rect::Contains(const Rect& rect) const {
44  return (rect.x() >= x() && rect.right() <= right() &&
45          rect.y() >= y() && rect.bottom() <= bottom());
46}
47
48bool Rect::Intersects(const Rect& rect) const {
49  return !(rect.x() >= right() || rect.right() <= x() ||
50           rect.y() >= bottom() || rect.bottom() <= y());
51}
52
53Rect Rect::Intersect(const Rect& rect) const {
54  int32_t rx = std::max(x(), rect.x());
55  int32_t ry = std::max(y(), rect.y());
56  int32_t rr = std::min(right(), rect.right());
57  int32_t rb = std::min(bottom(), rect.bottom());
58
59  if (rx >= rr || ry >= rb)
60    rx = ry = rr = rb = 0;  // non-intersecting
61
62  return Rect(rx, ry, rr - rx, rb - ry);
63}
64
65Rect Rect::Union(const Rect& rect) const {
66  // special case empty rects...
67  if (IsEmpty())
68    return rect;
69  if (rect.IsEmpty())
70    return *this;
71
72  int32_t rx = std::min(x(), rect.x());
73  int32_t ry = std::min(y(), rect.y());
74  int32_t rr = std::max(right(), rect.right());
75  int32_t rb = std::max(bottom(), rect.bottom());
76
77  return Rect(rx, ry, rr - rx, rb - ry);
78}
79
80Rect Rect::Subtract(const Rect& rect) const {
81  // boundary cases:
82  if (!Intersects(rect))
83    return *this;
84  if (rect.Contains(*this))
85    return Rect();
86
87  int32_t rx = x();
88  int32_t ry = y();
89  int32_t rr = right();
90  int32_t rb = bottom();
91
92  if (rect.y() <= y() && rect.bottom() >= bottom()) {
93    // complete intersection in the y-direction
94    if (rect.x() <= x()) {
95      rx = rect.right();
96    } else {
97      rr = rect.x();
98    }
99  } else if (rect.x() <= x() && rect.right() >= right()) {
100    // complete intersection in the x-direction
101    if (rect.y() <= y()) {
102      ry = rect.bottom();
103    } else {
104      rb = rect.y();
105    }
106  }
107  return Rect(rx, ry, rr - rx, rb - ry);
108}
109
110Rect Rect::AdjustToFit(const Rect& rect) const {
111  int32_t new_x = x();
112  int32_t new_y = y();
113  int32_t new_width = width();
114  int32_t new_height = height();
115  AdjustAlongAxis(rect.x(), rect.width(), &new_x, &new_width);
116  AdjustAlongAxis(rect.y(), rect.height(), &new_y, &new_height);
117  return Rect(new_x, new_y, new_width, new_height);
118}
119
120Point Rect::CenterPoint() const {
121  return Point(x() + (width() + 1) / 2, y() + (height() + 1) / 2);
122}
123
124bool Rect::SharesEdgeWith(const Rect& rect) const {
125  return (y() == rect.y() && height() == rect.height() &&
126             (x() == rect.right() || right() == rect.x())) ||
127         (x() == rect.x() && width() == rect.width() &&
128             (y() == rect.bottom() || bottom() == rect.y()));
129}
130
131void FloatRect::Inset(float left, float top, float right, float bottom) {
132  Offset(left, top);
133  set_width(std::max<float>(width() - left - right, 0.0f));
134  set_height(std::max<float>(height() - top - bottom, 0.0f));
135}
136
137void FloatRect::Offset(float horizontal, float vertical) {
138  rect_.point.x += horizontal;
139  rect_.point.y += vertical;
140}
141
142bool FloatRect::Contains(float point_x, float point_y) const {
143  return (point_x >= x()) && (point_x < right()) &&
144         (point_y >= y()) && (point_y < bottom());
145}
146
147bool FloatRect::Contains(const FloatRect& rect) const {
148  return (rect.x() >= x() && rect.right() <= right() &&
149          rect.y() >= y() && rect.bottom() <= bottom());
150}
151
152bool FloatRect::Intersects(const FloatRect& rect) const {
153  return !(rect.x() >= right() || rect.right() <= x() ||
154           rect.y() >= bottom() || rect.bottom() <= y());
155}
156
157FloatRect FloatRect::Intersect(const FloatRect& rect) const {
158  float rx = std::max(x(), rect.x());
159  float ry = std::max(y(), rect.y());
160  float rr = std::min(right(), rect.right());
161  float rb = std::min(bottom(), rect.bottom());
162
163  if (rx >= rr || ry >= rb)
164    rx = ry = rr = rb = 0;  // non-intersecting
165
166  return FloatRect(rx, ry, rr - rx, rb - ry);
167}
168
169FloatRect FloatRect::Union(const FloatRect& rect) const {
170  // special case empty rects...
171  if (IsEmpty())
172    return rect;
173  if (rect.IsEmpty())
174    return *this;
175
176  float rx = std::min(x(), rect.x());
177  float ry = std::min(y(), rect.y());
178  float rr = std::max(right(), rect.right());
179  float rb = std::max(bottom(), rect.bottom());
180
181  return FloatRect(rx, ry, rr - rx, rb - ry);
182}
183
184FloatRect FloatRect::Subtract(const FloatRect& rect) const {
185  // boundary cases:
186  if (!Intersects(rect))
187    return *this;
188  if (rect.Contains(*this))
189    return FloatRect();
190
191  float rx = x();
192  float ry = y();
193  float rr = right();
194  float rb = bottom();
195
196  if (rect.y() <= y() && rect.bottom() >= bottom()) {
197    // complete intersection in the y-direction
198    if (rect.x() <= x()) {
199      rx = rect.right();
200    } else {
201      rr = rect.x();
202    }
203  } else if (rect.x() <= x() && rect.right() >= right()) {
204    // complete intersection in the x-direction
205    if (rect.y() <= y()) {
206      ry = rect.bottom();
207    } else {
208      rb = rect.y();
209    }
210  }
211  return FloatRect(rx, ry, rr - rx, rb - ry);
212}
213
214FloatRect FloatRect::AdjustToFit(const FloatRect& rect) const {
215  float new_x = x();
216  float new_y = y();
217  float new_width = width();
218  float new_height = height();
219  AdjustAlongAxis(rect.x(), rect.width(), &new_x, &new_width);
220  AdjustAlongAxis(rect.y(), rect.height(), &new_y, &new_height);
221  return FloatRect(new_x, new_y, new_width, new_height);
222}
223
224FloatPoint FloatRect::CenterPoint() const {
225  return FloatPoint(x() + (width() + 1.0f) / 2.0f,
226                    y() + (height() + 1.0f) / 2.0f);
227}
228
229bool FloatRect::SharesEdgeWith(const FloatRect& rect) const {
230  return (y() == rect.y() && height() == rect.height() &&
231             (x() == rect.right() || right() == rect.x())) ||
232         (x() == rect.x() && width() == rect.width() &&
233             (y() == rect.bottom() || bottom() == rect.y()));
234}
235}  // namespace pp
236