• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/libs/confui/host_renderer.h"
18 
19 namespace cuttlefish {
20 namespace confui {
alfaCombineChannel(std::uint32_t shift,double alfa,teeui::Color a,teeui::Color b)21 static teeui::Color alfaCombineChannel(std::uint32_t shift, double alfa,
22                                        teeui::Color a, teeui::Color b) {
23   a >>= shift;
24   a &= 0xff;
25   b >>= shift;
26   b &= 0xff;
27   double acc = alfa * a + (1 - alfa) * b;
28   if (acc <= 0) return 0;
29   std::uint32_t result = acc;
30   if (result > 255) return 255 << shift;
31   return result << shift;
32 }
33 
ConfUiRenderer(const std::uint32_t display)34 ConfUiRenderer::ConfUiRenderer(const std::uint32_t display)
35     : display_num_(display),
36       lang_id_{"en"},
37       prompt_("Am I Yumi Meow?"),
38       current_height_(ScreenConnectorInfo::ScreenHeight(display_num_)),
39       current_width_(ScreenConnectorInfo::ScreenWidth(display_num_)),
40       color_bg_{kColorBackground},
41       color_text_{kColorDisabled},
42       shield_color_{kColorShield},
43       is_inverted_{false},
44       ctx_{GetDeviceContext()} {
45   auto opted_frame = RepaintRawFrame(prompt_, lang_id_);
46   if (opted_frame) {
47     raw_frame_ = std::move(opted_frame.value());
48   }
49 }
50 
SetConfUiMessage(const std::string & msg)51 void ConfUiRenderer::SetConfUiMessage(const std::string& msg) {
52   prompt_ = msg;
53   SetText<LabelConfMsg>(msg);
54 }
55 
SetLangId(const std::string & lang_id)56 teeui::Error ConfUiRenderer::SetLangId(const std::string& lang_id) {
57   using teeui::Error;
58   lang_id_ = lang_id;
59   teeui::localization::selectLangId(lang_id_.c_str());
60   if (auto error = UpdateTranslations()) {
61     return error;
62   }
63   return Error::OK;
64 }
65 
UpdateTranslations()66 teeui::Error ConfUiRenderer::UpdateTranslations() {
67   using namespace teeui;
68   if (auto error = UpdateString<LabelOK>()) {
69     return error;
70   }
71   if (auto error = UpdateString<LabelOK>()) {
72     return error;
73   }
74   if (auto error = UpdateString<LabelCancel>()) {
75     return error;
76   }
77   if (auto error = UpdateString<LabelTitle>()) {
78     return error;
79   }
80   if (auto error = UpdateString<LabelHint>()) {
81     return error;
82   }
83   return Error::OK;
84 }
85 
GetDeviceContext()86 teeui::context<teeui::ConUIParameters> ConfUiRenderer::GetDeviceContext() {
87   using namespace teeui;
88   const unsigned long long w = ScreenConnectorInfo::ScreenWidth(display_num_);
89   const unsigned long long h = ScreenConnectorInfo::ScreenHeight(display_num_);
90   const auto screen_width = operator""_px(w);
91   const auto screen_height = operator""_px(h);
92   context<teeui::ConUIParameters> ctx(6.45211, 400.0 / 412.0);
93   ctx.setParam<RightEdgeOfScreen>(screen_width);
94   ctx.setParam<BottomOfScreen>(screen_height);
95   ctx.setParam<PowerButtonTop>(20.26_mm);
96   ctx.setParam<PowerButtonBottom>(30.26_mm);
97   ctx.setParam<VolUpButtonTop>(40.26_mm);
98   ctx.setParam<VolUpButtonBottom>(50.26_mm);
99   ctx.setParam<DefaultFontSize>(14_dp);
100   ctx.setParam<BodyFontSize>(16_dp);
101   return ctx;
102 }
103 
InitLayout(const std::string & lang_id)104 bool ConfUiRenderer::InitLayout(const std::string& lang_id) {
105   layout_ = teeui::instantiateLayout(teeui::ConfUILayout(), ctx_);
106   SetLangId(lang_id);
107   if (auto error = UpdateTranslations()) {
108     ConfUiLog(ERROR) << "Update Translation Error";
109     return false;
110   }
111   UpdateColorScheme(&ctx_);
112   return true;
113 }
114 
UpdatePixels(TeeUiFrame & raw_frame,std::uint32_t x,std::uint32_t y,teeui::Color color)115 teeui::Error ConfUiRenderer::UpdatePixels(TeeUiFrame& raw_frame,
116                                           std::uint32_t x, std::uint32_t y,
117                                           teeui::Color color) {
118   auto buffer = raw_frame.data();
119   const auto height = ScreenConnectorInfo::ScreenHeight(display_num_);
120   const auto width = ScreenConnectorInfo::ScreenWidth(display_num_);
121   auto pos = width * y + x;
122   if (pos >= (height * width)) {
123     ConfUiLog(ERROR) << "Rendering Out of Bound";
124     return teeui::Error::OutOfBoundsDrawing;
125   }
126   const double alfa = ((color & 0xff000000) >> 24) / 255.0;
127   auto& pixel = *reinterpret_cast<teeui::Color*>(buffer + pos);
128   pixel = alfaCombineChannel(0, alfa, color, pixel) |
129           alfaCombineChannel(8, alfa, color, pixel) |
130           alfaCombineChannel(16, alfa, color, pixel);
131   return teeui::Error::OK;
132 }
133 
RenderRawFrame(const std::string & confirmation_msg,const std::string & lang_id)134 std::tuple<TeeUiFrame&, bool> ConfUiRenderer::RenderRawFrame(
135     const std::string& confirmation_msg, const std::string& lang_id) {
136   /* we repaint only if one or more of the followng meet:
137    *
138    *  1. raw_frame_ is empty
139    *  2. the current_width_ and current_height_ is out of date
140    *  3. lang_id is different (e.g. new locale)
141    *
142    *  in the future, maybe you wanna inverted, new background, etc?
143    */
144   if (lang_id != lang_id_ || !IsFrameReady() ||
145       current_height_ != ScreenConnectorInfo::ScreenHeight(display_num_) ||
146       current_width_ != ScreenConnectorInfo::ScreenWidth(display_num_)) {
147     auto opted_new_frame = RepaintRawFrame(confirmation_msg, lang_id_);
148     if (opted_new_frame) {
149       // repainting from the scratch successful in a new frame
150       raw_frame_ = std::move(opted_new_frame.value());
151       return {raw_frame_, true};
152     }
153     // repaint failed even if it was necessary, so returns invalid values
154     raw_frame_.clear();
155     return {raw_frame_, false};
156   }
157   // no need to repaint from the scratch. repaint the confirmation message only
158   // the frame is mostly already in raw_frame_
159   auto ret_code = RenderConfirmationMsgOnly(confirmation_msg);
160   return {raw_frame_, (ret_code == teeui::Error::OK)};
161 }
162 
RepaintRawFrame(const std::string & confirmation_msg,const std::string & lang_id)163 std::optional<TeeUiFrame> ConfUiRenderer::RepaintRawFrame(
164     const std::string& confirmation_msg, const std::string& lang_id) {
165   /*
166    * NOTE: DON'T use current_width_/height_ to create this frame
167    * it may fail, and then we must not mess up the current_width_, height_
168    *
169    */
170   if (!InitLayout(lang_id)) {
171     return std::nullopt;
172   }
173   SetConfUiMessage(confirmation_msg);
174   auto color = kColorEnabled;
175   std::get<teeui::LabelOK>(layout_).setTextColor(color);
176   std::get<teeui::LabelCancel>(layout_).setTextColor(color);
177 
178   /* in the future, if ever we need to register a handler for the
179      Label{OK,Cancel}. do this: std::get<teeui::LabelOK>(layout_)
180      .setCB(teeui::makeCallback<teeui::Error, teeui::Event>(
181      [](teeui::Event e, void* p) -> teeui::Error {
182      LOG(DEBUG) << "Calling callback for Confirm?";
183      return reinterpret_cast<decltype(owner)*>(p)->TapOk(e); },
184      owner));
185   */
186   // we manually check if click happened, where if yes, and generate the label
187   // event manually. So we won't register the handler here.
188   /**
189    * should be uint32_t for teeui APIs.
190    * It assumes that each raw frame buffer element is 4 bytes
191    */
192   TeeUiFrame new_raw_frame(
193       ScreenConnectorInfo::ScreenSizeInBytes(display_num_) / 4,
194       kColorBackground);
195 
196   auto draw_pixel = teeui::makePixelDrawer(
197       [this, &new_raw_frame](std::uint32_t x, std::uint32_t y,
198                              teeui::Color color) -> teeui::Error {
199         return this->UpdatePixels(new_raw_frame, x, y, color);
200       });
201 
202   // render all components
203   const auto error = drawElements(layout_, draw_pixel);
204   if (error) {
205     ConfUiLog(ERROR) << "Painting failed: " << error.code();
206     return std::nullopt;
207   }
208 
209   // set current frame's dimension as frame generation was successful
210   current_height_ = ScreenConnectorInfo::ScreenHeight(display_num_);
211   current_width_ = ScreenConnectorInfo::ScreenWidth(display_num_);
212 
213   return {new_raw_frame};
214 }
215 
RenderConfirmationMsgOnly(const std::string & confirmation_msg)216 teeui::Error ConfUiRenderer::RenderConfirmationMsgOnly(
217     const std::string& confirmation_msg) {
218   // repaint labelbody on the raw_frame__ only
219   auto callback_func = [this](std::uint32_t x, std::uint32_t y,
220                               teeui::Color color) -> teeui::Error {
221     return UpdatePixels(raw_frame_, x, y, color);
222   };
223   auto draw_pixel = teeui::makePixelDrawer(callback_func);
224   LabelConfMsg& label = std::get<LabelConfMsg>(layout_);
225   auto b = GetBoundary(label);
226   for (std::uint32_t i = 0; i != b.w; i++) {
227     const auto col_index = i + b.x - 1;
228     for (std::uint32_t j = 0; j != b.y; j++) {
229       const auto row_index = (j + b.y - 1);
230       raw_frame_[current_width_ * row_index + col_index] = color_bg_;
231     }
232   }
233 
234   SetConfUiMessage(confirmation_msg);
235   ConfUiLog(DEBUG) << "Repaint Confirmation Msg with :" << prompt_;
236   if (auto error = std::get<LabelConfMsg>(layout_).draw(draw_pixel)) {
237     ConfUiLog(ERROR) << "Repainting Confirmation Message Label failed:"
238                      << error.code();
239     return error;
240   }
241   return teeui::Error::OK;
242 }
243 
244 }  // end of namespace confui
245 }  // end of namespace cuttlefish
246