xref: /aosp_15_r20/system/teeui/libteeui/src/utils.cpp (revision 20bfefbe1966c142a35ae1ab84a8af250b3fd403)
1*20bfefbeSAndroid Build Coastguard Worker /*
2*20bfefbeSAndroid Build Coastguard Worker  *
3*20bfefbeSAndroid Build Coastguard Worker  * Copyright 2019, The Android Open Source Project
4*20bfefbeSAndroid Build Coastguard Worker  *
5*20bfefbeSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
6*20bfefbeSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
7*20bfefbeSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
8*20bfefbeSAndroid Build Coastguard Worker  *
9*20bfefbeSAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
10*20bfefbeSAndroid Build Coastguard Worker  *
11*20bfefbeSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
12*20bfefbeSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
13*20bfefbeSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*20bfefbeSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
15*20bfefbeSAndroid Build Coastguard Worker  * limitations under the License.
16*20bfefbeSAndroid Build Coastguard Worker  */
17*20bfefbeSAndroid Build Coastguard Worker 
18*20bfefbeSAndroid Build Coastguard Worker #include <teeui/utils.h>
19*20bfefbeSAndroid Build Coastguard Worker 
20*20bfefbeSAndroid Build Coastguard Worker namespace teeui {
21*20bfefbeSAndroid Build Coastguard Worker 
operator ==(const ByteBufferProxy & lhs,const ByteBufferProxy & rhs)22*20bfefbeSAndroid Build Coastguard Worker bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs) {
23*20bfefbeSAndroid Build Coastguard Worker     if (lhs.size() == rhs.size()) {
24*20bfefbeSAndroid Build Coastguard Worker         auto lhsi = lhs.begin();
25*20bfefbeSAndroid Build Coastguard Worker         auto rhsi = rhs.begin();
26*20bfefbeSAndroid Build Coastguard Worker         while (lhsi != lhs.end()) {
27*20bfefbeSAndroid Build Coastguard Worker             if (*lhsi++ != *rhsi++) return false;
28*20bfefbeSAndroid Build Coastguard Worker         }
29*20bfefbeSAndroid Build Coastguard Worker     }
30*20bfefbeSAndroid Build Coastguard Worker     return true;
31*20bfefbeSAndroid Build Coastguard Worker }
32*20bfefbeSAndroid Build Coastguard Worker 
33*20bfefbeSAndroid Build Coastguard Worker constexpr const DefaultNumericType kEpsilon = 0.000001;
34*20bfefbeSAndroid Build Coastguard Worker constexpr const DefaultNumericType kHalfSqrt2 = 0.70710678118;
35*20bfefbeSAndroid Build Coastguard Worker 
pixelLineIntersect(Point<pxs> line,pxs dist,Color c)36*20bfefbeSAndroid Build Coastguard Worker Color pixelLineIntersect(Point<pxs> line, pxs dist, Color c) {
37*20bfefbeSAndroid Build Coastguard Worker     TEEUI_LOG << "Line: " << line << " Dist: " << dist;
38*20bfefbeSAndroid Build Coastguard Worker     bool more_than_half = dist < 0.0;
39*20bfefbeSAndroid Build Coastguard Worker     TEEUI_LOG << " " << more_than_half;
40*20bfefbeSAndroid Build Coastguard Worker 
41*20bfefbeSAndroid Build Coastguard Worker     Color intensity = 0;
42*20bfefbeSAndroid Build Coastguard Worker     if (dist.abs() < kEpsilon) {
43*20bfefbeSAndroid Build Coastguard Worker         intensity = 0x80;
44*20bfefbeSAndroid Build Coastguard Worker         TEEUI_LOG << " half covered";
45*20bfefbeSAndroid Build Coastguard Worker     } else if (dist.abs() >= kHalfSqrt2) {
46*20bfefbeSAndroid Build Coastguard Worker         intensity = more_than_half ? 0xff : 0;
47*20bfefbeSAndroid Build Coastguard Worker         TEEUI_LOG << (more_than_half ? " fully covered" : " not covered");
48*20bfefbeSAndroid Build Coastguard Worker     } else {
49*20bfefbeSAndroid Build Coastguard Worker         auto dist_vec = line * dist;
50*20bfefbeSAndroid Build Coastguard Worker         TEEUI_LOG << " vec " << dist_vec;
51*20bfefbeSAndroid Build Coastguard Worker         dist_vec = Point<pxs>(dist_vec.x().abs(), dist_vec.y().abs());
52*20bfefbeSAndroid Build Coastguard Worker         TEEUI_LOG << " vec " << dist_vec;
53*20bfefbeSAndroid Build Coastguard Worker         if (dist_vec.x() < dist_vec.y()) {
54*20bfefbeSAndroid Build Coastguard Worker             dist_vec = Point<pxs>(dist_vec.y(), dist_vec.x());
55*20bfefbeSAndroid Build Coastguard Worker         }
56*20bfefbeSAndroid Build Coastguard Worker         auto a0 = dist_vec.x();
57*20bfefbeSAndroid Build Coastguard Worker         auto a1 = -dist_vec.y();
58*20bfefbeSAndroid Build Coastguard Worker         pxs area(.0);
59*20bfefbeSAndroid Build Coastguard Worker         if (a1 > -kEpsilon) {
60*20bfefbeSAndroid Build Coastguard Worker             TEEUI_LOG << " X";
61*20bfefbeSAndroid Build Coastguard Worker             area = a0;
62*20bfefbeSAndroid Build Coastguard Worker         } else {
63*20bfefbeSAndroid Build Coastguard Worker             Point<pxs> Q(a1 * (a1 + pxs(.5)) / a0 + a0, pxs(-.5));
64*20bfefbeSAndroid Build Coastguard Worker             if (Q.x() >= pxs(.5)) {
65*20bfefbeSAndroid Build Coastguard Worker                 // line does not intersect our pixel.
66*20bfefbeSAndroid Build Coastguard Worker                 intensity = more_than_half ? 0xff : 0;
67*20bfefbeSAndroid Build Coastguard Worker                 TEEUI_LOG << (more_than_half ? " fully covered (2)" : " not covered(2)");
68*20bfefbeSAndroid Build Coastguard Worker             } else {
69*20bfefbeSAndroid Build Coastguard Worker                 TEEUI_LOG << " partially covered";
70*20bfefbeSAndroid Build Coastguard Worker                 Point<pxs> P(pxs(.5), a1 - a0 * (pxs(.5) - a0) / a1);
71*20bfefbeSAndroid Build Coastguard Worker                 TEEUI_LOG << " P: " << P << " Q: " << Q;
72*20bfefbeSAndroid Build Coastguard Worker                 Point<pxs> R = P - Q;
73*20bfefbeSAndroid Build Coastguard Worker                 TEEUI_LOG << " R: " << R;
74*20bfefbeSAndroid Build Coastguard Worker                 area = R.x() * R.y() * pxs(.5);
75*20bfefbeSAndroid Build Coastguard Worker                 if (R.y() > 1.0) {
76*20bfefbeSAndroid Build Coastguard Worker                     auto r = R.y() - pxs(1.0);
77*20bfefbeSAndroid Build Coastguard Worker                     area -= r * R.x() * ((r) / R.y()) * pxs(.5);
78*20bfefbeSAndroid Build Coastguard Worker                 }
79*20bfefbeSAndroid Build Coastguard Worker             }
80*20bfefbeSAndroid Build Coastguard Worker         }
81*20bfefbeSAndroid Build Coastguard Worker         if (more_than_half) {
82*20bfefbeSAndroid Build Coastguard Worker             area = pxs(1.0) - area;
83*20bfefbeSAndroid Build Coastguard Worker         }
84*20bfefbeSAndroid Build Coastguard Worker         TEEUI_LOG << " area: " << area;
85*20bfefbeSAndroid Build Coastguard Worker         intensity = area.count() * 0xff;
86*20bfefbeSAndroid Build Coastguard Worker     }
87*20bfefbeSAndroid Build Coastguard Worker     TEEUI_LOG << ENDL;
88*20bfefbeSAndroid Build Coastguard Worker     return intensity << 24 | (c & 0xffffff);
89*20bfefbeSAndroid Build Coastguard Worker }
90*20bfefbeSAndroid Build Coastguard Worker 
drawLinePoint(Point<pxs> a,Point<pxs> b,Point<pxs> px_origin,Color c,pxs width)91*20bfefbeSAndroid Build Coastguard Worker Color drawLinePoint(Point<pxs> a, Point<pxs> b, Point<pxs> px_origin, Color c, pxs width) {
92*20bfefbeSAndroid Build Coastguard Worker     auto line = a - b;
93*20bfefbeSAndroid Build Coastguard Worker     auto len = line.length();
94*20bfefbeSAndroid Build Coastguard Worker     auto l = line / len;
95*20bfefbeSAndroid Build Coastguard Worker     auto seg = l * (px_origin - b);
96*20bfefbeSAndroid Build Coastguard Worker     auto dist = 0_px;
97*20bfefbeSAndroid Build Coastguard Worker     if (seg < 0_px) {
98*20bfefbeSAndroid Build Coastguard Worker         //        line = px_origin - b;
99*20bfefbeSAndroid Build Coastguard Worker         //        dist = line.length();
100*20bfefbeSAndroid Build Coastguard Worker         //        line /= dist;
101*20bfefbeSAndroid Build Coastguard Worker         //        dist -= width;
102*20bfefbeSAndroid Build Coastguard Worker         return 0;
103*20bfefbeSAndroid Build Coastguard Worker     } else if (seg > len) {
104*20bfefbeSAndroid Build Coastguard Worker         //        line = px_origin - a;
105*20bfefbeSAndroid Build Coastguard Worker         //        dist = line.length();
106*20bfefbeSAndroid Build Coastguard Worker         //        line /= dist;
107*20bfefbeSAndroid Build Coastguard Worker         //        dist -= width;
108*20bfefbeSAndroid Build Coastguard Worker         return 0;
109*20bfefbeSAndroid Build Coastguard Worker     } else {
110*20bfefbeSAndroid Build Coastguard Worker         line = Point<pxs>(-line.y(), line.x()) / len;
111*20bfefbeSAndroid Build Coastguard Worker         dist = (line * (px_origin - a)).abs() - width + .5_px;
112*20bfefbeSAndroid Build Coastguard Worker     }
113*20bfefbeSAndroid Build Coastguard Worker 
114*20bfefbeSAndroid Build Coastguard Worker     return pixelLineIntersect(line, dist, c);
115*20bfefbeSAndroid Build Coastguard Worker }
116*20bfefbeSAndroid Build Coastguard Worker 
drawCirclePoint(Point<pxs> center,pxs r,Point<pxs> px_origin,Color c)117*20bfefbeSAndroid Build Coastguard Worker Color drawCirclePoint(Point<pxs> center, pxs r, Point<pxs> px_origin, Color c) {
118*20bfefbeSAndroid Build Coastguard Worker     auto line = px_origin - center;
119*20bfefbeSAndroid Build Coastguard Worker     auto dist = line.length() - r;
120*20bfefbeSAndroid Build Coastguard Worker 
121*20bfefbeSAndroid Build Coastguard Worker     return pixelLineIntersect(line.unit(), dist, c);
122*20bfefbeSAndroid Build Coastguard Worker }
123*20bfefbeSAndroid Build Coastguard Worker 
124*20bfefbeSAndroid Build Coastguard Worker /*
125*20bfefbeSAndroid Build Coastguard Worker  * Computes the intersection of the lines given by ax + b and cy + d.
126*20bfefbeSAndroid Build Coastguard Worker  * The result may be empty if there is no solution.
127*20bfefbeSAndroid Build Coastguard Worker  */
intersect(const PxVec & a,const PxPoint & b,const PxVec & c,const PxPoint & d)128*20bfefbeSAndroid Build Coastguard Worker optional<PxPoint> intersect(const PxVec& a, const PxPoint& b, const PxVec& c, const PxPoint& d) {
129*20bfefbeSAndroid Build Coastguard Worker     pxs y = 0.0;
130*20bfefbeSAndroid Build Coastguard Worker     PxVec g = b - d;
131*20bfefbeSAndroid Build Coastguard Worker     if (a.x().abs() < kEpsilon) {
132*20bfefbeSAndroid Build Coastguard Worker         if (c.x().abs() < kEpsilon || a.y() < kEpsilon) {
133*20bfefbeSAndroid Build Coastguard Worker             return {};
134*20bfefbeSAndroid Build Coastguard Worker         } else {
135*20bfefbeSAndroid Build Coastguard Worker             y = g.x() / c.x();
136*20bfefbeSAndroid Build Coastguard Worker         }
137*20bfefbeSAndroid Build Coastguard Worker     } else {
138*20bfefbeSAndroid Build Coastguard Worker         pxs f = a.y() / a.x();
139*20bfefbeSAndroid Build Coastguard Worker         pxs h = f * c.x() - c.y();
140*20bfefbeSAndroid Build Coastguard Worker         if (h.abs() < kEpsilon) {
141*20bfefbeSAndroid Build Coastguard Worker             return {};
142*20bfefbeSAndroid Build Coastguard Worker         } else {
143*20bfefbeSAndroid Build Coastguard Worker             y = (f * g.x() - g.y()) / h;
144*20bfefbeSAndroid Build Coastguard Worker         }
145*20bfefbeSAndroid Build Coastguard Worker     }
146*20bfefbeSAndroid Build Coastguard Worker     return c * y + d;
147*20bfefbeSAndroid Build Coastguard Worker }
148*20bfefbeSAndroid Build Coastguard Worker 
149*20bfefbeSAndroid Build Coastguard Worker namespace bits {
150*20bfefbeSAndroid Build Coastguard Worker 
rotate90(const VectorType & in)151*20bfefbeSAndroid Build Coastguard Worker template <typename VectorType> inline VectorType rotate90(const VectorType& in) {
152*20bfefbeSAndroid Build Coastguard Worker     return {-in.y(), in.x()};
153*20bfefbeSAndroid Build Coastguard Worker }
154*20bfefbeSAndroid Build Coastguard Worker 
intersect(const PxPoint * oBegin,const PxPoint * oEnd,const PxPoint & lineA,const PxPoint & lineB,PxPoint * nBegin,PxPoint * nEnd)155*20bfefbeSAndroid Build Coastguard Worker ssize_t intersect(const PxPoint* oBegin, const PxPoint* oEnd, const PxPoint& lineA,
156*20bfefbeSAndroid Build Coastguard Worker                   const PxPoint& lineB, PxPoint* nBegin, PxPoint* nEnd) {
157*20bfefbeSAndroid Build Coastguard Worker 
158*20bfefbeSAndroid Build Coastguard Worker     auto line = lineB - lineA;
159*20bfefbeSAndroid Build Coastguard Worker     if (oBegin == oEnd) return kIntersectEmpty;
160*20bfefbeSAndroid Build Coastguard Worker     auto b = oBegin;
161*20bfefbeSAndroid Build Coastguard Worker     auto a = b;
162*20bfefbeSAndroid Build Coastguard Worker     ++b;
163*20bfefbeSAndroid Build Coastguard Worker     auto nCur = nBegin;
164*20bfefbeSAndroid Build Coastguard Worker     unsigned int intersections_found = 0;
165*20bfefbeSAndroid Build Coastguard Worker     // inside indicates if we are inside the new convex object.
166*20bfefbeSAndroid Build Coastguard Worker     // If we happen to transition from inside to inside, we know that we where wrong and
167*20bfefbeSAndroid Build Coastguard Worker     // reset the output object. But if we were on the inside we have the full new object once
168*20bfefbeSAndroid Build Coastguard Worker     // we have traveled around the old object once.
169*20bfefbeSAndroid Build Coastguard Worker     bool inside = true;
170*20bfefbeSAndroid Build Coastguard Worker 
171*20bfefbeSAndroid Build Coastguard Worker     auto processSegment = [&](const PxVec& a, const PxVec& b) -> bool {
172*20bfefbeSAndroid Build Coastguard Worker         auto segment = b - a;
173*20bfefbeSAndroid Build Coastguard Worker         if (auto p = intersect(line, lineA, segment, a)) {
174*20bfefbeSAndroid Build Coastguard Worker             auto seg_len = segment.length();
175*20bfefbeSAndroid Build Coastguard Worker             auto aDist = (segment * (*p - a)) / seg_len;
176*20bfefbeSAndroid Build Coastguard Worker             if (aDist >= 0.0 && aDist < segment.length()) {
177*20bfefbeSAndroid Build Coastguard Worker                 ++intersections_found;
178*20bfefbeSAndroid Build Coastguard Worker                 // The line vector points toward the negative half plain of segment.
179*20bfefbeSAndroid Build Coastguard Worker                 // This means we are entering the resulting convex object.
180*20bfefbeSAndroid Build Coastguard Worker                 bool enter = rotate90(segment) * line < 0;
181*20bfefbeSAndroid Build Coastguard Worker                 if (enter && inside) {
182*20bfefbeSAndroid Build Coastguard Worker                     // if we are entering the object, but we thought we are already inside, we
183*20bfefbeSAndroid Build Coastguard Worker                     // forget all previous points, because we were wrong.
184*20bfefbeSAndroid Build Coastguard Worker                     if (intersections_found < 2) {
185*20bfefbeSAndroid Build Coastguard Worker                         // Only do after we found the first intersection. Other cases are likely
186*20bfefbeSAndroid Build Coastguard Worker                         // duplications due to rounding errors.
187*20bfefbeSAndroid Build Coastguard Worker                         nCur = nBegin;
188*20bfefbeSAndroid Build Coastguard Worker                     }
189*20bfefbeSAndroid Build Coastguard Worker                 }
190*20bfefbeSAndroid Build Coastguard Worker                 TEEUI_LOG << *p << " inside: " << inside << " enter: " << enter << ENDL;
191*20bfefbeSAndroid Build Coastguard Worker                 inside = enter;
192*20bfefbeSAndroid Build Coastguard Worker                 // an intersection of the new line and a segment is always part of the resulting
193*20bfefbeSAndroid Build Coastguard Worker                 // object.
194*20bfefbeSAndroid Build Coastguard Worker                 if (nCur == nEnd) {
195*20bfefbeSAndroid Build Coastguard Worker                     TEEUI_LOG << "error out of space 1" << ENDL;
196*20bfefbeSAndroid Build Coastguard Worker                     return false;
197*20bfefbeSAndroid Build Coastguard Worker                 }
198*20bfefbeSAndroid Build Coastguard Worker                 if (aDist > 0.0 || enter) {
199*20bfefbeSAndroid Build Coastguard Worker                     TEEUI_LOG << "add P: " << *p << ENDL;
200*20bfefbeSAndroid Build Coastguard Worker                     *nCur++ = *p;
201*20bfefbeSAndroid Build Coastguard Worker                 }
202*20bfefbeSAndroid Build Coastguard Worker             }
203*20bfefbeSAndroid Build Coastguard Worker         }
204*20bfefbeSAndroid Build Coastguard Worker         if (nCur == nEnd) {
205*20bfefbeSAndroid Build Coastguard Worker             TEEUI_LOG << "error out of space 2" << ENDL;
206*20bfefbeSAndroid Build Coastguard Worker             return false;
207*20bfefbeSAndroid Build Coastguard Worker         }
208*20bfefbeSAndroid Build Coastguard Worker         if (inside) {
209*20bfefbeSAndroid Build Coastguard Worker             TEEUI_LOG << "add B: " << b << ENDL;
210*20bfefbeSAndroid Build Coastguard Worker             *nCur++ = b;
211*20bfefbeSAndroid Build Coastguard Worker         }
212*20bfefbeSAndroid Build Coastguard Worker         return true;
213*20bfefbeSAndroid Build Coastguard Worker     };
214*20bfefbeSAndroid Build Coastguard Worker 
215*20bfefbeSAndroid Build Coastguard Worker     while (b != oEnd) {
216*20bfefbeSAndroid Build Coastguard Worker         if (!processSegment(*a, *b)) return kIntersectEmpty;
217*20bfefbeSAndroid Build Coastguard Worker         a = b++;
218*20bfefbeSAndroid Build Coastguard Worker     }
219*20bfefbeSAndroid Build Coastguard Worker     if (!processSegment(*a, *oBegin)) return kIntersectEmpty;
220*20bfefbeSAndroid Build Coastguard Worker 
221*20bfefbeSAndroid Build Coastguard Worker     TEEUI_LOG << "intersections found: " << intersections_found << ENDL;
222*20bfefbeSAndroid Build Coastguard Worker     // handle tangents and disjunct case
223*20bfefbeSAndroid Build Coastguard Worker     if (intersections_found < 2) {
224*20bfefbeSAndroid Build Coastguard Worker         // find a point that is not on the line
225*20bfefbeSAndroid Build Coastguard Worker         // if there is at most one intersection, all points of the object are on the same half
226*20bfefbeSAndroid Build Coastguard Worker         // plane or on the line.
227*20bfefbeSAndroid Build Coastguard Worker         a = oBegin;
228*20bfefbeSAndroid Build Coastguard Worker         pxs d;
229*20bfefbeSAndroid Build Coastguard Worker         do {
230*20bfefbeSAndroid Build Coastguard Worker             d = rotate90(line) * (*a - lineA);
231*20bfefbeSAndroid Build Coastguard Worker             if (++a == oEnd) {
232*20bfefbeSAndroid Build Coastguard Worker                 TEEUI_LOG << "error no point with distance > 0" << ENDL;
233*20bfefbeSAndroid Build Coastguard Worker                 return kIntersectEmpty;
234*20bfefbeSAndroid Build Coastguard Worker             }
235*20bfefbeSAndroid Build Coastguard Worker         } while (d == 0.0);
236*20bfefbeSAndroid Build Coastguard Worker 
237*20bfefbeSAndroid Build Coastguard Worker         if (d > 0) {
238*20bfefbeSAndroid Build Coastguard Worker             // positive half plane
239*20bfefbeSAndroid Build Coastguard Worker             return kIntersectAllPositive;
240*20bfefbeSAndroid Build Coastguard Worker         } else {
241*20bfefbeSAndroid Build Coastguard Worker             // negative half plane
242*20bfefbeSAndroid Build Coastguard Worker             TEEUI_LOG << "egative half plane" << ENDL;
243*20bfefbeSAndroid Build Coastguard Worker             return kIntersectEmpty;
244*20bfefbeSAndroid Build Coastguard Worker         }
245*20bfefbeSAndroid Build Coastguard Worker     }
246*20bfefbeSAndroid Build Coastguard Worker 
247*20bfefbeSAndroid Build Coastguard Worker     return nCur - nBegin;
248*20bfefbeSAndroid Build Coastguard Worker }
249*20bfefbeSAndroid Build Coastguard Worker 
area(const PxPoint * begin,const PxPoint * end)250*20bfefbeSAndroid Build Coastguard Worker pxs area(const PxPoint* begin, const PxPoint* end) {
251*20bfefbeSAndroid Build Coastguard Worker     if (end - begin < 3) return 0.0;
252*20bfefbeSAndroid Build Coastguard Worker     auto o = *begin;
253*20bfefbeSAndroid Build Coastguard Worker     auto a = begin;
254*20bfefbeSAndroid Build Coastguard Worker     ++a;
255*20bfefbeSAndroid Build Coastguard Worker     auto b = a;
256*20bfefbeSAndroid Build Coastguard Worker     ++b;
257*20bfefbeSAndroid Build Coastguard Worker     pxs result = 0;
258*20bfefbeSAndroid Build Coastguard Worker     while (b != end) {
259*20bfefbeSAndroid Build Coastguard Worker         auto x = *a - o;
260*20bfefbeSAndroid Build Coastguard Worker         auto y = *b - o;
261*20bfefbeSAndroid Build Coastguard Worker         result += x.x() * y.y() - x.y() * y.x();
262*20bfefbeSAndroid Build Coastguard Worker         a = b;
263*20bfefbeSAndroid Build Coastguard Worker         ++b;
264*20bfefbeSAndroid Build Coastguard Worker     }
265*20bfefbeSAndroid Build Coastguard Worker     result /= 2;
266*20bfefbeSAndroid Build Coastguard Worker     return result;
267*20bfefbeSAndroid Build Coastguard Worker }
268*20bfefbeSAndroid Build Coastguard Worker 
269*20bfefbeSAndroid Build Coastguard Worker }  // namespace bits
270*20bfefbeSAndroid Build Coastguard Worker 
271*20bfefbeSAndroid Build Coastguard Worker }  // namespace teeui
272