Merge "Edit README file for teeui_localization_rendering_test"
diff --git a/libteeui/example/Roboto-Medium.ttf b/libteeui/example/Roboto-Medium.ttf
new file mode 100644
index 0000000..1a7f3b0
--- /dev/null
+++ b/libteeui/example/Roboto-Medium.ttf
Binary files differ
diff --git a/libteeui/example/fonts.S b/libteeui/example/fonts.S
index f1a3f1a..5a134df 100644
--- a/libteeui/example/fonts.S
+++ b/libteeui/example/fonts.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -16,5 +16,6 @@
 
 #include <teeui/incfont.h>
 
+TEEUI_INCFONT(RobotoMedium, "Roboto-Medium.ttf");
 TEEUI_INCFONT(RobotoRegular, "Roboto-Regular.ttf");
 TEEUI_INCFONT(Shield, "Shield.ttf");
diff --git a/libteeui/example/fonts.h b/libteeui/example/fonts.h
index 4aae6e0..3fd7cea 100644
--- a/libteeui/example/fonts.h
+++ b/libteeui/example/fonts.h
@@ -1,6 +1,5 @@
 /*
- *
- * Copyright 2019, The Android Open Source Project
+ * Copyright 2020, 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.
@@ -15,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef LIBTEEUI_EXAMPLE_FONTS_H_
-#define LIBTEEUI_EXAMPLE_FONTS_H_
+#pragma once
 
 #include <teeui/incfont.h>
 
@@ -27,7 +25,6 @@
  * The first one pointing to a raw ttf font file in the .rodata section, and the second
  * beeing the size of the buffer.
  */
+TEEUI_INCFONT(RobotoMedium);
 TEEUI_INCFONT(RobotoRegular);
 TEEUI_INCFONT(Shield);
-
-#endif  // LIBTEEUI_EXAMPLE_FONTS_H_
diff --git a/libteeui/example/layout.h b/libteeui/example/layout.h
index 1bfd50a..8f78020 100644
--- a/libteeui/example/layout.h
+++ b/libteeui/example/layout.h
@@ -1,5 +1,4 @@
 /*
- *
  * Copyright 2019, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef TEEUI_LIBTEEUI_EXAMPLE_LAYOUT_H_
-#define TEEUI_LIBTEEUI_EXAMPLE_LAYOUT_H_
+#pragma once
 
 #include <teeui/button.h>
 #include <teeui/label.h>
@@ -34,10 +32,13 @@
 DECLARE_PARAMETER(VolUpButtonBottom);
 DECLARE_PARAMETER(DefaultFontSize);  // 14_dp regular and 18_dp magnified
 DECLARE_PARAMETER(BodyFontSize);     // 16_dp regular and 20_dp magnified
+DECLARE_TYPED_PARAMETER(ShieldColor, ::teeui::Color);
+DECLARE_TYPED_PARAMETER(ColorText, ::teeui::Color);
+DECLARE_TYPED_PARAMETER(ColorBG, ::teeui::Color);
 
 NEW_PARAMETER_SET(ConUIParameters, RightEdgeOfScreen, BottomOfScreen, PowerButtonTop,
                   PowerButtonBottom, VolUpButtonTop, VolUpButtonBottom, DefaultFontSize,
-                  BodyFontSize);
+                  BodyFontSize, ShieldColor, ColorText, ColorBG);
 
 CONSTANT(BorderWidth, 24_dp);
 CONSTANT(PowerButtonCenter, (PowerButtonTop() + PowerButtonBottom()) / 2_px);
@@ -45,7 +46,6 @@
 CONSTANT(GrayZone, 12_dp);
 CONSTANT(RightLabelEdge, RightEdgeOfScreen() - BorderWidth - GrayZone);
 CONSTANT(LabelWidth, RightLabelEdge - BorderWidth);
-CONSTANT(DefaultTextColor, Color(0xff212121));
 
 CONSTANT(SQRT2, 1.4142135623_dp);
 CONSTANT(SQRT8, 2.828427125_dp);
@@ -56,8 +56,10 @@
                         CONVEX_OBJECT(Vec2d{6.0_dp - SQRT8, 6.0_dp}, Vec2d{6.0_dp, 6.0_dp},
                                       Vec2d{0.0_dp, 12.0_dp}, Vec2d{-SQRT2, 12.0_dp - SQRT2})));
 
+DECLARE_FONT_BUFFER(RobotoMedium, RobotoMedium, RobotoMedium_length);
 DECLARE_FONT_BUFFER(RobotoRegular, RobotoRegular, RobotoRegular_length);
 DECLARE_FONT_BUFFER(Shield, Shield, Shield_length);
+
 CONSTANT(DefaultFont, FONT(RobotoRegular));
 
 BEGIN_ELEMENT(LabelOK, teeui::Label)
@@ -69,8 +71,8 @@
 DefaultText("Wiggle your big toe to confirm");
 RightJustified;
 VerticallyCentered;
-TextColor(DefaultTextColor);
-Font(DefaultFont);
+TextColor(ColorText());
+Font(FONT(RobotoMedium));
 TextID(1424834532030812203);
 END_ELEMENT();
 
@@ -78,10 +80,10 @@
 Dimension(BorderWidth, PowerButtonBottom() - PowerButtonTop());
 Position(RightEdgeOfScreen() - BorderWidth, PowerButtonTop());
 CornerRadius(3_dp);
-ButtonColor(0xff212121);
+ButtonColor(ColorText());
 RoundTopLeft;
 RoundBottomLeft;
-ConvexObjectColor(0xffffffff);
+ConvexObjectColor(ColorBG());
 ConvexObjects(ARROW_SHAPE);
 END_ELEMENT();
 
@@ -94,8 +96,8 @@
 DefaultText("Wink left then right thrice to cancel");
 RightJustified;
 VerticallyCentered;
-TextColor(DefaultTextColor);
-Font(DefaultFont);
+TextColor(ColorText());
+Font(FONT(RobotoMedium));
 TextID(1796282799666106567);
 END_ELEMENT();
 
@@ -103,32 +105,32 @@
 Dimension(BorderWidth, VolUpButtonBottom() - VolUpButtonTop());
 Position(RightEdgeOfScreen() - BorderWidth, VolUpButtonTop());
 CornerRadius(5_dp);
-ButtonColor(0xffffffff);
-ConvexObjectColor(0xff212121);
+ButtonColor(ColorBG());
+ConvexObjectColor(ColorText());
 ConvexObjects(ARROW_SHAPE);
 END_ELEMENT();
 
 BEGIN_ELEMENT(IconShield, teeui::Label)
-FontSize(36_dp);
-LineHeight(36_dp);
+FontSize(24_dp);
+LineHeight(24_dp);
 NumberOfLines(1);
 Dimension(LabelWidth, HeightFromLines);
 Position(BorderWidth, BOTTOM_EDGE_OF(LabelCancel) + 60_dp);
 DefaultText("A");  // ShieldTTF has just one glyph at the code point for capital A
-TextColor(0xfff48542);
+TextColor(ShieldColor());
 Font(FONT(Shield));
 END_ELEMENT();
 
 BEGIN_ELEMENT(LabelTitle, teeui::Label)
-FontSize(22_dp);
-LineHeight(28_dp);
+FontSize(20_dp);
+LineHeight(20_dp);
 NumberOfLines(1);
 Dimension(RightEdgeOfScreen() - BorderWidth, HeightFromLines);
-Position(BorderWidth, BOTTOM_EDGE_OF(IconShield) + 16_dp);
+Position(BorderWidth, BOTTOM_EDGE_OF(IconShield) + 12_dp);
 DefaultText("Android Protected Confirmation");
-Font(DefaultFont);
+Font(FONT(RobotoMedium));
 VerticallyCentered;
-TextColor(DefaultTextColor);
+TextColor(ColorText());
 TextID(6973195374358399966);
 END_ELEMENT();
 
@@ -141,7 +143,7 @@
 DefaultText("This confirmation provides an extra layer of security for the action you're "
             "about to take.");
 VerticallyCentered;
-TextColor(DefaultTextColor);
+TextColor(ColorText());
 Font(DefaultFont);
 TextID(217688588483778177);
 END_ELEMENT();
@@ -150,17 +152,15 @@
 FontSize(BodyFontSize());
 LineHeight(BodyFontSize() * 1.4_px);
 NumberOfLines(20);
-Position(BorderWidth, BOTTOM_EDGE_OF(LabelTitle) + 24_dp);
+Position(BorderWidth, BOTTOM_EDGE_OF(LabelTitle) + 18_dp);
 Dimension(LabelWidth, LabelHint::pos_y - pos_y - 24_dp);
-DefaultText("Confirmation Message");
-TextColor(DefaultTextColor);
-Font(DefaultFont);
+DefaultText("12345678901234567890123456789012345678901234567890123456789012345678901234567890123456"
+            "78901234567890");
+TextColor(ColorText());
+Font(FONT(RobotoRegular));
 END_ELEMENT();
 
 NEW_LAYOUT(ConfUILayout, LabelOK, IconPower, LabelCancel, IconVolUp, IconShield, LabelTitle,
            LabelHint, LabelBody);
 
-// LABELS(ConfUILabels, LabelOK, LabelCancel, LabelTitle, LabelHint, LabelBody);
 }  // namespace teeui
-
-#endif  // TEEUI_LIBTEEUI_EXAMPLE_LAYOUT_H_
diff --git a/libteeui/example/teeui.cpp b/libteeui/example/teeui.cpp
index 1ee7718..9b9ed57 100644
--- a/libteeui/example/teeui.cpp
+++ b/libteeui/example/teeui.cpp
@@ -25,6 +25,22 @@
 
 static DeviceInfo sDeviceInfo;
 static bool sMagnified;
+static bool sInverted;
+static std::string sConfirmationMessage;
+
+/*
+ * AOSP color scheme constants.
+ */
+constexpr static const Color kShieldColor = Color(0xff778500);
+constexpr static const Color kShieldColorInv = Color(0xffc4cb80);
+constexpr static const Color kTextColor = Color(0xff212121);
+constexpr static const Color kTextColorInv = Color(0xffdedede);
+constexpr static const Color kBackGroundColor = Color(0xffffffff);
+constexpr static const Color kBackGroundColorInv = Color(0xff212121);
+
+void setConfirmationMessage(const char* confirmationMessage) {
+    sConfirmationMessage = confirmationMessage;
+}
 
 uint32_t alfaCombineChannel(uint32_t shift, double alfa, uint32_t a, uint32_t b) {
     a >>= shift;
@@ -75,9 +91,10 @@
     return (std::get<Elements>(layout).draw(drawPixel) || ...);
 }
 
-uint32_t setDeviceInfo(DeviceInfo deviceInfo, bool magnified) {
+uint32_t setDeviceInfo(DeviceInfo deviceInfo, bool magnified, bool inverted) {
     sDeviceInfo = deviceInfo;
     sMagnified = magnified;
+    sInverted = inverted;
     return 0;
 }
 
@@ -109,30 +126,42 @@
         afterLastPixelIndex > buffer_size_in_elements_not_bytes) {
         return uint32_t(Error::OutOfBoundsDrawing);
     }
-    context<ConUIParameters> conv(sDeviceInfo.mm2px_, sDeviceInfo.dp2px_);
-    conv.setParam<RightEdgeOfScreen>(pxs(sDeviceInfo.width_));
-    conv.setParam<BottomOfScreen>(pxs(sDeviceInfo.height_));
-    conv.setParam<PowerButtonTop>(mms(sDeviceInfo.powerButtonTopMm_));
-    conv.setParam<PowerButtonBottom>(mms(sDeviceInfo.powerButtonBottomMm_));
-    conv.setParam<VolUpButtonTop>(mms(sDeviceInfo.volUpButtonTopMm_));
-    conv.setParam<VolUpButtonBottom>(mms(sDeviceInfo.volUpButtonBottomMm_));
+    context<ConUIParameters> ctx(sDeviceInfo.mm2px_, sDeviceInfo.dp2px_);
+    ctx.setParam<RightEdgeOfScreen>(pxs(sDeviceInfo.width_));
+    ctx.setParam<BottomOfScreen>(pxs(sDeviceInfo.height_));
+    ctx.setParam<PowerButtonTop>(mms(sDeviceInfo.powerButtonTopMm_));
+    ctx.setParam<PowerButtonBottom>(mms(sDeviceInfo.powerButtonBottomMm_));
+    ctx.setParam<VolUpButtonTop>(mms(sDeviceInfo.volUpButtonTopMm_));
+    ctx.setParam<VolUpButtonBottom>(mms(sDeviceInfo.volUpButtonBottomMm_));
     if (sMagnified) {
-        conv.setParam<DefaultFontSize>(18_dp);
-        conv.setParam<BodyFontSize>(20_dp);
+        ctx.setParam<DefaultFontSize>(18_dp);
+        ctx.setParam<BodyFontSize>(20_dp);
     } else {
-        conv.setParam<DefaultFontSize>(14_dp);
-        conv.setParam<BodyFontSize>(16_dp);
+        ctx.setParam<DefaultFontSize>(14_dp);
+        ctx.setParam<BodyFontSize>(16_dp);
     }
 
-    auto layoutInstance = instantiateLayout(ConfUILayout(), conv);
+    if (sInverted) {
+        ctx.setParam<ShieldColor>(kShieldColorInv);
+        ctx.setParam<ColorText>(kTextColorInv);
+        ctx.setParam<ColorBG>(kBackGroundColorInv);
+    } else {
+        ctx.setParam<ShieldColor>(kShieldColor);
+        ctx.setParam<ColorText>(kTextColor);
+        ctx.setParam<ColorBG>(kBackGroundColor);
+    }
+
+    auto layoutInstance = instantiateLayout(ConfUILayout(), ctx);
 
     translateLabels(layoutInstance);
 
     uint32_t* begin = buffer + (y * lineStride + x);
+
+    Color bgColor = sInverted ? kBackGroundColorInv : kBackGroundColor;
+
     for (uint32_t yi = 0; yi < h; ++yi) {
         for (uint32_t xi = 0; xi < w; ++xi) {
-            begin[xi] = 0xffffffff;
-            //            begin[xi] = renderPixel(x + xi, y + yi, layoutInstance);
+            begin[xi] = bgColor;
         }
         begin += lineStride;
     }
@@ -148,6 +177,9 @@
     auto pixelDrawer = makePixelDrawer(
         [&fb](uint32_t x, uint32_t y, Color color) -> Error { return fb.drawPixel(x, y, color); });
 
+    std::get<LabelBody>(layoutInstance)
+        .setText({&*sConfirmationMessage.begin(), &*sConfirmationMessage.end()});
+
     if (auto error = drawElements(layoutInstance, pixelDrawer)) {
         return uint32_t(error.code());
     }
diff --git a/libteeui/include/teeui/button.h b/libteeui/include/teeui/button.h
index 8d6c02b..1762a0f 100644
--- a/libteeui/include/teeui/button.h
+++ b/libteeui/include/teeui/button.h
@@ -84,10 +84,10 @@
     template <typename Context>
     explicit Button(const Context& context)
         : LayoutElement<Derived>(context),
-          ButtonImpl(context = Derived::button_radius, Derived::button_color,
-                     Derived::button_drawable_object_color, Derived::button_round_top_left,
-                     Derived::button_round_top_right, Derived::button_round_bottom_left,
-                     Derived::button_round_bottom_right) {
+          ButtonImpl(context = Derived::button_radius, context = Derived::button_color,
+                     context = Derived::button_drawable_object_color,
+                     Derived::button_round_top_left, Derived::button_round_top_right,
+                     Derived::button_round_bottom_left, Derived::button_round_bottom_right) {
         static_assert(
             convexElemCount::value >=
                 std::tuple_size<decltype(Derived::button_drawable_objects)>::value,
@@ -113,7 +113,7 @@
 
 #define CornerRadius(radius) static const constexpr auto button_radius = radius
 
-#define ButtonColor(color) static const constexpr Color button_color = color
+#define ButtonColor(color) static const constexpr auto button_color = color
 
 #define RoundTopLeft static const constexpr bool button_round_top_left = true
 #define RoundTopRight static const constexpr bool button_round_top_right = true
@@ -130,6 +130,6 @@
 #define ConvexObjects(convex_objects)                                                              \
     static constexpr const auto button_drawable_objects = convex_objects
 
-#define ConvexObjectColor(color) static constexpr const Color button_drawable_object_color = color
+#define ConvexObjectColor(color) static constexpr const auto button_drawable_object_color = color
 
 #endif  // LIBTEEUI_BUTTON_H_
diff --git a/libteeui/include/teeui/example/teeui.h b/libteeui/include/teeui/example/teeui.h
index 2e456e7..3ee37f4 100644
--- a/libteeui/include/teeui/example/teeui.h
+++ b/libteeui/include/teeui/example/teeui.h
@@ -32,10 +32,12 @@
     double volUpButtonBottomMm_;
 };
 
-uint32_t setDeviceInfo(DeviceInfo device_info, bool magnified);
+uint32_t setDeviceInfo(DeviceInfo device_info, bool magnified, bool inverted = false);
 uint32_t renderUIIntoBuffer(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t lineStride,
                             uint32_t* buffer, size_t buffer_size_in_elements_not_bytes);
 
 void selectLanguage(const char* language_id);
 
+void setConfirmationMessage(const char* confirmationMessage);
+
 #endif  // TEEUI_LIBTEEUI_INCLUDE_TEEUI_H_
diff --git a/libteeui/include/teeui/label.h b/libteeui/include/teeui/label.h
index 97a47e6..acead70 100644
--- a/libteeui/include/teeui/label.h
+++ b/libteeui/include/teeui/label.h
@@ -114,7 +114,8 @@
               context = Derived::label_font_size, context = Derived::label_line_height,
               {&Derived::label_text[0], &Derived::label_text[sizeof(Derived::label_text) - 1]},
               Derived::label_right_justified, Derived::label_vertically_centered,
-              Derived::label_text_color, getFont(Derived::label_font), Derived::text_id) {}
+              context = Derived::label_text_color, getFont(Derived::label_font), Derived::text_id) {
+    }
 
     Error draw(const PixelDrawer& drawPixel) {
         LabelImpl::LineInfo::info_t lines[Derived::label_number_of_lines];
@@ -139,7 +140,7 @@
 
 #define VerticallyCentered static const constexpr bool label_vertically_centered = true
 
-#define TextColor(color) static const constexpr Color label_text_color = color
+#define TextColor(color) static const constexpr auto label_text_color = color
 
 #define FONT(name) TEEUI_FONT_##name()
 
diff --git a/libteeui/include/teeui/utils.h b/libteeui/include/teeui/utils.h
index f9f318c..7e8f69e 100644
--- a/libteeui/include/teeui/utils.h
+++ b/libteeui/include/teeui/utils.h
@@ -185,8 +185,6 @@
 
 using DefaultNumericType = float;
 
-template <typename UnitFrom, typename UnitTo, typename Numeric = DefaultNumericType> struct convert;
-
 namespace bits {
 
 inline long double abs(long double v) {
@@ -220,6 +218,18 @@
     return ::sqrt(v);
 }
 
+inline float round(float v) {
+    return ::roundf(v);
+}
+
+inline long double round(long double v) {
+    return ::roundl(v);
+}
+
+inline double round(double v) {
+    return ::round(v);
+}
+
 }  // namespace bits
 
 template <typename Unit, typename Numeric = DefaultNumericType> class Coordinate;
@@ -267,9 +277,9 @@
     BinOp(const BinOp&) = default;
     BinOp(BinOp&&) = default;
 
-    template <typename Context> Coordinate<px, Numeric> eval(const Context& conv) const {
-        Coordinate<px, Numeric> v1 = conv = v1_;
-        Coordinate<px, Numeric> v2 = conv = v2_;
+    template <typename Context> Coordinate<px, Numeric> eval(const Context& ctx) const {
+        Coordinate<px, Numeric> v1 = ctx = v1_;
+        Coordinate<px, Numeric> v2 = ctx = v2_;
         return Op<Numeric>::eval(v1, v2);
     }
     template <typename T> constexpr add<BinOp, T, Numeric> operator+(const T& v) const {
@@ -286,7 +296,10 @@
     }
 };
 
-template <typename Name, typename Numeric> struct MetaParam {
+template <typename Name, typename ParamType> struct MetaParam {};
+
+template <typename Name, typename Unit, typename Numeric>
+struct MetaParam<Name, Coordinate<Unit, Numeric>> {
     template <typename T> constexpr add<MetaParam, T, Numeric> operator+(const T& v) const {
         return {*this, v};
     }
@@ -301,9 +314,9 @@
     }
 };
 
-template <typename Name, typename Numeric> struct Param {
-    Coordinate<px, Numeric> coord_;
-    Param() : coord_(0) {}
+template <typename Name, typename ParamType> struct Param {
+    ParamType param_;
+    Param() : param_{} {}
     Param(const Param&) = default;
     Param(Param&&) = default;
     Param& operator=(const Param&) = default;
@@ -319,7 +332,13 @@
     constexpr Coordinate(Numeric value) : value_(value) {}
     Coordinate(const Coordinate&) = default;
     Coordinate(Coordinate&&) = default;
-    template <typename N> Coordinate(const Coordinate<Unit, N>& other) : value_(other.count()) {}
+    template <typename N> Coordinate(const Coordinate<Unit, N>& other) {
+        if constexpr (std::is_floating_point<N>::value && std::is_integral<Numeric>::value) {
+            value_ = bits::round(other.count());
+        } else {
+            value_ = other.count();
+        }
+    }
     Coordinate& operator=(const Coordinate& rhs) = default;
     Coordinate& operator=(Coordinate&& rhs) = default;
 
@@ -377,16 +396,43 @@
 
 template <typename MetaParam> struct metaParam2Param;
 
-template <typename ParamName, typename Numeric>
-struct metaParam2Param<MetaParam<ParamName, Numeric>> {
-    using type = Param<ParamName, Numeric>;
+template <typename ParamName, typename ParamType>
+struct metaParam2Param<MetaParam<ParamName, ParamType>> {
+    using type = Param<ParamName, ParamType>;
 };
 
-template <typename... ParamsNames, typename Numeric>
-class context<MetaList<MetaParam<ParamsNames, Numeric>...>, Numeric> {
+template <typename MetaParam> struct metaParam2ParamType;
+
+template <typename ParamName, typename ParamType>
+struct metaParam2ParamType<MetaParam<ParamName, ParamType>> {
+    using type = ParamType;
+};
+
+template <typename T> struct isCoordinateType { constexpr static const bool value = false; };
+
+template <typename Unit, typename Numeric> struct isCoordinateType<Coordinate<Unit, Numeric>> {
+    constexpr static const bool value = true;
+};
+
+template <typename MetaParam> struct isCoordinateParam;
+
+template <typename ParamName, typename ParamType>
+struct isCoordinateParam<MetaParam<ParamName, ParamType>> {
+    constexpr static const bool value = isCoordinateType<ParamType>::value;
+};
+
+template <typename T> struct isMetaParam { constexpr static const bool value = false; };
+
+template <typename ParamName, typename ParamType>
+struct isMetaParam<MetaParam<ParamName, ParamType>> {
+    constexpr static const bool value = true;
+};
+
+template <typename... ParamsNames, typename... ParamTypes, typename Numeric>
+class context<MetaList<MetaParam<ParamsNames, ParamTypes>...>, Numeric> {
     Numeric mm2px_;
     Numeric dp2px_;
-    std::tuple<Param<ParamsNames, Numeric>...> params_;
+    std::tuple<Param<ParamsNames, ParamTypes>...> params_;
 
     class Proxy {
         Numeric valuepx_;
@@ -418,12 +464,22 @@
         return std::get<typename metaParam2Param<MetaParam>::type>(params_);
     }
 
-    template <typename MetaParam> void setParam(const Coordinate<px, Numeric>& v) {
-        getParam<MetaParam>().coord_ = v;
+    template <typename MetaParam>
+    void setParam(
+        std::enable_if_t<isCoordinateParam<MetaParam>::value, const Coordinate<px, Numeric>>& v) {
+        getParam<MetaParam>().param_ = v;
     }
 
-    template <typename MetaParam, typename T> void setParam(const T& v) {
-        getParam<MetaParam>().coord_ = *this = v;
+    template <typename MetaParam, typename Unit, typename N,
+              typename = std::enable_if_t<isCoordinateParam<MetaParam>::value>>
+    void setParam(const Coordinate<Unit, N>& v) {
+        getParam<MetaParam>().param_ = *this = v;
+    }
+
+    template <typename MetaParam>
+    void setParam(std::enable_if_t<!isCoordinateParam<MetaParam>::value,
+                                   const typename metaParam2ParamType<MetaParam>::type>& v) {
+        getParam<MetaParam>().param_ = v;
     }
 
     Proxy operator=(const Coordinate<px, Numeric>& rhs) const {
@@ -439,8 +495,20 @@
     Proxy operator=(const BinOp<T1, T2, Numeric, Op>& rhs) const {
         return {rhs.eval(*this).count(), mm2px_, dp2px_};
     }
-    template <typename ParamName> Proxy operator=(const MetaParam<ParamName, Numeric>&) const {
-        return {getParam<MetaParam<ParamName, Numeric>>().coord_.count(), mm2px_, dp2px_};
+    template <typename ParamName, typename ParamType>
+    std::enable_if_t<isCoordinateParam<MetaParam<ParamName, ParamType>>::value, Proxy>
+    operator=(const MetaParam<ParamName, ParamType>&) const {
+        return {getParam<MetaParam<ParamName, ParamType>>().param_.count(), mm2px_, dp2px_};
+    }
+    template <typename ParamName, typename ParamType>
+    std::enable_if_t<!isCoordinateParam<MetaParam<ParamName, ParamType>>::value, const ParamType&>
+    operator=(const MetaParam<ParamName, ParamType>&) const {
+        return getParam<MetaParam<ParamName, ParamType>>().param_;
+    }
+    template <typename T,
+              typename = std::enable_if_t<!(isMetaParam<T>::value || isCoordinateType<T>::value)>>
+    inline T&& operator=(T&& v) const {
+        return std::forward<T>(v);
     }
 };
 
@@ -764,7 +832,7 @@
      */
     Box translate(const Point<Coord>& offset) const& {
         Box result = *this;
-        result += offset;
+        result.topLeft_ += offset;
         return result;
     }
     /*
@@ -897,9 +965,11 @@
 
 #define END_ELEMENT() }
 
-#define DECLARE_PARAMETER(name)                                                                    \
+#define DECLARE_TYPED_PARAMETER(name, type)                                                        \
     struct Param_##name {};                                                                        \
-    using name = ::teeui::MetaParam<Param_##name, DefaultNumericType>
+    using name = ::teeui::MetaParam<Param_##name, type>
+
+#define DECLARE_PARAMETER(name) DECLARE_TYPED_PARAMETER(name, ::teeui::pxs)
 
 #define CONSTANT(name, value) static constexpr const auto name = value
 
diff --git a/libteeui/src/button.cpp b/libteeui/src/button.cpp
index 9b4f2b0..e55e56c 100644
--- a/libteeui/src/button.cpp
+++ b/libteeui/src/button.cpp
@@ -28,8 +28,7 @@
                        const ConvexObjectInfo* coBegin, const ConvexObjectInfo* coEnd) {
 
     using intpxs = Coordinate<px, int64_t>;
-    Box<intpxs> intBounds(intpxs((int64_t)bounds.x().count()), intpxs((int64_t)bounds.y().count()),
-                          intpxs((int64_t)bounds.w().count()), intpxs((int64_t)bounds.h().count()));
+    Box<intpxs> intBounds(bounds);
 
     auto drawPixelBoundsEnforced = [&](uint32_t x, uint32_t y, Color color) -> Error {
         if (!intBounds.contains(Point<intpxs>(x, y))) {
@@ -123,15 +122,12 @@
         }
     }
 
-    if (auto error = drawCorner(1, 0)) return error;
-    if (auto error = drawCorner(0, 1)) return error;
-    if (auto error = drawCorner(1, 1)) return error;
-
     auto centerbox = Box<intpxs>(intRadius, intRadius, intBounds.w() - intRadius - intRadius,
                                  intBounds.h() - intRadius - intRadius)
                          .translate(intBounds.topLeft());
 
     if (auto error = drawBox(centerbox, color_)) return error;
+
     if (auto error =
             drawBox(Box<intpxs>(0, intRadius, intRadius, intBounds.h() - intRadius - intRadius)
                         .translate(intBounds.topLeft()),
diff --git a/libteeui/src/font_rendering.cpp b/libteeui/src/font_rendering.cpp
index 9ee1c19..49c4847 100644
--- a/libteeui/src/font_rendering.cpp
+++ b/libteeui/src/font_rendering.cpp
@@ -179,6 +179,7 @@
             }
             pen += face->advance();
             previous = gindex;
+            ++c;
             if (workingBox.fitsInside(boundingBox)) {
                 currentBox = workingBox;
                 sequenceEnd = c;
@@ -187,7 +188,6 @@
                 TEEUI_LOG << "exceeding bbox" << ENDL;
                 break;
             }
-            ++c;
         }
         if (exceedsBoundingBox) break;
         wordStart = wordEnd;
diff --git a/libteeui/src/label.cpp b/libteeui/src/label.cpp
index 9847902..c1413c5 100644
--- a/libteeui/src/label.cpp
+++ b/libteeui/src/label.cpp
@@ -107,7 +107,7 @@
     curLine = lineInfo->begin();
 
 #ifdef DRAW_DEBUG_MARKERS
-    drawBox(*boundingBox + offset, 0xff00);
+    drawBox(boundingBox->translate(offset), 0xff00);
     auto p = offset + curLine->lineStart;
     drawPixel(p.x().count(), p.y().count(), 0xffff0000);
 #endif
diff --git a/libteeui_jni/include/com_android_framebufferizer_NativeRenderer.h b/libteeui_jni/include/com_android_framebufferizer_NativeRenderer.h
index 774200c..10b10a8 100644
--- a/libteeui_jni/include/com_android_framebufferizer_NativeRenderer.h
+++ b/libteeui_jni/include/com_android_framebufferizer_NativeRenderer.h
@@ -10,12 +10,10 @@
 /*
  * Class:     com_android_framebufferizer_NativeRenderer
  * Method:    setDeviceInfo
- * Signature: (Lcom/android/framebufferizer/utils/DeviceInfo;Z)I
+ * Signature: (Lcom/android/framebufferizer/utils/DeviceInfo;ZZ)I
  */
-JNIEXPORT jint JNICALL Java_com_android_framebufferizer_NativeRenderer_setDeviceInfo(JNIEnv*,
-                                                                                     jclass,
-                                                                                     jobject,
-                                                                                     jboolean);
+JNIEXPORT jint JNICALL Java_com_android_framebufferizer_NativeRenderer_setDeviceInfo(
+    JNIEnv*, jclass, jobject, jboolean, jboolean);
 
 /*
  * Class:     com_android_framebufferizer_NativeRenderer
@@ -26,19 +24,29 @@
     JNIEnv*, jclass, jint, jint, jint, jint, jint, jintArray);
 
 /*
- * Class:     com_android_framebufferizer_NativeRenderer_setLanguage
+ * Class:     com_android_framebufferizer_NativeRenderer
  * Method:    setLanguage
- * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ * Signature: (Ljava/lang/String;)V
  */
 JNIEXPORT void JNICALL Java_com_android_framebufferizer_NativeRenderer_setLanguage(JNIEnv*, jclass,
                                                                                    jstring);
+
 /*
- * Class:     com_android_framebufferizer_NativeRenderer_getLanguageIdList
+ * Class:     com_android_framebufferizer_NativeRenderer
  * Method:    getLanguageIdList
+ * Signature: ()[Ljava/lang/String;
  */
 JNIEXPORT jobjectArray JNICALL
 Java_com_android_framebufferizer_NativeRenderer_getLanguageIdList(JNIEnv*, jclass);
 
+/*
+ * Class:     com_android_framebufferizer_NativeRenderer
+ * Method:    setConfimationMessage
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL
+Java_com_android_framebufferizer_NativeRenderer_setConfimationMessage(JNIEnv*, jclass, jstring);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libteeui_jni/libteeui_jni.cpp b/libteeui_jni/libteeui_jni.cpp
index ee08859..807100e 100644
--- a/libteeui_jni/libteeui_jni.cpp
+++ b/libteeui_jni/libteeui_jni.cpp
@@ -126,10 +126,10 @@
 /*
  * Class:     com_android_framebufferizer_NativeRenderer
  * Method:    setDeviceInfo
- * Signature: (Lcom/android/framebufferizer/utils/DeviceInfo;Z)I
+ * Signature: (Lcom/android/framebufferizer/utils/DeviceInfo;ZZ)I
  */
 extern "C" JNIEXPORT jint JNICALL Java_com_android_framebufferizer_NativeRenderer_setDeviceInfo(
-    JNIEnv* env, jclass, jobject jDeviceInfo, jboolean magnified) {
+    JNIEnv* env, jclass, jobject jDeviceInfo, jboolean magnified, jboolean inverted) {
     jclass cDeviceInfo = env->FindClass("Lcom/android/framebufferizer/utils/DeviceInfo;");
     jmethodID method = env->GetMethodID(cDeviceInfo, "getWidthPx", "()I");
     DeviceInfo device_info;
@@ -148,7 +148,7 @@
     device_info.volUpButtonTopMm_ = env->CallDoubleMethod(jDeviceInfo, method);
     method = env->GetMethodID(cDeviceInfo, "getVolUpButtonBottomMm", "()D");
     device_info.volUpButtonBottomMm_ = env->CallDoubleMethod(jDeviceInfo, method);
-    return setDeviceInfo(device_info, magnified);
+    return setDeviceInfo(device_info, magnified, inverted);
 }
 
 /*
@@ -165,8 +165,9 @@
                               (uint32_t)lineStride, (uint32_t*)buffer.begin(), buffer.size());
 }
 /*
- * Class:     com_android_framebufferizer_NativeRenderer_setLanguage
- * Method:    setLanguage
+ * Class:     com_android_confirmationui_Translation_selectLangID
+ * Method:    selectLangID
+ * Signature: (Ljava/lang/String;)V
  */
 extern "C" JNIEXPORT void JNICALL
 Java_com_android_framebufferizer_NativeRenderer_setLanguage(JNIEnv* env, jclass, jstring jlang_id) {
@@ -176,8 +177,9 @@
     (env)->ReleaseStringUTFChars(jlang_id, lang_id);
 }
 /*
- * Class:     com_android_framebufferizer_NativeRenderer_getLanguageIdList
- * Method:    getLanguageIdList
+ * Class:     com_android_confirmationui_Translation_selectLangID
+ * Method:    selectLangID
+ * Signature: ()[Ljava/lang/String;
  */
 extern "C" JNIEXPORT jobjectArray JNICALL
 Java_com_android_framebufferizer_NativeRenderer_getLanguageIdList(JNIEnv* env, jclass) {
@@ -194,3 +196,14 @@
 
     return language_ids;
 }
+/*
+ * Class:     com_android_framebufferizer_NativeRenderer
+ * Method:    setConfimationMessage
+ * Signature: (Ljava/lang/String;)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_android_framebufferizer_NativeRenderer_setConfimationMessage(
+    JNIEnv* env, jclass, jstring jConfirmationMessage) {
+    JString confirmationMessage(env, jConfirmationMessage);
+    setConfirmationMessage(confirmationMessage.begin());
+}
diff --git a/tools/framebufferizer/src/com/android/framebufferizer/Main.java b/tools/framebufferizer/src/com/android/framebufferizer/Main.java
index 8bd76dd..b4b938f 100644
--- a/tools/framebufferizer/src/com/android/framebufferizer/Main.java
+++ b/tools/framebufferizer/src/com/android/framebufferizer/Main.java
@@ -20,8 +20,6 @@
 import com.android.framebufferizer.utils.FrameBufferBuffer;
 
 import java.awt.*;
-import java.awt.image.DataBufferInt;
-import java.security.SecureRandom;
 import java.util.Random;
 
 import javax.swing.*;
@@ -37,19 +35,15 @@
         theFramebuffer = new FrameBufferBuffer();
         theFramebuffer.setFrame(theFrame);
         FrameBufferBuffer.MagnifiedView magnifiedView = theFramebuffer.getMagnifiedView();
-        FrameBufferBuffer.DeviceSelector deviceSelector = theFramebuffer.getDeviceSelector();
-        FrameBufferBuffer.LanguageSelector languageSelector = theFramebuffer.getLanguageSelector();
+        FrameBufferBuffer.ConfigSelector configSelector = theFramebuffer.getConfigSelector();
         magnifiedView.setPreferredSize(new Dimension(100, 100));
         magnifiedView.setMinimumSize(new Dimension(100, 100));
         magnifiedView.setMaximumSize(new Dimension(100, 100));
         theFrame.getContentPane().add(magnifiedView, BorderLayout.EAST);
         theFrame.getContentPane().add(theFramebuffer, BorderLayout.CENTER);
-        theFrame.getContentPane().add(deviceSelector, BorderLayout.NORTH);
-        theFrame.getContentPane().add(languageSelector, BorderLayout.SOUTH);
+        theFrame.getContentPane().add(configSelector, BorderLayout.NORTH);
         theFrame.pack();
         theFrame.setVisible(true);
-        deviceSelector.refreshSelections();
-
     }
 
     public static void main(String[] args) {
diff --git a/tools/framebufferizer/src/com/android/framebufferizer/NativeRenderer.java b/tools/framebufferizer/src/com/android/framebufferizer/NativeRenderer.java
index 0198892..eca320e 100644
--- a/tools/framebufferizer/src/com/android/framebufferizer/NativeRenderer.java
+++ b/tools/framebufferizer/src/com/android/framebufferizer/NativeRenderer.java
@@ -23,8 +23,9 @@
          System.loadLibrary("teeui_jni");
     }
 
-    public static native int setDeviceInfo(DeviceInfo deviceInfo, boolean magnified);
+    public static native int setDeviceInfo(DeviceInfo deviceInfo, boolean magnified, boolean inverted);
     public static native int renderBuffer(int x, int y, int width, int height, int lineStride, int[] buffer);
     public static native void setLanguage(String language_id);
     public static native String[] getLanguageIdList();
+    public static native void setConfimationMessage(String confimationMessage);
 }
diff --git a/tools/framebufferizer/src/com/android/framebufferizer/utils/FrameBufferBuffer.java b/tools/framebufferizer/src/com/android/framebufferizer/utils/FrameBufferBuffer.java
index a1104f1..4b97657 100644
--- a/tools/framebufferizer/src/com/android/framebufferizer/utils/FrameBufferBuffer.java
+++ b/tools/framebufferizer/src/com/android/framebufferizer/utils/FrameBufferBuffer.java
@@ -23,8 +23,6 @@
 import java.awt.event.ComponentListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionListener;
-import java.awt.event.ItemListener;
-import java.awt.event.ItemEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ActionEvent;
 import java.awt.geom.AffineTransform;
@@ -88,63 +86,112 @@
     }
 
 
-    public class DeviceSelector extends JPanel implements ActionListener {
-        private JComboBox<String> dropDownMenu = new JComboBox(DeviceInfoDB.Device.values());
-        private JCheckBox magnifiedCheckbox = new JCheckBox("Magnified");
+    public class ConfigSelector extends JPanel implements ActionListener {
+        private final String languages [];
 
-        protected DeviceSelector() {
-            dropDownMenu.addActionListener(this);
+        {
+            languages = NativeRenderer.getLanguageIdList();
+        }
+
+        private JComboBox<String> deviceSelector = new JComboBox(DeviceInfoDB.Device.values());
+        private JCheckBox magnifiedCheckbox = new JCheckBox("Magnified");
+        private JCheckBox invertedCheckbox = new JCheckBox("Inverted");
+        private JComboBox<String> localeSelector = new JComboBox(languages);
+        private JTextField confirmationMessage = new JTextField();
+
+        protected ConfigSelector() {
+            System.err.println("ConfigSelector");
+            this.setLayout(new GridBagLayout());
+
+            GridBagConstraints c = null;
+
+            c = new GridBagConstraints();
+            c.gridx = 0;
+            c.gridy = 0;
+            this.add(new JLabel("Select Device:"), c);
+
+            deviceSelector.addActionListener(this);
+            c = new GridBagConstraints();
+            c.gridx = 1;
+            c.gridy = 0;
+            c.fill = GridBagConstraints.HORIZONTAL;
+            c.gridwidth = 2;
+            this.add(deviceSelector, c);
+
+            c = new GridBagConstraints();
+            c.gridx = 0;
+            c.gridy = 1;
+            this.add(new JLabel("Select Locale:"), c);
+
+            localeSelector.addActionListener(this);
+            c = new GridBagConstraints();
+            c.gridx = 1;
+            c.gridy = 1;
+            c.gridwidth = 2;
+            c.fill = GridBagConstraints.HORIZONTAL;
+            this.add(localeSelector, c);
+
+            c = new GridBagConstraints();
+            c.gridx = 0;
+            c.gridy = 2;
+            this.add(new JLabel("UIOptions:"), c);
+
             magnifiedCheckbox.addActionListener(this);
-            this.add(dropDownMenu);
-            this.add(magnifiedCheckbox);
+            c = new GridBagConstraints();
+            c.gridx = 1;
+            c.gridy = 2;
+            this.add(magnifiedCheckbox, c);
+
+            invertedCheckbox.addActionListener(this);
+            c = new GridBagConstraints();
+            c.gridx = 2;
+            c.gridy = 2;
+            this.add(invertedCheckbox, c);
+
+            c = new GridBagConstraints();
+            c.gridx = 0;
+            c.gridy = 3;
+            this.add(new JLabel("Confirmation message:"), c);
+
+            confirmationMessage.setText("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW");
+            confirmationMessage.addActionListener(this);
+            c = new GridBagConstraints();
+            c.gridx = 1;
+            c.gridy = 3;
+            c.fill = GridBagConstraints.BOTH;
+            c.gridwidth = 2;
+            this.add(confirmationMessage, c);
         }
 
         public void actionPerformed(ActionEvent e) {
-            synchronized (this) {
-                FrameBufferBuffer.this.calibrateNativeBuffer();
-            }
-        }
-
-        public void refreshSelections(){
-            dropDownMenu.setSelectedItem(DeviceInfoDB.Device.CORAL);
+            FrameBufferBuffer.this.renderNativeBuffer();
         }
 
         public DeviceInfoDB.Device currentDevice() {
-            return (DeviceInfoDB.Device) dropDownMenu.getSelectedItem();
+            return (DeviceInfoDB.Device) deviceSelector.getSelectedItem();
+        }
+
+        public String currentLocale() {
+            return (String)localeSelector.getSelectedItem();
         }
 
         public boolean magnified() {
             return magnifiedCheckbox.isSelected();
         }
-    }
 
-    public class LanguageSelector extends JPanel implements ActionListener {
-        String languages [] = NativeRenderer.getLanguageIdList();
-
-        private JComboBox<String> dropDownMenu;
-
-        protected LanguageSelector() {
-            dropDownMenu = new JComboBox(languages);
-            dropDownMenu.addActionListener(this);
-            this.add(dropDownMenu);
+        public boolean inverted() {
+            return invertedCheckbox.isSelected();
         }
 
-        public void actionPerformed(ActionEvent e) {
-            synchronized (this) {
-                String language = (String) dropDownMenu.getSelectedItem();
-                NativeRenderer.setLanguage(language);
-                FrameBufferBuffer.this.calibrateNativeBuffer();
-            }
+        public String confirmationMessage() {
+            return confirmationMessage.getText();
         }
-
     }
 
-
     private BufferedImage mImage;
     private DataBufferInt mBuffer;
     private MagnifiedView mMagnifiedView;
-    private DeviceSelector mDeviceSelector;
-    private LanguageSelector mLanguageSelector;
+    private ConfigSelector mConfigSelector;
     private JFrame mFrame;
 
     public MagnifiedView getMagnifiedView() {
@@ -154,18 +201,11 @@
         return mMagnifiedView;
     }
 
-    public DeviceSelector getDeviceSelector(){
-        if (mDeviceSelector == null){
-            mDeviceSelector = new DeviceSelector();
+    public ConfigSelector getConfigSelector(){
+        if (mConfigSelector == null){
+            mConfigSelector = new ConfigSelector();
         }
-        return mDeviceSelector;
-    }
-
-    public LanguageSelector getLanguageSelector(){
-        if (mLanguageSelector == null){
-            mLanguageSelector = new LanguageSelector();
-        }
-        return mLanguageSelector;
+        return mConfigSelector;
     }
 
     @Override
@@ -205,14 +245,14 @@
     public FrameBufferBuffer() {
         setSize(412, 900);
         setPreferredSize(new Dimension(412, 900));
-        calibrateNativeBuffer();
+        renderNativeBuffer();
         addComponentListener(this);
         addMouseMotionListener(this);
     }
 
     @Override
     public void componentResized(ComponentEvent e) {
-        calibrateNativeBuffer();
+        renderNativeBuffer();
         repaint();
     }
     @Override
@@ -241,13 +281,12 @@
         mFrame = frame;
     }
 
-    public void calibrateNativeBuffer(){
-      DeviceInfo deviceInfo = DeviceInfoDB.getDeviceInfo(getDeviceSelector().currentDevice());
-      boolean magnified = getDeviceSelector().magnified();
-      renderNativeBuffer(deviceInfo, magnified);
-      repaint();
-    }
-    public int renderNativeBuffer(DeviceInfo deviceInfo, boolean magnified){
+    public void renderNativeBuffer(){
+        DeviceInfo deviceInfo = DeviceInfoDB.getDeviceInfo(getConfigSelector().currentDevice());
+        boolean magnified = getConfigSelector().magnified();
+        boolean inverted = getConfigSelector().inverted();
+        NativeRenderer.setLanguage(getConfigSelector().currentLocale());
+        NativeRenderer.setConfimationMessage(getConfigSelector().confirmationMessage());
         int w = deviceInfo.getWidthPx();
         int h = deviceInfo.getHeightPx();
         final int linestride = w;
@@ -262,7 +301,7 @@
                 new int[]{rMask, gMask, bMask}, null);
             ColorModel colorModel = new DirectColorModel(bpp, rMask, gMask, bMask);
             BufferedImage image = new BufferedImage(colorModel, raster, true, null);
-            NativeRenderer.setDeviceInfo(deviceInfo, magnified);
+            NativeRenderer.setDeviceInfo(deviceInfo, magnified, inverted);
             error = NativeRenderer.renderBuffer(0, 0, w, h, linestride, mBuffer.getData());
             if (error != 0) {
                 System.out.println("Error rendering native buffer " + error);
@@ -270,12 +309,17 @@
 
             mImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
             Graphics2D gc = mImage.createGraphics();
-            double scale = (double)getWidth()/(double)w;
+            double scale = 0.0;
+            if (w/(double)h > getWidth()/(double)getHeight()) {
+                scale = (double)getWidth()/(double)w;
+            } else {
+                scale = (double)getHeight()/(double)h;
+            }
             gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
             gc.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
             gc.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
             gc.drawRenderedImage(image, AffineTransform.getScaleInstance(scale, scale));
         }
-        return error;
+        repaint();
     }
 }