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
32namespace Gfx {
33
34void Rect::intersect(const Rect& other)
35{
36 int l = max(left(), other.left());
37 int r = min(right(), other.right());
38 int t = max(top(), other.top());
39 int b = min(bottom(), other.bottom());
40
41 if (l > r || t > b) {
42 m_location = {};
43 m_size = {};
44 return;
45 }
46
47 m_location.set_x(l);
48 m_location.set_y(t);
49 m_size.set_width((r - l) + 1);
50 m_size.set_height((b - t) + 1);
51}
52
53Rect Rect::united(const Rect& other) const
54{
55 if (is_null())
56 return other;
57 if (other.is_null())
58 return *this;
59 Rect rect;
60 rect.set_left(min(left(), other.left()));
61 rect.set_top(min(top(), other.top()));
62 rect.set_right(max(right(), other.right()));
63 rect.set_bottom(max(bottom(), other.bottom()));
64 return rect;
65}
66
67Vector<Rect, 4> Rect::shatter(const Rect& hammer) const
68{
69 Vector<Rect, 4> pieces;
70 if (!intersects(hammer)) {
71 pieces.unchecked_append(*this);
72 return pieces;
73 }
74 Rect top_shard {
75 x(),
76 y(),
77 width(),
78 hammer.y() - y()
79 };
80 Rect bottom_shard {
81 x(),
82 hammer.y() + hammer.height(),
83 width(),
84 (y() + height()) - (hammer.y() + hammer.height())
85 };
86 Rect left_shard {
87 x(),
88 max(hammer.y(), y()),
89 hammer.x() - x(),
90 min((hammer.y() + hammer.height()), (y() + height())) - max(hammer.y(), y())
91 };
92 Rect right_shard {
93 hammer.x() + hammer.width(),
94 max(hammer.y(), y()),
95 right() - hammer.right(),
96 min((hammer.y() + hammer.height()), (y() + height())) - max(hammer.y(), y())
97 };
98 if (intersects(top_shard))
99 pieces.unchecked_append(top_shard);
100 if (intersects(bottom_shard))
101 pieces.unchecked_append(bottom_shard);
102 if (intersects(left_shard))
103 pieces.unchecked_append(left_shard);
104 if (intersects(right_shard))
105 pieces.unchecked_append(right_shard);
106
107 return pieces;
108}
109
110void Rect::align_within(const Rect& other, TextAlignment alignment)
111{
112 switch (alignment) {
113 case TextAlignment::Center:
114 center_within(other);
115 return;
116 case TextAlignment::TopLeft:
117 set_location(other.location());
118 return;
119 case TextAlignment::TopRight:
120 set_x(other.x() + other.width() - width());
121 set_y(other.y());
122 return;
123 case TextAlignment::CenterLeft:
124 set_x(other.x());
125 center_vertically_within(other);
126 return;
127 case TextAlignment::CenterRight:
128 set_x(other.x() + other.width() - width());
129 center_vertically_within(other);
130 return;
131 }
132}
133
134String Rect::to_string() const
135{
136 return String::format("[%d,%d %dx%d]", x(), y(), width(), height());
137}
138
139const LogStream& operator<<(const LogStream& stream, const Rect& value)
140{
141 return stream << value.to_string();
142}
143
144}
145
146namespace IPC {
147
148bool decode(BufferStream& stream, Gfx::Rect& rect)
149{
150 Gfx::Point point;
151 Gfx::Size size;
152 if (!decode(stream, point))
153 return false;
154 if (!decode(stream, size))
155 return false;
156 rect = { point, size };
157 return true;
158}
159
160}