xref: /aosp_15_r20/system/teeui/libteeui/src/label.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/label.h>
19*20bfefbeSAndroid Build Coastguard Worker 
20*20bfefbeSAndroid Build Coastguard Worker #include <teeui/error.h>
21*20bfefbeSAndroid Build Coastguard Worker #include <teeui/font_rendering.h>
22*20bfefbeSAndroid Build Coastguard Worker 
23*20bfefbeSAndroid Build Coastguard Worker namespace teeui {
24*20bfefbeSAndroid Build Coastguard Worker 
draw(const PixelDrawer & drawPixel,const Box<pxs> & bounds,LineInfo * lineInfo)25*20bfefbeSAndroid Build Coastguard Worker Error LabelImpl::draw(const PixelDrawer& drawPixel, const Box<pxs>& bounds, LineInfo* lineInfo) {
26*20bfefbeSAndroid Build Coastguard Worker     if (!font_) return Error::NotInitialized;
27*20bfefbeSAndroid Build Coastguard Worker 
28*20bfefbeSAndroid Build Coastguard Worker     Error error;
29*20bfefbeSAndroid Build Coastguard Worker     TextContext context;
30*20bfefbeSAndroid Build Coastguard Worker     std::tie(error, context) = TextContext::create();
31*20bfefbeSAndroid Build Coastguard Worker     if (error) return error;
32*20bfefbeSAndroid Build Coastguard Worker 
33*20bfefbeSAndroid Build Coastguard Worker     TextFace face;
34*20bfefbeSAndroid Build Coastguard Worker     std::tie(error, face) = context.loadFace(font_);
35*20bfefbeSAndroid Build Coastguard Worker     if (error) return error;
36*20bfefbeSAndroid Build Coastguard Worker 
37*20bfefbeSAndroid Build Coastguard Worker     error = face.setCharSizeInPix(fontSize());
38*20bfefbeSAndroid Build Coastguard Worker     if (error) return error;
39*20bfefbeSAndroid Build Coastguard Worker 
40*20bfefbeSAndroid Build Coastguard Worker     using intpxs = Coordinate<px, int64_t>;
41*20bfefbeSAndroid Build Coastguard Worker     Box<intpxs> intBounds(intpxs((int64_t)bounds.x().count()), intpxs((int64_t)bounds.y().count()),
42*20bfefbeSAndroid Build Coastguard Worker                           intpxs((int64_t)bounds.w().count()), intpxs((int64_t)bounds.h().count()));
43*20bfefbeSAndroid Build Coastguard Worker 
44*20bfefbeSAndroid Build Coastguard Worker     auto drawPixelBoundsEnforced =
45*20bfefbeSAndroid Build Coastguard Worker         makePixelDrawer([&, this](uint32_t x, uint32_t y, Color color) -> Error {
46*20bfefbeSAndroid Build Coastguard Worker             if (!intBounds.contains(Point<intpxs>(x, y))) {
47*20bfefbeSAndroid Build Coastguard Worker                 TEEUI_LOG << "Bounds: " << bounds << " Pixel: " << Point<pxs>(x, y) << ENDL;
48*20bfefbeSAndroid Build Coastguard Worker                 return Error::OutOfBoundsDrawing;
49*20bfefbeSAndroid Build Coastguard Worker             }
50*20bfefbeSAndroid Build Coastguard Worker             // combine the given alpha channel with the text color.
51*20bfefbeSAndroid Build Coastguard Worker             return drawPixel(x, y, (textColor_ & 0xffffff) | (color & 0xff000000));
52*20bfefbeSAndroid Build Coastguard Worker         });
53*20bfefbeSAndroid Build Coastguard Worker 
54*20bfefbeSAndroid Build Coastguard Worker #ifdef DRAW_DEBUG_MARKERS
55*20bfefbeSAndroid Build Coastguard Worker     auto drawBox = [&](const Box<pxs>& box, Color c) {
56*20bfefbeSAndroid Build Coastguard Worker         for (int y = 0; y < box.h().count(); ++y) {
57*20bfefbeSAndroid Build Coastguard Worker             for (int x = 0; x < box.w().count(); ++x) {
58*20bfefbeSAndroid Build Coastguard Worker                 drawPixel(box.x().count() + x, box.y().count() + y, (c & 0xffffff) | 0x40000000);
59*20bfefbeSAndroid Build Coastguard Worker             }
60*20bfefbeSAndroid Build Coastguard Worker         }
61*20bfefbeSAndroid Build Coastguard Worker     };
62*20bfefbeSAndroid Build Coastguard Worker 
63*20bfefbeSAndroid Build Coastguard Worker     drawBox(bounds, 0xff);
64*20bfefbeSAndroid Build Coastguard Worker #endif
65*20bfefbeSAndroid Build Coastguard Worker 
66*20bfefbeSAndroid Build Coastguard Worker     Point<pxs> pen = {0_px, 0_px};
67*20bfefbeSAndroid Build Coastguard Worker     auto textBegin = text_.begin();
68*20bfefbeSAndroid Build Coastguard Worker     optional<Box<pxs>> boundingBox;
69*20bfefbeSAndroid Build Coastguard Worker 
70*20bfefbeSAndroid Build Coastguard Worker     auto curLine = lineInfo->begin();
71*20bfefbeSAndroid Build Coastguard Worker     while (textBegin != text_.end()) {
72*20bfefbeSAndroid Build Coastguard Worker         if (curLine == lineInfo->end()) {
73*20bfefbeSAndroid Build Coastguard Worker             TEEUI_LOG << "lineInfo filled: lines=" << lineInfo->size_ << " textId=" << textId_
74*20bfefbeSAndroid Build Coastguard Worker                       << ENDL;
75*20bfefbeSAndroid Build Coastguard Worker             return Error::OutOfMemory;
76*20bfefbeSAndroid Build Coastguard Worker         }
77*20bfefbeSAndroid Build Coastguard Worker 
78*20bfefbeSAndroid Build Coastguard Worker         auto lineEnd = textBegin;
79*20bfefbeSAndroid Build Coastguard Worker 
80*20bfefbeSAndroid Build Coastguard Worker         while (!isNewline(lineEnd.codePoint()) && lineEnd != text_.end()) {
81*20bfefbeSAndroid Build Coastguard Worker             lineEnd++;
82*20bfefbeSAndroid Build Coastguard Worker         }
83*20bfefbeSAndroid Build Coastguard Worker 
84*20bfefbeSAndroid Build Coastguard Worker         Box<pxs> bBox;
85*20bfefbeSAndroid Build Coastguard Worker         std::tie(error, bBox, curLine->lineText) =
86*20bfefbeSAndroid Build Coastguard Worker             findLongestWordSequence(&face, text_t(*textBegin, *lineEnd), bounds);
87*20bfefbeSAndroid Build Coastguard Worker         if (error) return error;
88*20bfefbeSAndroid Build Coastguard Worker 
89*20bfefbeSAndroid Build Coastguard Worker         pen = {-bBox.x(), pen.y()};
90*20bfefbeSAndroid Build Coastguard Worker 
91*20bfefbeSAndroid Build Coastguard Worker         // check horizontal justification to set pen value
92*20bfefbeSAndroid Build Coastguard Worker         switch (horizontalTextAlignment_) {
93*20bfefbeSAndroid Build Coastguard Worker         case Alignment::LEFT:
94*20bfefbeSAndroid Build Coastguard Worker         case Alignment::TOP:
95*20bfefbeSAndroid Build Coastguard Worker         case Alignment::BOTTOM:
96*20bfefbeSAndroid Build Coastguard Worker             break;
97*20bfefbeSAndroid Build Coastguard Worker         case Alignment::CENTER:
98*20bfefbeSAndroid Build Coastguard Worker             pen += {(bounds.w() - bBox.w()) / 2.0_px, 0};
99*20bfefbeSAndroid Build Coastguard Worker             break;
100*20bfefbeSAndroid Build Coastguard Worker         case Alignment::RIGHT:
101*20bfefbeSAndroid Build Coastguard Worker             pen += {bounds.w() - bBox.w(), 0};
102*20bfefbeSAndroid Build Coastguard Worker             break;
103*20bfefbeSAndroid Build Coastguard Worker         }
104*20bfefbeSAndroid Build Coastguard Worker 
105*20bfefbeSAndroid Build Coastguard Worker         curLine->lineStart = pen;
106*20bfefbeSAndroid Build Coastguard Worker         bBox.translateSelf(pen);
107*20bfefbeSAndroid Build Coastguard Worker 
108*20bfefbeSAndroid Build Coastguard Worker         if (boundingBox)
109*20bfefbeSAndroid Build Coastguard Worker             boundingBox = boundingBox->merge(bBox);
110*20bfefbeSAndroid Build Coastguard Worker         else
111*20bfefbeSAndroid Build Coastguard Worker             boundingBox = bBox;
112*20bfefbeSAndroid Build Coastguard Worker 
113*20bfefbeSAndroid Build Coastguard Worker         // Set start position for next loop, skipping a newline if found
114*20bfefbeSAndroid Build Coastguard Worker         textBegin = curLine->lineText.end();
115*20bfefbeSAndroid Build Coastguard Worker         if (isNewline(textBegin.codePoint())) {
116*20bfefbeSAndroid Build Coastguard Worker             textBegin++;
117*20bfefbeSAndroid Build Coastguard Worker         }
118*20bfefbeSAndroid Build Coastguard Worker 
119*20bfefbeSAndroid Build Coastguard Worker         pen += {0_px, lineHeight_};
120*20bfefbeSAndroid Build Coastguard Worker         ++curLine;
121*20bfefbeSAndroid Build Coastguard Worker     }
122*20bfefbeSAndroid Build Coastguard Worker 
123*20bfefbeSAndroid Build Coastguard Worker     if (!boundingBox) return Error::OK;
124*20bfefbeSAndroid Build Coastguard Worker 
125*20bfefbeSAndroid Build Coastguard Worker     TEEUI_LOG << "BoundingBox: " << *boundingBox << " Bounds: " << bounds << ENDL;
126*20bfefbeSAndroid Build Coastguard Worker     Point<pxs> offset = bounds.topLeft();
127*20bfefbeSAndroid Build Coastguard Worker     offset -= {0, boundingBox->y()};
128*20bfefbeSAndroid Build Coastguard Worker     TEEUI_LOG << "Offset: " << offset << ENDL;
129*20bfefbeSAndroid Build Coastguard Worker 
130*20bfefbeSAndroid Build Coastguard Worker     if (verticalTextAlignment_ == Alignment::CENTER)
131*20bfefbeSAndroid Build Coastguard Worker         offset += {0, (bounds.h() - boundingBox->h()) / 2.0_px};
132*20bfefbeSAndroid Build Coastguard Worker     else if (verticalTextAlignment_ == Alignment::BOTTOM)
133*20bfefbeSAndroid Build Coastguard Worker         offset += {0, (bounds.h() - boundingBox->h())};
134*20bfefbeSAndroid Build Coastguard Worker 
135*20bfefbeSAndroid Build Coastguard Worker     auto lineEnd = curLine;
136*20bfefbeSAndroid Build Coastguard Worker     curLine = lineInfo->begin();
137*20bfefbeSAndroid Build Coastguard Worker 
138*20bfefbeSAndroid Build Coastguard Worker #ifdef DRAW_DEBUG_MARKERS
139*20bfefbeSAndroid Build Coastguard Worker     drawBox(boundingBox->translate(offset), 0xff00);
140*20bfefbeSAndroid Build Coastguard Worker     auto p = offset + curLine->lineStart;
141*20bfefbeSAndroid Build Coastguard Worker     drawPixel(p.x().count(), p.y().count(), 0xffff0000);
142*20bfefbeSAndroid Build Coastguard Worker #endif
143*20bfefbeSAndroid Build Coastguard Worker 
144*20bfefbeSAndroid Build Coastguard Worker     while (curLine != lineEnd) {
145*20bfefbeSAndroid Build Coastguard Worker         if (auto error = drawText(&face, curLine->lineText, drawPixelBoundsEnforced,
146*20bfefbeSAndroid Build Coastguard Worker                                   curLine->lineStart + offset)) {
147*20bfefbeSAndroid Build Coastguard Worker             TEEUI_LOG << "drawText returned " << error << ENDL;
148*20bfefbeSAndroid Build Coastguard Worker             return error;
149*20bfefbeSAndroid Build Coastguard Worker         }
150*20bfefbeSAndroid Build Coastguard Worker         ++curLine;
151*20bfefbeSAndroid Build Coastguard Worker     }
152*20bfefbeSAndroid Build Coastguard Worker     return Error::OK;
153*20bfefbeSAndroid Build Coastguard Worker }
154*20bfefbeSAndroid Build Coastguard Worker 
hit(const Event & event,const Box<pxs> & bounds)155*20bfefbeSAndroid Build Coastguard Worker Error LabelImpl::hit(const Event& event, const Box<pxs>& bounds) {
156*20bfefbeSAndroid Build Coastguard Worker     using intpxs = Coordinate<px, int64_t>;
157*20bfefbeSAndroid Build Coastguard Worker     if (bounds.contains(Point<intpxs>(event.x_, event.y_))) {
158*20bfefbeSAndroid Build Coastguard Worker         optional<CallbackEvent> callback = getCB();
159*20bfefbeSAndroid Build Coastguard Worker         if (callback) {
160*20bfefbeSAndroid Build Coastguard Worker             return callback.value()(event);
161*20bfefbeSAndroid Build Coastguard Worker         }
162*20bfefbeSAndroid Build Coastguard Worker     }
163*20bfefbeSAndroid Build Coastguard Worker     return Error::OK;
164*20bfefbeSAndroid Build Coastguard Worker }
165*20bfefbeSAndroid Build Coastguard Worker }  // namespace teeui
166