Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/StdLibExtras.h>
28#include <AK/String.h>
29#include <AK/Vector.h>
30#include <LibGfx/Rect.h>
31#include <LibIPC/Decoder.h>
32
33namespace Gfx {
34
35void Rect::intersect(const Rect& other)
36{
37 int l = max(left(), other.left());
38 int r = min(right(), other.right());
39 int t = max(top(), other.top());
40 int b = min(bottom(), other.bottom());
41
42 if (l > r || t > b) {
43 m_location = {};
44 m_size = {};
45 return;
46 }
47
48 m_location.set_x(l);
49 m_location.set_y(t);
50 m_size.set_width((r - l) + 1);
51 m_size.set_height((b - t) + 1);
52}
53
54Rect Rect::united(const Rect& other) const
55{
56 if (is_null())
57 return other;
58 if (other.is_null())
59 return *this;
60 Rect rect;
61 rect.set_left(min(left(), other.left()));
62 rect.set_top(min(top(), other.top()));
63 rect.set_right(max(right(), other.right()));
64 rect.set_bottom(max(bottom(), other.bottom()));
65 return rect;
66}
67
68Vector<Rect, 4> Rect::shatter(const Rect& hammer) const
69{
70 Vector<Rect, 4> pieces;
71 if (!intersects(hammer)) {
72 pieces.unchecked_append(*this);
73 return pieces;
74 }
75 Rect top_shard {
76 x(),
77 y(),
78 width(),
79 hammer.y() - y()
80 };
81 Rect bottom_shard {
82 x(),
83 hammer.y() + hammer.height(),
84 width(),
85 (y() + height()) - (hammer.y() + hammer.height())
86 };
87 Rect left_shard {
88 x(),
89 max(hammer.y(), y()),
90 hammer.x() - x(),
91 min((hammer.y() + hammer.height()), (y() + height())) - max(hammer.y(), y())
92 };
93 Rect right_shard {
94 hammer.x() + hammer.width(),
95 max(hammer.y(), y()),
96 right() - hammer.right(),
97 min((hammer.y() + hammer.height()), (y() + height())) - max(hammer.y(), y())
98 };
99 if (intersects(top_shard))
100 pieces.unchecked_append(top_shard);
101 if (intersects(bottom_shard))
102 pieces.unchecked_append(bottom_shard);
103 if (intersects(left_shard))
104 pieces.unchecked_append(left_shard);
105 if (intersects(right_shard))
106 pieces.unchecked_append(right_shard);
107
108 return pieces;
109}
110
111void Rect::align_within(const Rect& other, TextAlignment alignment)
112{
113 switch (alignment) {
114 case TextAlignment::Center:
115 center_within(other);
116 return;
117 case TextAlignment::TopLeft:
118 set_location(other.location());
119 return;
120 case TextAlignment::TopRight:
121 set_x(other.x() + other.width() - width());
122 set_y(other.y());
123 return;
124 case TextAlignment::CenterLeft:
125 set_x(other.x());
126 center_vertically_within(other);
127 return;
128 case TextAlignment::CenterRight:
129 set_x(other.x() + other.width() - width());
130 center_vertically_within(other);
131 return;
132 }
133}
134
135String Rect::to_string() const
136{
137 return String::format("[%d,%d %dx%d]", x(), y(), width(), height());
138}
139
140const LogStream& operator<<(const LogStream& stream, const Rect& value)
141{
142 return stream << value.to_string();
143}
144
145}
146
147namespace IPC {
148
149bool decode(Decoder& decoder, Gfx::Rect& rect)
150{
151 Gfx::Point point;
152 Gfx::Size size;
153 if (!decoder.decode(point))
154 return false;
155 if (!decoder.decode(size))
156 return false;
157 rect = { point, size };
158 return true;
159}
160
161}