/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "host/libs/confui/host_renderer.h" #include #include "host/libs/config/cuttlefish_config.h" namespace cuttlefish { namespace confui { static teeui::Color alfaCombineChannel(std::uint32_t shift, double alfa, teeui::Color a, teeui::Color b) { a >>= shift; a &= 0xff; b >>= shift; b &= 0xff; double acc = alfa * a + (1 - alfa) * b; if (acc <= 0) { return 0; } std::uint32_t result = acc; if (result > 255) { return 255 << shift; } return result << shift; } /** * create a raw frame for confirmation UI dialog * * Many rendering code borrowed from the following source * https://android.googlesource.com/trusty/app/confirmationui/+/0429cc7/src */ class ConfUiRendererImpl { friend class ConfUiRenderer; public: using LabelConfMsg = teeui::LabelBody; private: static Result> GenerateRenderer( const std::uint32_t display, const std::string& confirmation_msg, const std::string& locale, const bool inverted, const bool magnified); /** * this does not repaint from the scratch all the time * * It does repaint its frame buffer only when w/h of * current display has changed */ std::unique_ptr& RenderRawFrame(); bool IsFrameReady() const { return raw_frame_ && !raw_frame_->IsEmpty(); } bool IsInConfirm(const std::uint32_t x, const std::uint32_t y) { return IsInside(x, y); } bool IsInCancel(const std::uint32_t x, const std::uint32_t y) { return IsInside(x, y); } bool IsSetUpSuccessful() const { return is_setup_well_; } ConfUiRendererImpl(const std::uint32_t display, const std::string& confirmation_msg, const std::string& locale, const bool inverted, const bool magnified); struct Boundary { // inclusive but.. LayoutElement's size is float std::uint32_t x, y, w, h; // (x, y) is the top left }; template Boundary GetBoundary(LayoutElement&& e) const { auto box = e.bounds_; Boundary b; // (x,y) is left top. so floor() makes sense // w, h are width and height in float. perhaps ceiling makes more // sense b.x = static_cast(box.x().floor().count()); b.y = static_cast(box.y().floor().count()); b.w = static_cast(box.w().ceil().count()); b.h = static_cast(box.h().ceil().count()); return b; } template bool IsInside(const std::uint32_t x, const std::uint32_t y) const { auto box = GetBoundary(std::get(layout_)); if (x >= box.x && x <= box.x + box.w && y >= box.y && y <= box.y + box.h) { return true; } return false; } // essentially, to repaint from the scratch, so returns new frame // when successful. Or, nullopt std::unique_ptr RepaintRawFrame(const int w, const int h); bool InitLayout(const std::string& lang_id); teeui::Error UpdateTranslations(); teeui::Error UpdateLocale(); void SetDeviceContext(const unsigned long long w, const unsigned long long h, bool is_inverted, bool is_magnified); // a callback function to be effectively sent to TeeUI library teeui::Error UpdatePixels(TeeUiFrameWrapper& buffer, std::uint32_t x, std::uint32_t y, teeui::Color color); // second param is for type deduction template static teeui::Error drawElements(std::tuple& layout, const teeui::PixelDrawer& drawPixel) { // Error::operator|| is overloaded, so we don't get short circuit // evaluation. But we get the first error that occurs. We will still try and // draw the remaining elements in the order they appear in the layout tuple. return (std::get(layout).draw(drawPixel) || ...); } void UpdateColorScheme(const bool is_inverted); template auto SetText(const std::string& text) { return std::get