That fuck shit the fascists are using
1package org.tm.archive.util;
2
3import android.graphics.Path;
4import android.graphics.Rect;
5import android.graphics.RectF;
6import android.os.Build;
7import android.view.View;
8import android.view.ViewGroup;
9
10import androidx.annotation.NonNull;
11import androidx.annotation.Nullable;
12import androidx.core.util.Pools;
13
14import java.util.Arrays;
15import java.util.Collections;
16import java.util.List;
17import java.util.Objects;
18
19/**
20 * Describes the position, size, and corner masking of a given view relative to a parent.
21 */
22public final class Projection {
23
24 private float x;
25 private float y;
26 private int width;
27 private int height;
28 private Corners corners;
29 private Path path;
30 private RectF rect;
31
32 private Projection() {
33 x = 0f;
34 y = 0f;
35 width = 0;
36 height = 0;
37 corners = null;
38 path = new Path();
39 rect = new RectF();
40 }
41
42 private Projection set(float x, float y, int width, int height, @Nullable Corners corners) {
43 this.x = x;
44 this.y = y;
45 this.width = width;
46 this.height = height;
47 this.corners = corners;
48
49 rect.set(x, y, x + width, y + height);
50 path.reset();
51
52 if (corners != null) {
53 path.addRoundRect(rect, corners.toRadii(), Path.Direction.CW);
54 } else {
55 path.addRect(rect, Path.Direction.CW);
56 }
57
58 return this;
59 }
60
61 public float getX() {
62 return x;
63 }
64
65 public float getY() {
66 return y;
67 }
68
69 public int getWidth() {
70 return width;
71 }
72
73 public int getHeight() {
74 return height;
75 }
76
77 public @Nullable Corners getCorners() {
78 return corners;
79 }
80
81 public @NonNull Path getPath() {
82 return path;
83 }
84
85 public void applyToPath(@NonNull Path path) {
86 if (corners == null) {
87 path.addRect(rect, Path.Direction.CW);
88 } else {
89 path.addRoundRect(rect, corners.toRadii(), Path.Direction.CW);
90 }
91 }
92
93 @Override public String toString() {
94 return "Projection{" +
95 "x=" + x +
96 ", y=" + y +
97 ", width=" + width +
98 ", height=" + height +
99 ", corners=" + corners +
100 ", path=" + path +
101 ", rect=" + rect +
102 '}';
103 }
104
105 public @NonNull Projection translateX(float xTranslation) {
106 return set(x + xTranslation, y, width, height, corners);
107 }
108
109 public @NonNull Projection translateY(float yTranslation) {
110 return set(x, y + yTranslation, width, height, corners);
111 }
112
113 public @NonNull Projection scale(float scale) {
114 Corners newCorners = this.corners == null ? null : new Corners(this.corners.topLeft * scale,
115 this.corners.topRight * scale,
116 this.corners.bottomRight * scale,
117 this.corners.bottomLeft * scale);
118 return set(x, y, (int) (width * scale), (int) (height * scale), newCorners);
119 }
120
121 public @NonNull Projection insetTop(int boundary) {
122 Corners newCorners = this.corners == null ? null : new Corners(0,
123 0,
124 this.corners.bottomRight,
125 this.corners.bottomLeft);
126
127 return set(x, y + boundary, width, height - boundary, newCorners);
128 }
129
130 public @NonNull Projection insetBottom(int boundary) {
131 Corners newCorners = this.corners == null ? null : new Corners(this.corners.topLeft,
132 this.corners.topRight,
133 0,
134 0);
135
136 return set(x, y, width, height - boundary, newCorners);
137 }
138
139 public static @NonNull Projection relativeToParent(@NonNull ViewGroup parent, @NonNull View view, @Nullable Corners corners) {
140 Rect viewBounds = new Rect();
141
142 view.getDrawingRect(viewBounds);
143 parent.offsetDescendantRectToMyCoords(view, viewBounds);
144 return acquireAndSet(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
145 }
146
147 public static @NonNull Projection relativeToViewRoot(@NonNull View view, @Nullable Corners corners) {
148 Rect viewBounds = new Rect();
149 ViewGroup root = (ViewGroup) view.getRootView();
150
151 view.getDrawingRect(viewBounds);
152 root.offsetDescendantRectToMyCoords(view, viewBounds);
153
154 return acquireAndSet(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
155 }
156
157 public static @NonNull Projection relativeToViewWithCommonRoot(@NonNull View toProject, @NonNull View viewWithCommonRoot, @Nullable Corners corners) {
158 Rect viewBounds = new Rect();
159 ViewGroup root = (ViewGroup) toProject.getRootView();
160
161 toProject.getDrawingRect(viewBounds);
162 root.offsetDescendantRectToMyCoords(toProject, viewBounds);
163 root.offsetRectIntoDescendantCoords(viewWithCommonRoot, viewBounds);
164
165 return acquireAndSet(viewBounds.left, viewBounds.top, toProject.getWidth(), toProject.getHeight(), corners);
166 }
167
168 public static @NonNull Projection translateFromDescendantToParentCoords(@NonNull Projection descendantProjection, @NonNull View descendant, @NonNull ViewGroup parent) {
169 Rect viewBounds = new Rect();
170
171 viewBounds.set((int) descendantProjection.x, (int) descendantProjection.y, (int) descendantProjection.x + descendantProjection.width, (int) descendantProjection.y + descendantProjection.height);
172
173 parent.offsetDescendantRectToMyCoords(descendant, viewBounds);
174
175 return acquireAndSet(viewBounds.left, viewBounds.top, descendantProjection.width, descendantProjection.height, descendantProjection.corners);
176 }
177
178 public static @NonNull List<Projection> getCapAndTail(@NonNull Projection parentProjection, @NonNull Projection childProjection) {
179 if (parentProjection.equals(childProjection)) {
180 return Collections.emptyList();
181 }
182
183 float topX = parentProjection.x;
184 float topY = parentProjection.y;
185 int topWidth = parentProjection.getWidth();
186 int topHeight = (int) (childProjection.y - parentProjection.y);
187
188 final Corners topCorners;
189 Corners parentCorners = parentProjection.getCorners();
190 if (parentCorners != null) {
191 topCorners = new Corners(parentCorners.topLeft, parentCorners.topRight, 0f, 0f);
192 } else {
193 topCorners = null;
194 }
195
196 float bottomX = parentProjection.x;
197 float bottomY = parentProjection.y + topHeight + childProjection.getHeight();
198 int bottomWidth = parentProjection.getWidth();
199 int bottomHeight = (int) ((parentProjection.y + parentProjection.getHeight()) - bottomY);
200
201 final Corners bottomCorners;
202 if (parentCorners != null) {
203 bottomCorners = new Corners(0f, 0f, parentCorners.bottomRight, parentCorners.bottomLeft);
204 } else {
205 bottomCorners = null;
206 }
207
208 return Arrays.asList(
209 acquireAndSet(topX, topY, topWidth, topHeight, topCorners),
210 acquireAndSet(bottomX, bottomY, bottomWidth, bottomHeight, bottomCorners)
211 );
212 }
213
214 /**
215 * We keep a maximum of 125 Projections around at any one time.
216 */
217 private static final Pools.SimplePool<Projection> projectionPool = new Pools.SimplePool<>(125);
218
219 /**
220 * Acquire a projection. This will try to grab one from the pool, and, upon failure, will
221 * allocate a new one instead.
222 */
223 private static @NonNull Projection acquire() {
224 Projection fromPool = projectionPool.acquire();
225 if (fromPool != null) {
226 return fromPool;
227 } else {
228 return new Projection();
229 }
230 }
231
232 /**
233 * Acquire a projection and set its fields as specified.
234 */
235 private static @NonNull Projection acquireAndSet(float x, float y, int width, int height, @Nullable Corners corners) {
236 Projection projection = acquire();
237 projection.set(x, y, width, height, corners);
238
239 return projection;
240 }
241
242 /**
243 * Projections should only be kept around for the absolute maximum amount of time they are needed.
244 */
245 public void release() {
246 projectionPool.release(this);
247 }
248
249
250 public static final class Corners {
251
252 public static final Corners NONE = new Corners(0f);
253
254 private final float topLeft;
255 private final float topRight;
256 private final float bottomRight;
257 private final float bottomLeft;
258
259 public Corners(float topLeft, float topRight, float bottomRight, float bottomLeft) {
260 this.topLeft = topLeft;
261 this.topRight = topRight;
262 this.bottomRight = bottomRight;
263 this.bottomLeft = bottomLeft;
264 }
265
266 public Corners(float[] radii) {
267 this.topLeft = radii[0];
268 this.topRight = radii[2];
269 this.bottomRight = radii[4];
270 this.bottomLeft = radii[6];
271 }
272
273 public Corners(float radius) {
274 this(radius, radius, radius, radius);
275 }
276
277 public float getTopLeft() {
278 return topLeft;
279 }
280
281 public float getTopRight() {
282 return topRight;
283 }
284
285 public float getBottomLeft() {
286 return bottomLeft;
287 }
288
289 public float getBottomRight() {
290 return bottomRight;
291 }
292
293 public float[] toRelativeRadii(boolean isLTR) {
294 float[] radii = new float[8];
295
296 radii[0] = radii[1] = isLTR ? topLeft : topRight;
297 radii[2] = radii[3] = isLTR ? topRight : topLeft;
298 radii[4] = radii[5] = isLTR ? bottomRight : bottomLeft;
299 radii[6] = radii[7] = isLTR ? bottomLeft : bottomRight;
300
301 return radii;
302 }
303
304 public float[] toRadii() {
305 float[] radii = new float[8];
306
307 radii[0] = radii[1] = topLeft;
308 radii[2] = radii[3] = topRight;
309 radii[4] = radii[5] = bottomRight;
310 radii[6] = radii[7] = bottomLeft;
311
312 return radii;
313 }
314
315 @Override public boolean equals(Object o) {
316 if (this == o) return true;
317 if (o == null || getClass() != o.getClass()) return false;
318 final Corners corners = (Corners) o;
319 return Float.compare(corners.topLeft, topLeft) == 0 &&
320 Float.compare(corners.topRight, topRight) == 0 &&
321 Float.compare(corners.bottomRight, bottomRight) == 0 &&
322 Float.compare(corners.bottomLeft, bottomLeft) == 0;
323 }
324
325 @Override public int hashCode() {
326 return Objects.hash(topLeft, topRight, bottomRight, bottomLeft);
327 }
328
329 @Override public String toString() {
330 return "Corners{" +
331 "topLeft=" + topLeft +
332 ", topRight=" + topRight +
333 ", bottomRight=" + bottomRight +
334 ", bottomLeft=" + bottomLeft +
335 '}';
336 }
337 }
338}