Merge tag 'android-10.0.0_r25' into aosp10-4

Android 10.0.0 release 25
diff --git a/minui/Android.bp b/minui/Android.bp
new file mode 100644
index 0000000..fff3a8e
--- /dev/null
+++ b/minui/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2018 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.
+
+cc_library {
+    name: "libminui",
+    recovery_available: true,
+
+    defaults: [
+        "recovery_defaults",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    srcs: [
+        "events.cpp",
+        "graphics.cpp",
+        "graphics_adf.cpp",
+        "graphics_drm.cpp",
+        "graphics_fbdev.cpp",
+        "resources.cpp",
+    ],
+
+    whole_static_libs: [
+        "libadf",
+        "libdrm",
+        "libsync",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libpng",
+        "libz",
+    ],
+}
diff --git a/minui/events.cpp b/minui/events.cpp
index c777996..0b4540b 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -23,42 +23,49 @@
 #include <string.h>
 #include <sys/epoll.h>
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include <functional>
+#include <memory>
+
+#include <android-base/unique_fd.h>
 
 #include "minui/minui.h"
 
-#define MAX_DEVICES 16
-#define MAX_MISC_FDS 16
+constexpr size_t MAX_DEVICES = 16;
+constexpr size_t MAX_MISC_FDS = 16;
 
-#define BITS_PER_LONG (sizeof(unsigned long) * 8)
-#define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG)
+constexpr size_t BITS_PER_LONG = sizeof(unsigned long) * 8;
+constexpr size_t BITS_TO_LONGS(size_t bits) {
+  return ((bits + BITS_PER_LONG - 1) / BITS_PER_LONG);
+}
 
-struct fd_info {
-  int fd;
+struct FdInfo {
+  android::base::unique_fd fd;
   ev_callback cb;
 #ifdef TW_USE_MINUI_WITH_DATA
   void* data;
 #endif
 };
 
-static int g_epoll_fd;
-static epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS];
-static int npolledevents;
+static android::base::unique_fd g_epoll_fd;
+static epoll_event g_polled_events[MAX_DEVICES + MAX_MISC_FDS];
+static int g_polled_events_count;
 
-static fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
+static FdInfo ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
 
-static unsigned ev_count = 0;
-static unsigned ev_dev_count = 0;
-static unsigned ev_misc_count = 0;
+static size_t g_ev_count = 0;
+static size_t g_ev_dev_count = 0;
+static size_t g_ev_misc_count = 0;
 
 static bool test_bit(size_t bit, unsigned long* array) { // NOLINT
-    return (array[bit/BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0;
+  return (array[bit / BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0;
 }
 
 #ifdef TW_USE_MINUI_WITH_OPTIONAL_TOUCH_EVENTS
 int ev_init(ev_callback input_cb, bool allow_touch_inputs) {
+<<<<<<< HEAD
 #else
 #ifdef TW_USE_MINUI_WITH_DATA
 int ev_init(ev_callback input_cb, void* data) {
@@ -70,45 +77,44 @@
 
   g_epoll_fd = epoll_create(MAX_DEVICES + MAX_MISC_FDS);
   if (g_epoll_fd == -1) {
+=======
+  g_epoll_fd.reset();
+
+  android::base::unique_fd epoll_fd(epoll_create1(EPOLL_CLOEXEC));
+  if (epoll_fd == -1) {
+>>>>>>> android-10.0.0_r25
     return -1;
   }
 
-  bool epollctlfail = false;
-  DIR* dir = opendir("/dev/input");
-  if (dir != nullptr) {
-    dirent* de;
-    while ((de = readdir(dir))) {
-      if (strncmp(de->d_name, "event", 5)) continue;
-      int fd = openat(dirfd(dir), de->d_name, O_RDONLY);
-      if (fd == -1) continue;
+  std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/dev/input"), closedir);
+  if (!dir) {
+    return -1;
+  }
 
-      // Use unsigned long to match ioctl's parameter type.
-      unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];  // NOLINT
+  bool epoll_ctl_failed = false;
+  dirent* de;
+  while ((de = readdir(dir.get())) != nullptr) {
+    if (strncmp(de->d_name, "event", 5)) continue;
+    android::base::unique_fd fd(openat(dirfd(dir.get()), de->d_name, O_RDONLY | O_CLOEXEC));
+    if (fd == -1) continue;
 
-      // Read the evbits of the input device.
-      if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
-        close(fd);
+    // Use unsigned long to match ioctl's parameter type.
+    unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];  // NOLINT
+
+    // Read the evbits of the input device.
+    if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
+      continue;
+    }
+
+    // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. EV_ABS is also
+    // allowed if allow_touch_inputs is set.
+    if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
+      if (!allow_touch_inputs || !test_bit(EV_ABS, ev_bits)) {
         continue;
       }
+    }
 
-      // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. EV_ABS is also
-      // allowed if allow_touch_inputs is set.
-      if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
-        if (!allow_touch_inputs || !test_bit(EV_ABS, ev_bits)) {
-          close(fd);
-          continue;
-        }
-      }
-
-      epoll_event ev;
-      ev.events = EPOLLIN | EPOLLWAKEUP;
-      ev.data.ptr = &ev_fdinfo[ev_count];
-      if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
-        close(fd);
-        epollctlfail = true;
-        continue;
-      }
-
+<<<<<<< HEAD
       ev_fdinfo[ev_count].fd = fd;
       ev_fdinfo[ev_count].cb = std::move(input_cb);
 #ifdef TW_USE_MINUI_WITH_DATA
@@ -117,38 +123,55 @@
       ev_count++;
       ev_dev_count++;
       if (ev_dev_count == MAX_DEVICES) break;
+=======
+    epoll_event ev;
+    ev.events = EPOLLIN | EPOLLWAKEUP;
+    ev.data.ptr = &ev_fdinfo[g_ev_count];
+    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+      epoll_ctl_failed = true;
+      continue;
+>>>>>>> android-10.0.0_r25
     }
 
-    closedir(dir);
+    ev_fdinfo[g_ev_count].fd.reset(fd.release());
+    ev_fdinfo[g_ev_count].cb = input_cb;
+    g_ev_count++;
+    g_ev_dev_count++;
+    if (g_ev_dev_count == MAX_DEVICES) break;
   }
 
-  if (epollctlfail && !ev_count) {
-    close(g_epoll_fd);
-    g_epoll_fd = -1;
+  if (epoll_ctl_failed && !g_ev_count) {
     return -1;
   }
 
+  g_epoll_fd.reset(epoll_fd.release());
   return 0;
 }
 
 int ev_get_epollfd(void) {
-    return g_epoll_fd;
+  return g_epoll_fd.get();
 }
 
+<<<<<<< HEAD
 #ifdef TW_USE_MINUI_WITH_DATA
 int ev_add_fd(int fd, ev_callback cb, void* data) {
 #else
 int ev_add_fd(int fd, ev_callback cb) {
 #endif
   if (ev_misc_count == MAX_MISC_FDS || cb == NULL) {
+=======
+int ev_add_fd(android::base::unique_fd&& fd, ev_callback cb) {
+  if (g_ev_misc_count == MAX_MISC_FDS || cb == nullptr) {
+>>>>>>> android-10.0.0_r25
     return -1;
   }
 
   epoll_event ev;
   ev.events = EPOLLIN | EPOLLWAKEUP;
-  ev.data.ptr = static_cast<void*>(&ev_fdinfo[ev_count]);
+  ev.data.ptr = static_cast<void*>(&ev_fdinfo[g_ev_count]);
   int ret = epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
   if (!ret) {
+<<<<<<< HEAD
     ev_fdinfo[ev_count].fd = fd;
     ev_fdinfo[ev_count].cb = std::move(cb);
 #ifdef TW_USE_MINUI_WITH_DATA
@@ -156,38 +179,48 @@
 #endif
     ev_count++;
     ev_misc_count++;
+=======
+    ev_fdinfo[g_ev_count].fd.reset(fd.release());
+    ev_fdinfo[g_ev_count].cb = std::move(cb);
+    g_ev_count++;
+    g_ev_misc_count++;
+>>>>>>> android-10.0.0_r25
   }
 
   return ret;
 }
 
 void ev_exit(void) {
-    while (ev_count > 0) {
-        close(ev_fdinfo[--ev_count].fd);
-    }
-    ev_misc_count = 0;
-    ev_dev_count = 0;
-    close(g_epoll_fd);
+  while (g_ev_count > 0) {
+    ev_fdinfo[--g_ev_count].fd.reset();
+  }
+  g_ev_misc_count = 0;
+  g_ev_dev_count = 0;
+  g_epoll_fd.reset();
 }
 
 int ev_wait(int timeout) {
-    npolledevents = epoll_wait(g_epoll_fd, polledevents, ev_count, timeout);
-    if (npolledevents <= 0) {
-        return -1;
-    }
-    return 0;
+  g_polled_events_count = epoll_wait(g_epoll_fd, g_polled_events, g_ev_count, timeout);
+  if (g_polled_events_count <= 0) {
+    return -1;
+  }
+  return 0;
 }
 
 void ev_dispatch(void) {
-  for (int n = 0; n < npolledevents; n++) {
-    fd_info* fdi = static_cast<fd_info*>(polledevents[n].data.ptr);
+  for (int n = 0; n < g_polled_events_count; n++) {
+    FdInfo* fdi = static_cast<FdInfo*>(g_polled_events[n].data.ptr);
     const ev_callback& cb = fdi->cb;
     if (cb) {
+<<<<<<< HEAD
 #ifdef TW_USE_MINUI_WITH_DATA
       cb(fdi->fd, polledevents[n].events, fdi->data);
 #else
       cb(fdi->fd, polledevents[n].events);
 #endif
+=======
+      cb(fdi->fd, g_polled_events[n].events);
+>>>>>>> android-10.0.0_r25
     }
   }
 }
@@ -211,7 +244,7 @@
   unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];    // NOLINT
   unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];  // NOLINT
 
-  for (size_t i = 0; i < ev_dev_count; ++i) {
+  for (size_t i = 0; i < g_ev_dev_count; ++i) {
     memset(ev_bits, 0, sizeof(ev_bits));
     memset(key_bits, 0, sizeof(key_bits));
 
@@ -240,38 +273,37 @@
 }
 
 void ev_iterate_available_keys(const std::function<void(int)>& f) {
-    // Use unsigned long to match ioctl's parameter type.
-    unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
-    unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; // NOLINT
+  // Use unsigned long to match ioctl's parameter type.
+  unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];    // NOLINT
+  unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];  // NOLINT
 
-    for (size_t i = 0; i < ev_dev_count; ++i) {
-        memset(ev_bits, 0, sizeof(ev_bits));
-        memset(key_bits, 0, sizeof(key_bits));
+  for (size_t i = 0; i < g_ev_dev_count; ++i) {
+    memset(ev_bits, 0, sizeof(ev_bits));
+    memset(key_bits, 0, sizeof(key_bits));
 
-        // Does this device even have keys?
-        if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
-            continue;
-        }
-        if (!test_bit(EV_KEY, ev_bits)) {
-            continue;
-        }
-
-        int rc = ioctl(ev_fdinfo[i].fd, EVIOCGBIT(EV_KEY, KEY_MAX), key_bits);
-        if (rc == -1) {
-            continue;
-        }
-
-        for (int key_code = 0; key_code <= KEY_MAX; ++key_code) {
-            if (test_bit(key_code, key_bits)) {
-                f(key_code);
-            }
-        }
+    // Does this device even have keys?
+    if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
+      continue;
     }
+    if (!test_bit(EV_KEY, ev_bits)) {
+      continue;
+    }
+
+    if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(EV_KEY, KEY_MAX), key_bits) == -1) {
+      continue;
+    }
+
+    for (int key_code = 0; key_code <= KEY_MAX; ++key_code) {
+      if (test_bit(key_code, key_bits)) {
+        f(key_code);
+      }
+    }
+  }
 }
 
 #ifdef TW_USE_MINUI_WITH_OPTIONAL_TOUCH_EVENTS
 void ev_iterate_touch_inputs(const std::function<void(int)>& action) {
-  for (size_t i = 0; i < ev_dev_count; ++i) {
+  for (size_t i = 0; i < g_ev_dev_count; ++i) {
     // Use unsigned long to match ioctl's parameter type.
     unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)] = {};  // NOLINT
     if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
diff --git a/minui/font_10x18.h b/minui/font_10x18.h
deleted file mode 100644
index 30dfb9c..0000000
--- a/minui/font_10x18.h
+++ /dev/null
@@ -1,214 +0,0 @@
-struct {
-  unsigned width;
-  unsigned height;
-  unsigned char_width;
-  unsigned char_height;
-  unsigned char rundata[2973];
-} font = {
-  .width = 960,
-  .height = 18,
-  .char_width = 10,
-  .char_height = 18,
-  .rundata = {
-0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x55,0x82,0x06,0x82,0x02,0x82,0x10,0x82,
-0x11,0x83,0x08,0x82,0x0a,0x82,0x04,0x82,0x46,0x82,0x08,0x82,0x07,0x84,0x06,
-0x84,0x0a,0x81,0x03,0x88,0x04,0x84,0x04,0x88,0x04,0x84,0x06,0x84,0x1e,0x81,
-0x0e,0x81,0x0a,0x84,0x06,0x84,0x07,0x82,0x05,0x85,0x07,0x84,0x04,0x86,0x04,
-0x88,0x02,0x88,0x04,0x84,0x04,0x82,0x04,0x82,0x02,0x88,0x05,0x86,0x01,0x82,
-0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x04,0x84,0x04,
-0x86,0x06,0x84,0x04,0x86,0x06,0x84,0x04,0x88,0x02,0x82,0x04,0x82,0x02,0x82,
-0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,
-0x88,0x03,0x86,0x0e,0x86,0x06,0x82,0x11,0x82,0x10,0x82,0x18,0x82,0x0f,0x84,
-0x0d,0x82,0x1c,0x82,0x09,0x84,0x7f,0x16,0x84,0x05,0x82,0x05,0x84,0x07,0x83,
-0x02,0x82,0x19,0x82,0x06,0x82,0x02,0x82,0x06,0x82,0x01,0x82,0x03,0x86,0x04,
-0x83,0x02,0x82,0x03,0x82,0x01,0x82,0x07,0x82,0x09,0x82,0x06,0x82,0x3e,0x82,
-0x04,0x84,0x06,0x83,0x06,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x03,
-0x82,0x09,0x82,0x02,0x82,0x09,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x02,0x82,
-0x1c,0x82,0x0e,0x82,0x08,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x05,0x84,0x04,
-0x82,0x02,0x82,0x05,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x82,
-0x09,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0a,0x82,0x03,0x82,0x04,
-0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x83,0x03,0x82,0x03,0x82,0x02,0x82,
-0x03,0x82,0x03,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x04,0x82,0x02,
-0x82,0x06,0x82,0x05,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,
-0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x08,0x82,0x03,0x82,0x08,0x82,0x0c,
-0x82,0x05,0x84,0x11,0x82,0x0f,0x82,0x18,0x82,0x0e,0x82,0x02,0x82,0x0c,0x82,
-0x1c,0x82,0x0b,0x82,0x7f,0x15,0x82,0x08,0x82,0x08,0x82,0x05,0x82,0x01,0x82,
-0x01,0x82,0x19,0x82,0x06,0x82,0x02,0x82,0x06,0x82,0x01,0x82,0x02,0x82,0x01,
-0x82,0x01,0x82,0x02,0x82,0x01,0x82,0x01,0x82,0x03,0x82,0x01,0x82,0x07,0x82,
-0x08,0x82,0x08,0x82,0x3d,0x82,0x03,0x82,0x02,0x82,0x04,0x84,0x05,0x82,0x04,
-0x82,0x02,0x82,0x04,0x82,0x06,0x83,0x03,0x82,0x08,0x82,0x04,0x81,0x09,0x82,
-0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x1a,0x82,0x10,0x82,0x06,0x82,0x04,
-0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x03,0x82,
-0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x04,0x82,0x02,
-0x82,0x04,0x82,0x05,0x82,0x0a,0x82,0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x83,
-0x02,0x83,0x02,0x83,0x03,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,
-0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,0x82,0x05,0x82,
-0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x04,
-0x82,0x02,0x82,0x09,0x82,0x03,0x82,0x08,0x82,0x0c,0x82,0x04,0x82,0x02,0x82,
-0x11,0x82,0x0e,0x82,0x18,0x82,0x0e,0x82,0x02,0x82,0x0c,0x82,0x0b,0x82,0x0b,
-0x82,0x02,0x82,0x0b,0x82,0x4d,0x82,0x45,0x82,0x08,0x82,0x08,0x82,0x05,0x82,
-0x02,0x83,0x1a,0x82,0x07,0x81,0x02,0x81,0x07,0x82,0x01,0x82,0x02,0x82,0x01,
-0x82,0x05,0x82,0x01,0x84,0x04,0x82,0x01,0x82,0x07,0x82,0x08,0x82,0x08,0x82,
-0x06,0x82,0x02,0x82,0x06,0x82,0x28,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x01,
-0x82,0x05,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,0x84,0x03,0x82,0x08,0x82,
-0x0d,0x82,0x03,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x19,0x82,0x12,0x82,0x05,
-0x82,0x04,0x82,0x02,0x82,0x02,0x84,0x03,0x82,0x02,0x82,0x03,0x82,0x03,0x82,
-0x03,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x08,0x82,0x04,
-0x82,0x05,0x82,0x0a,0x82,0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x83,0x02,0x83,
-0x02,0x84,0x02,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
-0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x0b,0x82,0x05,0x82,0x04,0x82,0x02,0x82,
-0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,
-0x82,0x04,0x82,0x09,0x82,0x0b,0x82,0x03,0x82,0x04,0x82,0x20,0x82,0x18,0x82,
-0x0e,0x82,0x10,0x82,0x0b,0x82,0x0b,0x82,0x02,0x82,0x0b,0x82,0x4d,0x82,0x45,
-0x82,0x08,0x82,0x08,0x82,0x26,0x82,0x10,0x88,0x01,0x82,0x01,0x82,0x06,0x83,
-0x01,0x82,0x04,0x84,0x08,0x81,0x08,0x82,0x0a,0x82,0x05,0x82,0x02,0x82,0x06,
-0x82,0x28,0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x08,0x82,0x04,0x82,
-0x01,0x82,0x03,0x82,0x08,0x82,0x0d,0x82,0x03,0x82,0x04,0x82,0x02,0x82,0x04,
-0x82,0x18,0x82,0x06,0x88,0x06,0x82,0x04,0x82,0x04,0x82,0x02,0x82,0x01,0x85,
-0x02,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x08,0x82,0x04,0x82,0x02,
-0x82,0x08,0x82,0x08,0x82,0x08,0x82,0x04,0x82,0x05,0x82,0x0a,0x82,0x03,0x82,
-0x02,0x82,0x04,0x82,0x08,0x88,0x02,0x84,0x02,0x82,0x02,0x82,0x04,0x82,0x02,
-0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x0b,0x82,
-0x05,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x04,0x84,0x06,
-0x84,0x08,0x82,0x05,0x82,0x09,0x82,0x0b,0x82,0x2b,0x82,0x18,0x82,0x0e,0x82,
-0x10,0x82,0x1c,0x82,0x0b,0x82,0x4d,0x82,0x45,0x82,0x08,0x82,0x08,0x82,0x26,
-0x82,0x11,0x82,0x01,0x82,0x03,0x82,0x01,0x82,0x09,0x82,0x06,0x82,0x12,0x82,
-0x0a,0x82,0x06,0x84,0x07,0x82,0x27,0x82,0x04,0x82,0x04,0x82,0x05,0x82,0x0b,
-0x82,0x07,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x01,0x83,0x04,0x82,0x01,0x83,
-0x08,0x82,0x05,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x05,0x83,0x07,0x83,0x05,
-0x82,0x16,0x82,0x08,0x82,0x03,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,
-0x02,0x82,0x02,0x82,0x04,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x08,
-0x82,0x08,0x82,0x04,0x82,0x05,0x82,0x0a,0x82,0x03,0x82,0x02,0x82,0x04,0x82,
-0x08,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,
-0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,
-0x0a,0x82,0x05,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x01,0x82,0x01,
-0x82,0x04,0x84,0x06,0x84,0x08,0x82,0x05,0x82,0x0a,0x82,0x0a,0x82,0x23,0x85,
-0x03,0x82,0x01,0x83,0x06,0x85,0x05,0x83,0x01,0x82,0x04,0x84,0x04,0x86,0x05,
-0x85,0x01,0x81,0x02,0x82,0x01,0x83,0x05,0x84,0x09,0x84,0x02,0x82,0x03,0x82,
-0x06,0x82,0x05,0x81,0x01,0x82,0x01,0x82,0x03,0x82,0x01,0x83,0x06,0x84,0x04,
-0x82,0x01,0x83,0x06,0x83,0x01,0x82,0x02,0x82,0x01,0x84,0x04,0x86,0x03,0x86,
-0x04,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
-0x82,0x02,0x82,0x04,0x82,0x03,0x87,0x05,0x82,0x08,0x82,0x08,0x82,0x26,0x82,
-0x11,0x82,0x01,0x82,0x04,0x86,0x07,0x82,0x05,0x83,0x12,0x82,0x0a,0x82,0x04,
-0x88,0x02,0x88,0x0c,0x88,0x10,0x82,0x04,0x82,0x04,0x82,0x05,0x82,0x0a,0x82,
-0x06,0x83,0x04,0x82,0x03,0x82,0x03,0x83,0x02,0x82,0x03,0x83,0x02,0x82,0x07,
-0x82,0x06,0x84,0x05,0x82,0x02,0x83,0x05,0x83,0x07,0x83,0x04,0x82,0x18,0x82,
-0x06,0x82,0x04,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x86,0x04,
-0x82,0x08,0x82,0x04,0x82,0x02,0x86,0x04,0x86,0x04,0x82,0x02,0x84,0x02,0x88,
-0x05,0x82,0x0a,0x82,0x03,0x85,0x05,0x82,0x08,0x82,0x01,0x82,0x01,0x82,0x02,
-0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x03,0x82,
-0x04,0x82,0x02,0x82,0x03,0x82,0x05,0x84,0x07,0x82,0x05,0x82,0x04,0x82,0x03,
-0x82,0x02,0x82,0x03,0x82,0x01,0x82,0x01,0x82,0x05,0x82,0x08,0x82,0x08,0x82,
-0x06,0x82,0x0a,0x82,0x0a,0x82,0x22,0x82,0x03,0x82,0x02,0x83,0x02,0x82,0x04,
-0x82,0x03,0x82,0x03,0x82,0x02,0x83,0x03,0x82,0x02,0x82,0x05,0x82,0x06,0x82,
-0x03,0x83,0x02,0x83,0x02,0x82,0x06,0x82,0x0b,0x82,0x02,0x82,0x02,0x82,0x07,
-0x82,0x05,0x88,0x02,0x83,0x02,0x82,0x04,0x82,0x02,0x82,0x03,0x83,0x02,0x82,
-0x04,0x82,0x02,0x83,0x03,0x83,0x02,0x82,0x02,0x82,0x04,0x82,0x04,0x82,0x06,
-0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,
-0x03,0x82,0x04,0x82,0x08,0x82,0x02,0x84,0x09,0x82,0x09,0x84,0x23,0x82,0x11,
-0x82,0x01,0x82,0x06,0x82,0x01,0x82,0x05,0x82,0x05,0x82,0x01,0x82,0x11,0x82,
-0x0a,0x82,0x06,0x84,0x07,0x82,0x26,0x82,0x05,0x82,0x04,0x82,0x05,0x82,0x08,
-0x83,0x09,0x82,0x03,0x82,0x03,0x82,0x09,0x82,0x02,0x82,0x04,0x82,0x05,0x82,
-0x06,0x82,0x02,0x82,0x05,0x83,0x01,0x82,0x17,0x82,0x16,0x82,0x06,0x82,0x05,
-0x82,0x01,0x82,0x01,0x82,0x02,0x88,0x02,0x82,0x03,0x82,0x03,0x82,0x08,0x82,
-0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,
-0x82,0x0a,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x08,0x82,0x01,0x82,0x01,0x82,
-0x02,0x82,0x02,0x84,0x02,0x82,0x04,0x82,0x02,0x86,0x04,0x82,0x04,0x82,0x02,
-0x86,0x09,0x82,0x06,0x82,0x05,0x82,0x04,0x82,0x04,0x84,0x04,0x82,0x01,0x82,
-0x01,0x82,0x04,0x84,0x07,0x82,0x07,0x82,0x07,0x82,0x0b,0x82,0x09,0x82,0x27,
-0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,
-0x04,0x82,0x06,0x82,0x03,0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,
-0x82,0x01,0x82,0x08,0x82,0x05,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,
-0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x07,
-0x82,0x0a,0x82,0x06,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x04,0x82,
-0x04,0x84,0x04,0x82,0x04,0x82,0x07,0x82,0x06,0x82,0x08,0x82,0x08,0x82,0x26,
-0x82,0x0f,0x88,0x05,0x82,0x01,0x82,0x05,0x82,0x05,0x82,0x02,0x82,0x01,0x82,
-0x0d,0x82,0x0a,0x82,0x05,0x82,0x02,0x82,0x06,0x82,0x26,0x82,0x05,0x82,0x04,
-0x82,0x05,0x82,0x07,0x82,0x0c,0x82,0x02,0x88,0x08,0x82,0x02,0x82,0x04,0x82,
-0x05,0x82,0x05,0x82,0x04,0x82,0x08,0x82,0x18,0x82,0x14,0x82,0x07,0x82,0x05,
-0x82,0x01,0x84,0x03,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,
-0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,
-0x82,0x0a,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x08,0x82,0x01,0x82,0x01,0x82,
-0x02,0x82,0x02,0x84,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,
-0x82,0x02,0x82,0x0a,0x82,0x05,0x82,0x05,0x82,0x04,0x82,0x04,0x84,0x04,0x82,
-0x01,0x82,0x01,0x82,0x04,0x84,0x07,0x82,0x07,0x82,0x07,0x82,0x0b,0x82,0x09,
-0x82,0x22,0x87,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x88,
-0x04,0x82,0x06,0x82,0x03,0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,
-0x84,0x09,0x82,0x05,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x82,
-0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x08,0x86,0x05,
-0x82,0x06,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x01,0x82,0x01,0x82,
-0x05,0x82,0x05,0x82,0x04,0x82,0x06,0x82,0x07,0x82,0x08,0x82,0x08,0x82,0x26,
-0x82,0x10,0x82,0x01,0x82,0x07,0x82,0x01,0x82,0x04,0x82,0x01,0x83,0x02,0x82,
-0x03,0x83,0x0f,0x82,0x08,0x82,0x06,0x82,0x02,0x82,0x06,0x82,0x25,0x82,0x07,
-0x82,0x02,0x82,0x06,0x82,0x06,0x82,0x07,0x82,0x04,0x82,0x07,0x82,0x09,0x82,
-0x02,0x82,0x04,0x82,0x04,0x82,0x06,0x82,0x04,0x82,0x08,0x82,0x19,0x82,0x05,
-0x88,0x05,0x82,0x08,0x82,0x05,0x82,0x02,0x82,0x04,0x82,0x04,0x82,0x02,0x82,
-0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x04,
-0x82,0x02,0x82,0x04,0x82,0x05,0x82,0x05,0x82,0x03,0x82,0x03,0x82,0x03,0x82,
-0x03,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x03,0x83,0x02,0x82,0x04,0x82,0x02,
-0x82,0x08,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x03,0x82,0x09,0x82,0x05,0x82,
-0x05,0x82,0x04,0x82,0x04,0x84,0x04,0x83,0x02,0x83,0x03,0x82,0x02,0x82,0x06,
-0x82,0x06,0x82,0x08,0x82,0x0c,0x82,0x08,0x82,0x21,0x82,0x04,0x82,0x02,0x82,
-0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x0a,0x82,0x06,0x82,0x03,
-0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,0x85,0x08,0x82,0x05,0x82,
-0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
-0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x0d,0x82,0x04,0x82,0x06,0x82,0x04,0x82,
-0x04,0x84,0x04,0x82,0x01,0x82,0x01,0x82,0x05,0x82,0x05,0x82,0x04,0x82,0x05,
-0x82,0x08,0x82,0x08,0x82,0x08,0x82,0x38,0x82,0x01,0x82,0x04,0x82,0x01,0x82,
-0x01,0x82,0x04,0x84,0x01,0x82,0x01,0x82,0x03,0x82,0x10,0x82,0x08,0x82,0x30,
-0x83,0x06,0x82,0x07,0x82,0x02,0x82,0x06,0x82,0x05,0x82,0x08,0x82,0x04,0x82,
-0x07,0x82,0x03,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x04,0x82,0x06,0x82,0x04,
-0x82,0x03,0x81,0x04,0x82,0x1a,0x82,0x10,0x82,0x10,0x82,0x08,0x82,0x04,0x82,
-0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,
-0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,0x82,0x05,0x82,0x03,0x82,
-0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x03,0x83,0x02,
-0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x02,0x84,0x02,0x82,0x03,0x82,0x03,0x82,
-0x04,0x82,0x05,0x82,0x05,0x82,0x04,0x82,0x05,0x82,0x05,0x83,0x02,0x83,0x03,
-0x82,0x02,0x82,0x06,0x82,0x05,0x82,0x09,0x82,0x0c,0x82,0x08,0x82,0x21,0x82,
-0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x0a,
-0x82,0x07,0x85,0x04,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,0x82,0x02,0x82,
-0x07,0x82,0x05,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
-0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x0d,0x82,0x04,0x82,
-0x06,0x82,0x04,0x82,0x04,0x84,0x04,0x82,0x01,0x82,0x01,0x82,0x04,0x84,0x04,
-0x82,0x04,0x82,0x04,0x82,0x09,0x82,0x08,0x82,0x08,0x82,0x26,0x82,0x10,0x82,
-0x01,0x82,0x05,0x86,0x04,0x82,0x01,0x82,0x01,0x82,0x01,0x83,0x01,0x84,0x10,
-0x82,0x06,0x82,0x1d,0x83,0x11,0x83,0x05,0x82,0x09,0x84,0x07,0x82,0x05,0x82,
-0x09,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
-0x82,0x08,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x06,0x83,0x07,0x83,0x09,0x82,
-0x0e,0x82,0x0a,0x82,0x06,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x03,
-0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x82,0x09,0x82,
-0x02,0x83,0x02,0x82,0x04,0x82,0x05,0x82,0x06,0x82,0x01,0x82,0x04,0x82,0x04,
-0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,
-0x03,0x82,0x09,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x06,
-0x82,0x06,0x82,0x02,0x82,0x06,0x82,0x05,0x82,0x04,0x82,0x02,0x82,0x04,0x82,
-0x05,0x82,0x05,0x82,0x09,0x82,0x0d,0x82,0x07,0x82,0x21,0x82,0x04,0x82,0x02,
-0x83,0x02,0x82,0x04,0x82,0x03,0x82,0x03,0x82,0x02,0x83,0x03,0x82,0x03,0x82,
-0x04,0x82,0x06,0x82,0x08,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,0x82,0x03,
-0x82,0x06,0x82,0x05,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x03,0x82,
-0x02,0x82,0x03,0x83,0x02,0x82,0x04,0x82,0x02,0x83,0x03,0x82,0x07,0x82,0x04,
-0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x02,0x83,0x05,0x82,0x05,0x88,0x03,0x82,
-0x02,0x82,0x04,0x82,0x02,0x83,0x03,0x82,0x0a,0x82,0x08,0x82,0x08,0x82,0x26,
-0x82,0x1c,0x82,0x06,0x82,0x02,0x83,0x03,0x84,0x02,0x82,0x10,0x82,0x04,0x82,
-0x1e,0x83,0x11,0x83,0x05,0x82,0x0a,0x82,0x05,0x88,0x02,0x88,0x04,0x84,0x09,
-0x82,0x05,0x84,0x06,0x84,0x05,0x82,0x09,0x84,0x06,0x84,0x07,0x83,0x07,0x83,
-0x0a,0x81,0x0e,0x81,0x0b,0x82,0x07,0x85,0x03,0x82,0x04,0x82,0x02,0x86,0x06,
-0x84,0x04,0x86,0x04,0x88,0x02,0x82,0x0a,0x84,0x01,0x81,0x02,0x82,0x04,0x82,
-0x02,0x88,0x04,0x83,0x05,0x82,0x04,0x82,0x02,0x88,0x02,0x82,0x04,0x82,0x02,
-0x82,0x04,0x82,0x04,0x84,0x04,0x82,0x0a,0x85,0x03,0x82,0x04,0x82,0x04,0x84,
-0x07,0x82,0x07,0x84,0x07,0x82,0x05,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,
-0x82,0x05,0x88,0x03,0x86,0x09,0x82,0x03,0x86,0x22,0x85,0x01,0x81,0x02,0x82,
-0x01,0x83,0x06,0x85,0x05,0x83,0x01,0x82,0x04,0x85,0x05,0x82,0x07,0x86,0x03,
-0x82,0x04,0x82,0x02,0x88,0x08,0x82,0x02,0x82,0x04,0x82,0x02,0x88,0x02,0x82,
-0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x04,0x84,0x04,0x82,0x01,0x83,0x06,
-0x83,0x01,0x82,0x03,0x82,0x08,0x86,0x06,0x84,0x05,0x83,0x01,0x82,0x05,0x82,
-0x06,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x04,0x83,0x01,0x82,0x03,0x87,0x06,
-0x84,0x05,0x82,0x05,0x84,0x7f,0x15,0x83,0x7f,0x14,0x83,0x7f,0x5e,0x82,0x7f,
-0x05,0x89,0x47,0x82,0x04,0x82,0x17,0x82,0x03,0x82,0x34,0x82,0x0e,0x82,0x4e,
-0x82,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x0a,0x82,0x04,0x82,0x17,0x82,0x03,0x82,
-0x34,0x82,0x0e,0x82,0x48,0x82,0x04,0x82,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x0a,
-0x82,0x04,0x82,0x17,0x82,0x03,0x82,0x34,0x82,0x0e,0x82,0x49,0x82,0x02,0x82,
-0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x0c,0x86,0x19,0x85,0x35,0x82,0x0e,0x82,0x4a,
-0x84,0x3f,
-0x00,
-  }
-};
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index f3380aa..744cceb 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -23,6 +23,7 @@
 
 #include <memory>
 
+<<<<<<< HEAD
 #ifdef BOARD_USE_CUSTOM_RECOVERY_FONT
 #include BOARD_USE_CUSTOM_RECOVERY_FONT
 #else
@@ -30,6 +31,10 @@
 #endif
 
 #ifndef MSM_BSP
+=======
+#include <android-base/properties.h>
+
+>>>>>>> android-10.0.0_r25
 #include "graphics_adf.h"
 #endif
 #include "graphics_drm.h"
@@ -37,10 +42,9 @@
 #include "graphics_overlay.h"
 #include "minui/minui.h"
 
-static GRFont* gr_font = NULL;
+static GRFont* gr_font = nullptr;
 static MinuiBackend* gr_backend = nullptr;
 
-static int overscan_percent = OVERSCAN_PERCENT;
 static int overscan_offset_x = 0;
 static int overscan_offset_y = 0;
 
@@ -58,12 +62,15 @@
 static uint32_t gr_current = ~0;
 static constexpr uint32_t alpha_mask = 0xff000000;
 
-static GRSurface* gr_draw = NULL;
-static GRRotation rotation = ROTATION_NONE;
+// gr_draw is owned by backends.
+static GRSurface* gr_draw = nullptr;
+static GRRotation rotation = GRRotation::NONE;
+static PixelFormat pixel_format = PixelFormat::UNKNOWN;
 
 static bool outside(int x, int y) {
-  return x < 0 || x >= (rotation % 2 ? gr_draw->height : gr_draw->width) || y < 0 ||
-         y >= (rotation % 2 ? gr_draw->width : gr_draw->height);
+  auto swapped = (rotation == GRRotation::LEFT || rotation == GRRotation::RIGHT);
+  return x < 0 || x >= (swapped ? gr_draw->height : gr_draw->width) || y < 0 ||
+         y >= (swapped ? gr_draw->width : gr_draw->height);
 }
 
 #ifdef TW_NO_MINUI_CUSTOM_FONTS
@@ -82,13 +89,26 @@
   return gr_font;
 }
 
+PixelFormat gr_pixel_format() {
+  return pixel_format;
+}
+
 int gr_measure(const GRFont* font, const char* s) {
+  if (font == nullptr) {
+    return -1;
+  }
+
   return font->char_width * strlen(s);
 }
 
-void gr_font_size(const GRFont* font, int* x, int* y) {
+int gr_font_size(const GRFont* font, int* x, int* y) {
+  if (font == nullptr) {
+    return -1;
+  }
+
   *x = font->char_width;
   *y = font->char_height;
+  return 0;
 }
 #endif // TW_NO_MINUI_CUSTOM_FONTS
 
@@ -202,6 +222,7 @@
   return (out_r & 0xff) | (out_g & 0xff00) | (out_b & 0xff0000) | (gr_current & 0xff000000);
 }
 
+<<<<<<< HEAD
 // increments pixel pointer right, with current rotation.
 static void incr_x16(uint16_t** p, int row_pixels) {
   if (rotation % 2) {
@@ -221,23 +242,35 @@
 }
 
 // increments pixel pointer right, with current rotation.
+=======
+// Increments pixel pointer right, with current rotation.
+>>>>>>> android-10.0.0_r25
 static void incr_x(uint32_t** p, int row_pixels) {
-  if (rotation % 2) {
-    *p = *p + (rotation == 1 ? 1 : -1) * row_pixels;
-  } else {
-    *p = *p + (rotation ? -1 : 1);
+  if (rotation == GRRotation::LEFT) {
+    *p = *p - row_pixels;
+  } else if (rotation == GRRotation::RIGHT) {
+    *p = *p + row_pixels;
+  } else if (rotation == GRRotation::DOWN) {
+    *p = *p - 1;
+  } else {  // GRRotation::NONE
+    *p = *p + 1;
   }
 }
 
-// increments pixel pointer down, with current rotation.
+// Increments pixel pointer down, with current rotation.
 static void incr_y(uint32_t** p, int row_pixels) {
-  if (rotation % 2) {
-    *p = *p + (rotation == 1 ? -1 : 1);
-  } else {
-    *p = *p + (rotation ? -1 : 1) * row_pixels;
+  if (rotation == GRRotation::LEFT) {
+    *p = *p + 1;
+  } else if (rotation == GRRotation::RIGHT) {
+    *p = *p - 1;
+  } else if (rotation == GRRotation::DOWN) {
+    *p = *p - row_pixels;
+  } else {  // GRRotation::NONE
+    *p = *p + row_pixels;
   }
 }
 
+<<<<<<< HEAD
 // returns pixel pointer at given coordinates with rotation adjustment.
 static uint16_t* pixel_at16(GRSurface* surf, int x, int y, int row_pixels) {
   switch (rotation) {
@@ -258,22 +291,28 @@
 
 // returns pixel pointer at given coordinates with rotation adjustment.
 static uint32_t* pixel_at(GRSurface* surf, int x, int y, int row_pixels) {
+=======
+// Returns pixel pointer at given coordinates with rotation adjustment.
+static uint32_t* PixelAt(GRSurface* surface, int x, int y, int row_pixels) {
+>>>>>>> android-10.0.0_r25
   switch (rotation) {
-    case ROTATION_NONE:
-      return reinterpret_cast<uint32_t*>(surf->data) + y * row_pixels + x;
-    case ROTATION_RIGHT:
-      return reinterpret_cast<uint32_t*>(surf->data) + x * row_pixels + (surf->width - y);
-    case ROTATION_DOWN:
-      return reinterpret_cast<uint32_t*>(surf->data) + (surf->height - 1 - y) * row_pixels +
-             (surf->width - 1 - x);
-    case ROTATION_LEFT:
-      return reinterpret_cast<uint32_t*>(surf->data) + (surf->height - 1 - x) * row_pixels + y;
+    case GRRotation::NONE:
+      return reinterpret_cast<uint32_t*>(surface->data()) + y * row_pixels + x;
+    case GRRotation::RIGHT:
+      return reinterpret_cast<uint32_t*>(surface->data()) + x * row_pixels + (surface->width - y);
+    case GRRotation::DOWN:
+      return reinterpret_cast<uint32_t*>(surface->data()) + (surface->height - 1 - y) * row_pixels +
+             (surface->width - 1 - x);
+    case GRRotation::LEFT:
+      return reinterpret_cast<uint32_t*>(surface->data()) + (surface->height - 1 - x) * row_pixels +
+             y;
     default:
-      printf("invalid rotation %d", rotation);
+      printf("invalid rotation %d", static_cast<int>(rotation));
   }
   return nullptr;
 }
 
+<<<<<<< HEAD
 static void text_blend16(uint8_t* src_p, int src_row_bytes, uint16_t* dst_p, int dst_row_pixels,
                        int width, int height) {
   uint8_t alpha_current = static_cast<uint8_t>((alpha_mask & gr_current) >> 24);
@@ -292,9 +331,13 @@
 
 static void text_blend(uint8_t* src_p, int src_row_bytes, uint32_t* dst_p, int dst_row_pixels,
                        int width, int height) {
+=======
+static void TextBlend(const uint8_t* src_p, int src_row_bytes, uint32_t* dst_p, int dst_row_pixels,
+                      int width, int height) {
+>>>>>>> android-10.0.0_r25
   uint8_t alpha_current = static_cast<uint8_t>((alpha_mask & gr_current) >> 24);
   for (int j = 0; j < height; ++j) {
-    uint8_t* sx = src_p;
+    const uint8_t* sx = src_p;
     uint32_t* px = dst_p;
     for (int i = 0; i < width; ++i, incr_x(&px, dst_row_pixels)) {
       uint8_t a = *sx++;
@@ -361,6 +404,7 @@
     }
 
     int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
+<<<<<<< HEAD
 
     uint8_t* src_p = font->texture->data + ((ch - ' ') * font->char_width) +
                      (bold ? font->char_height * font->texture->row_bytes : 0);
@@ -375,13 +419,22 @@
     text_blend(src_p, font->texture->row_bytes, dst_p, row_pixels, font->char_width,
                font->char_height);
     }
+=======
+    const uint8_t* src_p = font->texture->data() + ((ch - ' ') * font->char_width) +
+                           (bold ? font->char_height * font->texture->row_bytes : 0);
+    uint32_t* dst_p = PixelAt(gr_draw, x, y, row_pixels);
+
+    TextBlend(src_p, font->texture->row_bytes, dst_p, row_pixels, font->char_width,
+              font->char_height);
+
+>>>>>>> android-10.0.0_r25
     x += font->char_width;
   }
 }
 #endif //TW_NO_MINUI_CUSTOM_FONTS
 
-void gr_texticon(int x, int y, GRSurface* icon) {
-  if (icon == NULL) return;
+void gr_texticon(int x, int y, const GRSurface* icon) {
+  if (icon == nullptr) return;
 
   if (icon->pixel_bytes != 1) {
     printf("gr_texticon: source has wrong format\n");
@@ -394,6 +447,7 @@
   if (outside(x, y) || outside(x + icon->width - 1, y + icon->height - 1)) return;
 
   int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
+<<<<<<< HEAD
   uint8_t* src_p = icon->data;
   if (gr_draw->pixel_bytes == 2) {
 	uint16_t* dst_p = pixel_at16(gr_draw, x, y, row_pixels);
@@ -404,6 +458,11 @@
   uint32_t* dst_p = pixel_at(gr_draw, x, y, row_pixels);
 
   text_blend(src_p, icon->row_bytes, dst_p, row_pixels, icon->width, icon->height);
+=======
+  const uint8_t* src_p = icon->data();
+  uint32_t* dst_p = PixelAt(gr_draw, x, y, row_pixels);
+  TextBlend(src_p, icon->row_bytes, dst_p, row_pixels, icon->width, icon->height);
+>>>>>>> android-10.0.0_r25
 }
 
 void gr_convert_rgb_555(unsigned char r, unsigned char g, unsigned char b)
@@ -436,11 +495,11 @@
   }
 
   uint32_t r32 = r, g32 = g, b32 = b, a32 = a;
-#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
-  gr_current = (a32 << 24) | (r32 << 16) | (g32 << 8) | b32;
-#else
-  gr_current = (a32 << 24) | (b32 << 16) | (g32 << 8) | r32;
-#endif
+  if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) {
+    gr_current = (a32 << 24) | (r32 << 16) | (g32 << 8) | b32;
+  } else {
+    gr_current = (a32 << 24) | (b32 << 16) | (g32 << 8) | r32;
+  }
 }
 
 void gr_clear() {
@@ -454,9 +513,9 @@
       (gr_current & 0xff) == ((gr_current >> 16) & 0xff) &&
       (gr_current & 0xff) == ((gr_current >> 24) & 0xff) &&
       gr_draw->row_bytes == gr_draw->width * gr_draw->pixel_bytes) {
-    memset(gr_draw->data, gr_current & 0xff, gr_draw->height * gr_draw->row_bytes);
+    memset(gr_draw->data(), gr_current & 0xff, gr_draw->height * gr_draw->row_bytes);
   } else {
-    uint32_t* px = reinterpret_cast<uint32_t*>(gr_draw->data);
+    uint32_t* px = reinterpret_cast<uint32_t*>(gr_draw->data());
     int row_diff = gr_draw->row_bytes / gr_draw->pixel_bytes - gr_draw->width;
     for (int y = 0; y < gr_draw->height; ++y) {
       for (int x = 0; x < gr_draw->width; ++x) {
@@ -477,6 +536,7 @@
   if (outside(x1, y1) || outside(x2 - 1, y2 - 1)) return;
 
   int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
+<<<<<<< HEAD
   if (gr_draw->pixel_bytes == 2) {
 	uint16_t* p = pixel_at16(gr_draw, x1, y1, row_pixels);
     uint8_t alpha = static_cast<uint8_t>(((gr_current & alpha_mask) >> 24));
@@ -494,6 +554,9 @@
   }
   { // open brace to maintain separation between uint16_t p and uint32_t p
   uint32_t* p = pixel_at(gr_draw, x1, y1, row_pixels);
+=======
+  uint32_t* p = PixelAt(gr_draw, x1, y1, row_pixels);
+>>>>>>> android-10.0.0_r25
   uint8_t alpha = static_cast<uint8_t>(((gr_current & alpha_mask) >> 24));
   if (alpha > 0) {
     for (int y = y1; y < y2; ++y) {
@@ -550,8 +613,8 @@
   }
 }
 
-void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) {
-  if (source == NULL) return;
+void gr_blit(const GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) {
+  if (source == nullptr) return;
 
   if (gr_draw->pixel_bytes != source->pixel_bytes) {
     if (gr_draw->pixel_bytes == 2 && source->pixel_bytes == 4) {
@@ -568,14 +631,15 @@
 
   if (outside(dx, dy) || outside(dx + w - 1, dy + h - 1)) return;
 
-  if (rotation) {
+  if (rotation != GRRotation::NONE) {
     int src_row_pixels = source->row_bytes / source->pixel_bytes;
     int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
-    uint32_t* src_py = reinterpret_cast<uint32_t*>(source->data) + sy * source->row_bytes / 4 + sx;
-    uint32_t* dst_py = pixel_at(gr_draw, dx, dy, row_pixels);
+    const uint32_t* src_py =
+        reinterpret_cast<const uint32_t*>(source->data()) + sy * source->row_bytes / 4 + sx;
+    uint32_t* dst_py = PixelAt(gr_draw, dx, dy, row_pixels);
 
     for (int y = 0; y < h; y += 1) {
-      uint32_t* src_px = src_py;
+      const uint32_t* src_px = src_py;
       uint32_t* dst_px = dst_py;
       for (int x = 0; x < w; x += 1) {
         *dst_px = *src_px++;
@@ -585,11 +649,10 @@
       incr_y(&dst_py, row_pixels);
     }
   } else {
-    unsigned char* src_p = source->data + sy * source->row_bytes + sx * source->pixel_bytes;
-    unsigned char* dst_p = gr_draw->data + dy * gr_draw->row_bytes + dx * gr_draw->pixel_bytes;
+    const uint8_t* src_p = source->data() + sy * source->row_bytes + sx * source->pixel_bytes;
+    uint8_t* dst_p = gr_draw->data() + dy * gr_draw->row_bytes + dx * gr_draw->pixel_bytes;
 
-    int i;
-    for (i = 0; i < h; ++i) {
+    for (int i = 0; i < h; ++i) {
       memcpy(dst_p, src_p, w * source->pixel_bytes);
       src_p += source->row_bytes;
       dst_p += gr_draw->row_bytes;
@@ -597,15 +660,15 @@
   }
 }
 
-unsigned int gr_get_width(GRSurface* surface) {
-  if (surface == NULL) {
+unsigned int gr_get_width(const GRSurface* surface) {
+  if (surface == nullptr) {
     return 0;
   }
   return surface->width;
 }
 
-unsigned int gr_get_height(GRSurface* surface) {
-  if (surface == NULL) {
+unsigned int gr_get_height(const GRSurface* surface) {
+  if (surface == nullptr) {
     return 0;
   }
   return surface->height;
@@ -677,6 +740,7 @@
   return 0;
 }
 
+<<<<<<< HEAD
 static void gr_init_font(void) {
   int res = gr_init_font("font", &gr_font);
   if (res == 0) {
@@ -708,13 +772,36 @@
 }
 #endif // TW_NO_MINUI_CUSTOM_FONTS
 
+=======
+>>>>>>> android-10.0.0_r25
 void gr_flip() {
   gr_draw = gr_backend->Flip();
 }
 
+<<<<<<< HEAD
 int gr_init(void)
 {
   gr_init_font();
+=======
+int gr_init() {
+  // pixel_format needs to be set before loading any resources or initializing backends.
+  std::string format = android::base::GetProperty("ro.minui.pixel_format", "");
+  if (format == "ABGR_8888") {
+    pixel_format = PixelFormat::ABGR;
+  } else if (format == "RGBX_8888") {
+    pixel_format = PixelFormat::RGBX;
+  } else if (format == "BGRA_8888") {
+    pixel_format = PixelFormat::BGRA;
+  } else {
+    pixel_format = PixelFormat::UNKNOWN;
+  }
+
+  int ret = gr_init_font("font", &gr_font);
+  if (ret != 0) {
+    printf("Failed to init font: %d, continuing graphic backend initialization without font file\n",
+           ret);
+  }
+>>>>>>> android-10.0.0_r25
 
   auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendOverlay>() };
   gr_draw = backend->Init();
@@ -756,13 +843,28 @@
 
   gr_backend = backend.release();
 
+  int overscan_percent = android::base::GetIntProperty("ro.minui.overscan_percent", 0);
   overscan_offset_x = gr_draw->width * overscan_percent / 100;
   overscan_offset_y = gr_draw->height * overscan_percent / 100;
 
   gr_flip();
   gr_flip();
+  if (!gr_draw) {
+    printf("gr_init: gr_draw becomes nullptr after gr_flip\n");
+    return -1;
+  }
 
-  gr_rotate(DEFAULT_ROTATION);
+  std::string rotation_str =
+      android::base::GetProperty("ro.minui.default_rotation", "ROTATION_NONE");
+  if (rotation_str == "ROTATION_RIGHT") {
+    gr_rotate(GRRotation::RIGHT);
+  } else if (rotation_str == "ROTATION_DOWN") {
+    gr_rotate(GRRotation::DOWN);
+  } else if (rotation_str == "ROTATION_LEFT") {
+    gr_rotate(GRRotation::LEFT);
+  } else {  // "ROTATION_NONE" or unknown string
+    gr_rotate(GRRotation::NONE);
+  }
 
   if (gr_draw->pixel_bytes != 4) {
     printf("gr_init: Only 4-byte pixel formats supported\n");
@@ -773,16 +875,22 @@
 
 void gr_exit() {
   delete gr_backend;
+  gr_backend = nullptr;
+
+  delete gr_font;
+  gr_font = nullptr;
 }
 
 int gr_fb_width() {
-  return rotation % 2 ? gr_draw->height - 2 * overscan_offset_y
-                      : gr_draw->width - 2 * overscan_offset_x;
+  return (rotation == GRRotation::LEFT || rotation == GRRotation::RIGHT)
+             ? gr_draw->height - 2 * overscan_offset_y
+             : gr_draw->width - 2 * overscan_offset_x;
 }
 
 int gr_fb_height() {
-  return rotation % 2 ? gr_draw->width - 2 * overscan_offset_x
-                      : gr_draw->height - 2 * overscan_offset_y;
+  return (rotation == GRRotation::LEFT || rotation == GRRotation::RIGHT)
+             ? gr_draw->width - 2 * overscan_offset_x
+             : gr_draw->height - 2 * overscan_offset_y;
 }
 
 void gr_fb_blank(bool blank) {
diff --git a/minui/graphics_adf.cpp b/minui/graphics_adf.cpp
index 72b563b..df72e85 100644
--- a/minui/graphics_adf.cpp
+++ b/minui/graphics_adf.cpp
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
@@ -30,51 +31,60 @@
 
 #include "minui/minui.h"
 
-MinuiBackendAdf::MinuiBackendAdf()
-    : intf_fd(-1), dev(), current_surface(0), n_surfaces(0), surfaces() {}
-
-int MinuiBackendAdf::SurfaceInit(const drm_mode_modeinfo* mode, GRSurfaceAdf* surf) {
-  *surf = {};
-  surf->fence_fd = -1;
-  surf->fd = adf_interface_simple_buffer_alloc(intf_fd, mode->hdisplay, mode->vdisplay, format,
-                                               &surf->offset, &surf->pitch);
-  if (surf->fd < 0) {
-    return surf->fd;
+GRSurfaceAdf::~GRSurfaceAdf() {
+  if (mmapped_buffer_) {
+    munmap(mmapped_buffer_, pitch * height);
   }
-
-  surf->width = mode->hdisplay;
-  surf->height = mode->vdisplay;
-  surf->row_bytes = surf->pitch;
-  surf->pixel_bytes = (format == DRM_FORMAT_RGB565) ? 2 : 4;
-
-  surf->data = static_cast<uint8_t*>(
-      mmap(nullptr, surf->pitch * surf->height, PROT_WRITE, MAP_SHARED, surf->fd, surf->offset));
-  if (surf->data == MAP_FAILED) {
-    int saved_errno = errno;
-    close(surf->fd);
-    return -saved_errno;
+  if (fence_fd != -1) {
+    close(fence_fd);
   }
-
-  return 0;
+  if (fd != -1) {
+    close(fd);
+  }
 }
 
+std::unique_ptr<GRSurfaceAdf> GRSurfaceAdf::Create(int intf_fd, const drm_mode_modeinfo* mode,
+                                                   __u32 format, int* err) {
+  __u32 offset;
+  __u32 pitch;
+  auto fd = adf_interface_simple_buffer_alloc(intf_fd, mode->hdisplay, mode->vdisplay, format,
+                                              &offset, &pitch);
+
+  if (fd < 0) {
+    *err = fd;
+    return nullptr;
+  }
+
+  std::unique_ptr<GRSurfaceAdf> surf = std::unique_ptr<GRSurfaceAdf>(
+      new GRSurfaceAdf(mode->hdisplay, mode->vdisplay, pitch, (format == DRM_FORMAT_RGB565 ? 2 : 4),
+                       offset, pitch, fd));
+
+  auto mmapped =
+      mmap(nullptr, surf->pitch * surf->height, PROT_WRITE, MAP_SHARED, surf->fd, surf->offset);
+  if (mmapped == MAP_FAILED) {
+    *err = -errno;
+    return nullptr;
+  }
+  surf->mmapped_buffer_ = static_cast<uint8_t*>(mmapped);
+  return surf;
+}
+
+MinuiBackendAdf::MinuiBackendAdf() : intf_fd(-1), dev(), current_surface(0), n_surfaces(0) {}
+
 int MinuiBackendAdf::InterfaceInit() {
   adf_interface_data intf_data;
-  int err = adf_get_interface_data(intf_fd, &intf_data);
-  if (err < 0) return err;
+  if (int err = adf_get_interface_data(intf_fd, &intf_data); err < 0) return err;
 
-  int ret = 0;
-  err = SurfaceInit(&intf_data.current_mode, &surfaces[0]);
-  if (err < 0) {
-    fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err));
-    ret = err;
+  int result = 0;
+  surfaces[0] = GRSurfaceAdf::Create(intf_fd, &intf_data.current_mode, format, &result);
+  if (!surfaces[0]) {
+    fprintf(stderr, "Failed to allocate surface 0: %s\n", strerror(-result));
     goto done;
   }
 
-  err = SurfaceInit(&intf_data.current_mode, &surfaces[1]);
-  if (err < 0) {
-    fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err));
-    surfaces[1] = {};
+  surfaces[1] = GRSurfaceAdf::Create(intf_fd, &intf_data.current_mode, format, &result);
+  if (!surfaces[1]) {
+    fprintf(stderr, "Failed to allocate surface 1: %s\n", strerror(-result));
     n_surfaces = 1;
   } else {
     n_surfaces = 2;
@@ -82,7 +92,7 @@
 
 done:
   adf_free_interface_data(&intf_data);
-  return ret;
+  return result;
 }
 
 int MinuiBackendAdf::DeviceInit(adf_device* dev) {
@@ -93,7 +103,7 @@
   err = adf_device_attach(dev, eng_id, intf_id);
   if (err < 0 && err != -EALREADY) return err;
 
-  intf_fd = adf_interface_open(dev, intf_id, O_RDWR);
+  intf_fd = adf_interface_open(dev, intf_id, O_RDWR | O_CLOEXEC);
   if (intf_fd < 0) return intf_fd;
 
   err = InterfaceInit();
@@ -106,6 +116,7 @@
 }
 
 GRSurface* MinuiBackendAdf::Init() {
+<<<<<<< HEAD
 #if defined(RECOVERY_ABGR)
   format = DRM_FORMAT_ABGR8888;
 #elif defined(RECOVERY_BGRA)
@@ -117,6 +128,18 @@
 #else
   format = DRM_FORMAT_RGB565;
 #endif
+=======
+  PixelFormat pixel_format = gr_pixel_format();
+  if (pixel_format == PixelFormat::ABGR) {
+    format = DRM_FORMAT_ABGR8888;
+  } else if (pixel_format == PixelFormat::BGRA) {
+    format = DRM_FORMAT_BGRA8888;
+  } else if (pixel_format == PixelFormat::RGBX) {
+    format = DRM_FORMAT_RGBX8888;
+  } else {
+    format = DRM_FORMAT_RGB565;
+  }
+>>>>>>> android-10.0.0_r25
 
   adf_id_t* dev_ids = nullptr;
   ssize_t n_dev_ids = adf_devices(&dev_ids);
@@ -155,14 +178,19 @@
   return ret;
 }
 
+<<<<<<< HEAD
 void MinuiBackendAdf::Sync(__unused GRSurfaceAdf* surf) {
 #ifdef HAS_LIBSYNC
   static constexpr unsigned int warningTimeout = 3000;
+=======
+void MinuiBackendAdf::Sync(GRSurfaceAdf* surf) {
+  static constexpr unsigned int kWarningTimeout = 3000;
+>>>>>>> android-10.0.0_r25
 
   if (surf == nullptr) return;
 
   if (surf->fence_fd >= 0) {
-    int err = sync_wait(surf->fence_fd, warningTimeout);
+    int err = sync_wait(surf->fence_fd, kWarningTimeout);
     if (err < 0) {
       perror("adf sync fence wait error\n");
     }
@@ -174,31 +202,22 @@
 }
 
 GRSurface* MinuiBackendAdf::Flip() {
-  GRSurfaceAdf* surf = &surfaces[current_surface];
+  const auto& surf = surfaces[current_surface];
 
   int fence_fd = adf_interface_simple_post(intf_fd, eng_id, surf->width, surf->height, format,
                                            surf->fd, surf->offset, surf->pitch, -1);
   if (fence_fd >= 0) surf->fence_fd = fence_fd;
 
   current_surface = (current_surface + 1) % n_surfaces;
-  Sync(&surfaces[current_surface]);
-  return &surfaces[current_surface];
+  Sync(surfaces[current_surface].get());
+  return surfaces[current_surface].get();
 }
 
 void MinuiBackendAdf::Blank(bool blank) {
   adf_interface_blank(intf_fd, blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON);
 }
 
-void MinuiBackendAdf::SurfaceDestroy(GRSurfaceAdf* surf) {
-  munmap(surf->data, surf->pitch * surf->height);
-  close(surf->fence_fd);
-  close(surf->fd);
-}
-
 MinuiBackendAdf::~MinuiBackendAdf() {
   adf_device_close(&dev);
-  for (unsigned int i = 0; i < n_surfaces; i++) {
-    SurfaceDestroy(&surfaces[i]);
-  }
   if (intf_fd >= 0) close(intf_fd);
 }
diff --git a/minui/graphics_adf.h b/minui/graphics_adf.h
index 2f019ed..79d8d2a 100644
--- a/minui/graphics_adf.h
+++ b/minui/graphics_adf.h
@@ -14,45 +14,63 @@
  * limitations under the License.
  */
 
-#ifndef _GRAPHICS_ADF_H_
-#define _GRAPHICS_ADF_H_
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <memory>
 
 #include <adf/adf.h>
 
 #include "graphics.h"
+#include "minui/minui.h"
 
 class GRSurfaceAdf : public GRSurface {
- private:
-  int fence_fd;
-  int fd;
-  __u32 offset;
-  __u32 pitch;
+ public:
+  ~GRSurfaceAdf() override;
 
+  static std::unique_ptr<GRSurfaceAdf> Create(int intf_fd, const drm_mode_modeinfo* mode,
+                                              __u32 format, int* err);
+
+  uint8_t* data() override {
+    return mmapped_buffer_;
+  }
+
+ private:
   friend class MinuiBackendAdf;
+
+  GRSurfaceAdf(size_t width, size_t height, size_t row_bytes, size_t pixel_bytes, __u32 offset,
+               __u32 pitch, int fd)
+      : GRSurface(width, height, row_bytes, pixel_bytes), offset(offset), pitch(pitch), fd(fd) {}
+
+  const __u32 offset;
+  const __u32 pitch;
+
+  int fd;
+  int fence_fd{ -1 };
+  uint8_t* mmapped_buffer_{ nullptr };
 };
 
 class MinuiBackendAdf : public MinuiBackend {
  public:
+  MinuiBackendAdf();
+  ~MinuiBackendAdf() override;
   GRSurface* Init() override;
   GRSurface* Flip() override;
   void Blank(bool) override;
-  ~MinuiBackendAdf() override;
-  MinuiBackendAdf();
 
  private:
-  int SurfaceInit(const drm_mode_modeinfo* mode, GRSurfaceAdf* surf);
   int InterfaceInit();
   int DeviceInit(adf_device* dev);
-  void SurfaceDestroy(GRSurfaceAdf* surf);
   void Sync(GRSurfaceAdf* surf);
 
   int intf_fd;
   adf_id_t eng_id;
   __u32 format;
   adf_device dev;
-  unsigned int current_surface;
-  unsigned int n_surfaces;
-  GRSurfaceAdf surfaces[2];
+  size_t current_surface;
+  size_t n_surfaces;
+  std::unique_ptr<GRSurfaceAdf> surfaces[2];
 };
-
-#endif  // _GRAPHICS_ADF_H_
diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp
index ef377b7..b8d813e 100644
--- a/minui/graphics_drm.cpp
+++ b/minui/graphics_drm.cpp
@@ -17,78 +17,44 @@
 #include "graphics_drm.h"
 
 #include <fcntl.h>
+#include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <memory>
+
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
 #include <drm_fourcc.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
 #include "minui/minui.h"
 
-#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A)))
-
-MinuiBackendDrm::MinuiBackendDrm()
-    : GRSurfaceDrms(), main_monitor_crtc(nullptr), main_monitor_connector(nullptr), drm_fd(-1) {}
-
-void MinuiBackendDrm::DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc) {
-  if (crtc) {
-    drmModeSetCrtc(drm_fd, crtc->crtc_id,
-                   0,         // fb_id
-                   0, 0,      // x,y
-                   nullptr,   // connectors
-                   0,         // connector_count
-                   nullptr);  // mode
-  }
-}
-
-void MinuiBackendDrm::DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, GRSurfaceDrm* surface) {
-  int32_t ret = drmModeSetCrtc(drm_fd, crtc->crtc_id, surface->fb_id, 0, 0,  // x,y
-                               &main_monitor_connector->connector_id,
-                               1,  // connector_count
-                               &main_monitor_crtc->mode);
-
-  if (ret) {
-    printf("drmModeSetCrtc failed ret=%d\n", ret);
-  }
-}
-
-void MinuiBackendDrm::Blank(bool blank) {
-  if (blank) {
-    DrmDisableCrtc(drm_fd, main_monitor_crtc);
-  } else {
-    DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[current_buffer]);
-  }
-}
-
-void MinuiBackendDrm::DrmDestroySurface(GRSurfaceDrm* surface) {
-  if (!surface) return;
-
-  if (surface->data) {
-    munmap(surface->data, surface->row_bytes * surface->height);
+GRSurfaceDrm::~GRSurfaceDrm() {
+  if (mmapped_buffer_) {
+    munmap(mmapped_buffer_, row_bytes * height);
   }
 
-  if (surface->fb_id) {
-    int ret = drmModeRmFB(drm_fd, surface->fb_id);
-    if (ret) {
-      printf("drmModeRmFB failed ret=%d\n", ret);
+  if (fb_id) {
+    if (drmModeRmFB(drm_fd_, fb_id) != 0) {
+      perror("Failed to drmModeRmFB");
+      // Falling through to free other resources.
     }
   }
 
-  if (surface->handle) {
+  if (handle) {
     drm_gem_close gem_close = {};
-    gem_close.handle = surface->handle;
+    gem_close.handle = handle;
 
-    int ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
-    if (ret) {
-      printf("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret);
+    if (drmIoctl(drm_fd_, DRM_IOCTL_GEM_CLOSE, &gem_close) != 0) {
+      perror("Failed to DRM_IOCTL_GEM_CLOSE");
     }
   }
-
-  delete surface;
 }
 
 static int drm_format_to_bpp(uint32_t format) {
@@ -108,11 +74,9 @@
   }
 }
 
-GRSurfaceDrm* MinuiBackendDrm::DrmCreateSurface(int width, int height) {
-  GRSurfaceDrm* surface = new GRSurfaceDrm;
-  *surface = {};
-
+std::unique_ptr<GRSurfaceDrm> GRSurfaceDrm::Create(int drm_fd, int width, int height) {
   uint32_t format;
+<<<<<<< HEAD
 #if defined(RECOVERY_ABGR)
   format = DRM_FORMAT_RGBA8888;
 #elif defined(RECOVERY_BGRA)
@@ -124,6 +88,22 @@
 #else
   format = DRM_FORMAT_RGB565;
 #endif
+=======
+  PixelFormat pixel_format = gr_pixel_format();
+  // PixelFormat comes in byte order, whereas DRM_FORMAT_* uses little-endian
+  // (external/libdrm/include/drm/drm_fourcc.h). Note that although drm_fourcc.h also defines a
+  // macro of DRM_FORMAT_BIG_ENDIAN, it doesn't seem to be actually supported (see the discussion
+  // in https://lists.freedesktop.org/archives/amd-gfx/2017-May/008560.html).
+  if (pixel_format == PixelFormat::ABGR) {
+    format = DRM_FORMAT_RGBA8888;
+  } else if (pixel_format == PixelFormat::BGRA) {
+    format = DRM_FORMAT_ARGB8888;
+  } else if (pixel_format == PixelFormat::RGBX) {
+    format = DRM_FORMAT_XBGR8888;
+  } else {
+    format = DRM_FORMAT_RGB565;
+  }
+>>>>>>> android-10.0.0_r25
 
   drm_mode_create_dumb create_dumb = {};
   create_dumb.height = height;
@@ -131,53 +111,74 @@
   create_dumb.bpp = drm_format_to_bpp(format);
   create_dumb.flags = 0;
 
-  int ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
-  if (ret) {
-    printf("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n", ret);
-    DrmDestroySurface(surface);
+  if (drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) != 0) {
+    perror("Failed to DRM_IOCTL_MODE_CREATE_DUMB");
     return nullptr;
   }
-  surface->handle = create_dumb.handle;
+
+  // Cannot use std::make_unique to access non-public ctor.
+  auto surface = std::unique_ptr<GRSurfaceDrm>(new GRSurfaceDrm(
+      width, height, create_dumb.pitch, create_dumb.bpp / 8, drm_fd, create_dumb.handle));
 
   uint32_t handles[4], pitches[4], offsets[4];
 
   handles[0] = surface->handle;
   pitches[0] = create_dumb.pitch;
   offsets[0] = 0;
-
-  ret =
-      drmModeAddFB2(drm_fd, width, height, format, handles, pitches, offsets, &(surface->fb_id), 0);
-  if (ret) {
-    printf("drmModeAddFB2 failed ret=%d\n", ret);
-    DrmDestroySurface(surface);
+  if (drmModeAddFB2(drm_fd, width, height, format, handles, pitches, offsets, &surface->fb_id, 0) !=
+      0) {
+    perror("Failed to drmModeAddFB2");
     return nullptr;
   }
 
   drm_mode_map_dumb map_dumb = {};
   map_dumb.handle = create_dumb.handle;
-  ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
-  if (ret) {
-    printf("DRM_IOCTL_MODE_MAP_DUMB failed ret=%d\n", ret);
-    DrmDestroySurface(surface);
+  if (drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb) != 0) {
+    perror("Failed to DRM_IOCTL_MODE_MAP_DUMB");
     return nullptr;
   }
 
-  surface->height = height;
-  surface->width = width;
-  surface->row_bytes = create_dumb.pitch;
-  surface->pixel_bytes = create_dumb.bpp / 8;
-  surface->data = static_cast<unsigned char*>(mmap(nullptr, surface->height * surface->row_bytes,
-                                                   PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd,
-                                                   map_dumb.offset));
-  if (surface->data == MAP_FAILED) {
-    perror("mmap() failed");
-    DrmDestroySurface(surface);
+  auto mmapped = mmap(nullptr, surface->height * surface->row_bytes, PROT_READ | PROT_WRITE,
+                      MAP_SHARED, drm_fd, map_dumb.offset);
+  if (mmapped == MAP_FAILED) {
+    perror("Failed to mmap()");
     return nullptr;
   }
-
+  surface->mmapped_buffer_ = static_cast<uint8_t*>(mmapped);
   return surface;
 }
 
+void MinuiBackendDrm::DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc) {
+  if (crtc) {
+    drmModeSetCrtc(drm_fd, crtc->crtc_id,
+                   0,         // fb_id
+                   0, 0,      // x,y
+                   nullptr,   // connectors
+                   0,         // connector_count
+                   nullptr);  // mode
+  }
+}
+
+bool MinuiBackendDrm::DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc,
+                                    const std::unique_ptr<GRSurfaceDrm>& surface) {
+  if (drmModeSetCrtc(drm_fd, crtc->crtc_id, surface->fb_id, 0, 0,  // x,y
+                     &main_monitor_connector->connector_id,
+                     1,  // connector_count
+                     &main_monitor_crtc->mode) != 0) {
+    perror("Failed to drmModeSetCrtc");
+    return false;
+  }
+  return true;
+}
+
+void MinuiBackendDrm::Blank(bool blank) {
+  if (blank) {
+    DrmDisableCrtc(drm_fd, main_monitor_crtc);
+  } else {
+    DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[current_buffer]);
+  }
+}
+
 static drmModeCrtc* find_crtc_for_connector(int fd, drmModeRes* resources,
                                             drmModeConnector* connector) {
   // Find the encoder. If we already have one, just use it.
@@ -259,7 +260,7 @@
   do {
     main_monitor_connector = find_used_connector_by_type(fd, resources, kConnectorPriority[i]);
     i++;
-  } while (!main_monitor_connector && i < ARRAY_SIZE(kConnectorPriority));
+  } while (!main_monitor_connector && i < arraysize(kConnectorPriority));
 
   /* If we didn't find a connector, grab the first one that is connected. */
   if (!main_monitor_connector) {
@@ -293,60 +294,53 @@
 
 GRSurface* MinuiBackendDrm::Init() {
   drmModeRes* res = nullptr;
+  drm_fd = -1;
 
   /* Consider DRM devices in order. */
   for (int i = 0; i < DRM_MAX_MINOR; i++) {
-    char* dev_name;
-    int ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
-    if (ret < 0) continue;
+    auto dev_name = android::base::StringPrintf(DRM_DEV_NAME, DRM_DIR_NAME, i);
+    android::base::unique_fd fd(open(dev_name.c_str(), O_RDWR | O_CLOEXEC));
+    if (fd == -1) continue;
 
-    drm_fd = open(dev_name, O_RDWR, 0);
-    free(dev_name);
-    if (drm_fd < 0) continue;
-
-    uint64_t cap = 0;
     /* We need dumb buffers. */
-    ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap);
-    if (ret || cap == 0) {
-      close(drm_fd);
+    if (uint64_t cap = 0; drmGetCap(fd.get(), DRM_CAP_DUMB_BUFFER, &cap) != 0 || cap == 0) {
       continue;
     }
 
-    res = drmModeGetResources(drm_fd);
+    res = drmModeGetResources(fd.get());
     if (!res) {
-      close(drm_fd);
       continue;
     }
 
     /* Use this device if it has at least one connected monitor. */
     if (res->count_crtcs > 0 && res->count_connectors > 0) {
-      if (find_first_connected_connector(drm_fd, res)) break;
+      if (find_first_connected_connector(fd.get(), res)) {
+        drm_fd = fd.release();
+        break;
+      }
     }
 
     drmModeFreeResources(res);
-    close(drm_fd);
     res = nullptr;
   }
 
-  if (drm_fd < 0 || res == nullptr) {
-    perror("cannot find/open a drm device");
+  if (drm_fd == -1 || res == nullptr) {
+    perror("Failed to find/open a drm device");
     return nullptr;
   }
 
   uint32_t selected_mode;
   main_monitor_connector = FindMainMonitor(drm_fd, res, &selected_mode);
-
   if (!main_monitor_connector) {
-    printf("main_monitor_connector not found\n");
+    fprintf(stderr, "Failed to find main_monitor_connector\n");
     drmModeFreeResources(res);
     close(drm_fd);
     return nullptr;
   }
 
   main_monitor_crtc = find_crtc_for_connector(drm_fd, res, main_monitor_connector);
-
   if (!main_monitor_crtc) {
-    printf("main_monitor_crtc not found\n");
+    fprintf(stderr, "Failed to find main_monitor_crtc\n");
     drmModeFreeResources(res);
     close(drm_fd);
     return nullptr;
@@ -361,35 +355,66 @@
 
   drmModeFreeResources(res);
 
-  GRSurfaceDrms[0] = DrmCreateSurface(width, height);
-  GRSurfaceDrms[1] = DrmCreateSurface(width, height);
+  GRSurfaceDrms[0] = GRSurfaceDrm::Create(drm_fd, width, height);
+  GRSurfaceDrms[1] = GRSurfaceDrm::Create(drm_fd, width, height);
   if (!GRSurfaceDrms[0] || !GRSurfaceDrms[1]) {
-    // GRSurfaceDrms and drm_fd should be freed in d'tor.
     return nullptr;
   }
 
   current_buffer = 0;
 
-  DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1]);
+  // We will likely encounter errors in the backend functions (i.e. Flip) if EnableCrtc fails.
+  if (!DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1])) {
+    return nullptr;
+  }
 
-  return GRSurfaceDrms[0];
+  return GRSurfaceDrms[0].get();
+}
+
+static void page_flip_complete(__unused int fd,
+                               __unused unsigned int sequence,
+                               __unused unsigned int tv_sec,
+                               __unused unsigned int tv_usec,
+                               void *user_data) {
+  *static_cast<bool*>(user_data) = false;
 }
 
 GRSurface* MinuiBackendDrm::Flip() {
-  int ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id,
-                            GRSurfaceDrms[current_buffer]->fb_id, 0, nullptr);
-  if (ret < 0) {
-    printf("drmModePageFlip failed ret=%d\n", ret);
+  bool ongoing_flip = true;
+  if (drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, GRSurfaceDrms[current_buffer]->fb_id,
+                      DRM_MODE_PAGE_FLIP_EVENT, &ongoing_flip) != 0) {
+    perror("Failed to drmModePageFlip");
     return nullptr;
   }
+
+  while (ongoing_flip) {
+    struct pollfd fds = {
+      .fd = drm_fd,
+      .events = POLLIN
+    };
+
+    if (poll(&fds, 1, -1) == -1 || !(fds.revents & POLLIN)) {
+      perror("Failed to poll() on drm fd");
+      break;
+    }
+
+    drmEventContext evctx = {
+      .version = DRM_EVENT_CONTEXT_VERSION,
+      .page_flip_handler = page_flip_complete
+    };
+
+    if (drmHandleEvent(drm_fd, &evctx) != 0) {
+      perror("Failed to drmHandleEvent");
+      break;
+    }
+  }
+
   current_buffer = 1 - current_buffer;
-  return GRSurfaceDrms[current_buffer];
+  return GRSurfaceDrms[current_buffer].get();
 }
 
 MinuiBackendDrm::~MinuiBackendDrm() {
   DrmDisableCrtc(drm_fd, main_monitor_crtc);
-  DrmDestroySurface(GRSurfaceDrms[0]);
-  DrmDestroySurface(GRSurfaceDrms[1]);
   drmModeFreeCrtc(main_monitor_crtc);
   drmModeFreeConnector(main_monitor_connector);
   close(drm_fd);
diff --git a/minui/graphics_drm.h b/minui/graphics_drm.h
index de96212..57ba39b 100644
--- a/minui/graphics_drm.h
+++ b/minui/graphics_drm.h
@@ -14,45 +14,61 @@
  * limitations under the License.
  */
 
-#ifndef _GRAPHICS_DRM_H_
-#define _GRAPHICS_DRM_H_
+#pragma once
 
+#include <stddef.h>
 #include <stdint.h>
 
+#include <memory>
+
 #include <xf86drmMode.h>
 
 #include "graphics.h"
 #include "minui/minui.h"
 
 class GRSurfaceDrm : public GRSurface {
- private:
-  uint32_t fb_id;
-  uint32_t handle;
+ public:
+  ~GRSurfaceDrm() override;
 
+  // Creates a GRSurfaceDrm instance.
+  static std::unique_ptr<GRSurfaceDrm> Create(int drm_fd, int width, int height);
+
+  uint8_t* data() override {
+    return mmapped_buffer_;
+  }
+
+ private:
   friend class MinuiBackendDrm;
+
+  GRSurfaceDrm(size_t width, size_t height, size_t row_bytes, size_t pixel_bytes, int drm_fd,
+               uint32_t handle)
+      : GRSurface(width, height, row_bytes, pixel_bytes), drm_fd_(drm_fd), handle(handle) {}
+
+  const int drm_fd_;
+
+  uint32_t fb_id{ 0 };
+  uint32_t handle{ 0 };
+  uint8_t* mmapped_buffer_{ nullptr };
 };
 
 class MinuiBackendDrm : public MinuiBackend {
  public:
+  MinuiBackendDrm() = default;
+  ~MinuiBackendDrm() override;
+
   GRSurface* Init() override;
   GRSurface* Flip() override;
   void Blank(bool) override;
-  ~MinuiBackendDrm() override;
-  MinuiBackendDrm();
 
  private:
   void DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc);
-  void DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, GRSurfaceDrm* surface);
-  GRSurfaceDrm* DrmCreateSurface(int width, int height);
-  void DrmDestroySurface(GRSurfaceDrm* surface);
+  bool DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, const std::unique_ptr<GRSurfaceDrm>& surface);
   void DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc);
   drmModeConnector* FindMainMonitor(int fd, drmModeRes* resources, uint32_t* mode_index);
 
-  GRSurfaceDrm* GRSurfaceDrms[2];
-  int current_buffer;
-  drmModeCrtc* main_monitor_crtc;
-  drmModeConnector* main_monitor_connector;
-  int drm_fd;
+  std::unique_ptr<GRSurfaceDrm> GRSurfaceDrms[2];
+  int current_buffer{ 0 };
+  drmModeCrtc* main_monitor_crtc{ nullptr };
+  drmModeConnector* main_monitor_connector{ nullptr };
+  int drm_fd{ -1 };
 };
-
-#endif  // _GRAPHICS_DRM_H_
diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp
index bb91a57..353a070 100644
--- a/minui/graphics_fbdev.cpp
+++ b/minui/graphics_fbdev.cpp
@@ -26,9 +26,17 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <memory>
+
+#include <android-base/unique_fd.h>
+
 #include "minui/minui.h"
 
-MinuiBackendFbdev::MinuiBackendFbdev() : gr_draw(nullptr), fb_fd(-1) {}
+std::unique_ptr<GRSurfaceFbdev> GRSurfaceFbdev::Create(size_t width, size_t height,
+                                                       size_t row_bytes, size_t pixel_bytes) {
+  // Cannot use std::make_unique to access non-public ctor.
+  return std::unique_ptr<GRSurfaceFbdev>(new GRSurfaceFbdev(width, height, row_bytes, pixel_bytes));
+}
 
 void MinuiBackendFbdev::Blank(bool blank) {
 #if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS)
@@ -52,12 +60,12 @@
 #endif
 }
 
-void MinuiBackendFbdev::SetDisplayedFramebuffer(unsigned n) {
+void MinuiBackendFbdev::SetDisplayedFramebuffer(size_t n) {
   if (n > 1 || !double_buffered) return;
 
-  vi.yres_virtual = gr_framebuffer[0].height * 2;
-  vi.yoffset = n * gr_framebuffer[0].height;
-  vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8;
+  vi.yres_virtual = gr_framebuffer[0]->height * 2;
+  vi.yoffset = n * gr_framebuffer[0]->height;
+  vi.bits_per_pixel = gr_framebuffer[0]->pixel_bytes * 8;
   if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
     perror("active fb swap failed");
   }
@@ -65,7 +73,7 @@
 }
 
 GRSurface* MinuiBackendFbdev::Init() {
-  int fd = open("/dev/graphics/fb0", O_RDWR);
+  android::base::unique_fd fd(open("/dev/graphics/fb0", O_RDWR | O_CLOEXEC));
   if (fd == -1) {
     perror("cannot open fb0");
     return nullptr;
@@ -74,13 +82,11 @@
   fb_fix_screeninfo fi;
   if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
     perror("failed to get fb0 info");
-    close(fd);
     return nullptr;
   }
 
   if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
     perror("failed to get fb0 info");
-    close(fd);
     return nullptr;
   }
 
@@ -107,50 +113,41 @@
   void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
   if (bits == MAP_FAILED) {
     perror("failed to mmap framebuffer");
-    close(fd);
     return nullptr;
   }
 
   memset(bits, 0, fi.smem_len);
 
-  gr_framebuffer[0].width = vi.xres;
-  gr_framebuffer[0].height = vi.yres;
-  gr_framebuffer[0].row_bytes = fi.line_length;
-  gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
-  gr_framebuffer[0].data = static_cast<uint8_t*>(bits);
-  memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
+  gr_framebuffer[0] =
+      GRSurfaceFbdev::Create(vi.xres, vi.yres, fi.line_length, vi.bits_per_pixel / 8);
+  gr_framebuffer[0]->buffer_ = static_cast<uint8_t*>(bits);
+  memset(gr_framebuffer[0]->buffer_, 0, gr_framebuffer[0]->height * gr_framebuffer[0]->row_bytes);
+
+  gr_framebuffer[1] =
+      GRSurfaceFbdev::Create(gr_framebuffer[0]->width, gr_framebuffer[0]->height,
+                             gr_framebuffer[0]->row_bytes, gr_framebuffer[0]->pixel_bytes);
 
   /* check if we can use double buffering */
   if (vi.yres * fi.line_length * 2 <= fi.smem_len) {
     double_buffered = true;
 
-    memcpy(gr_framebuffer + 1, gr_framebuffer, sizeof(GRSurface));
-    gr_framebuffer[1].data =
-        gr_framebuffer[0].data + gr_framebuffer[0].height * gr_framebuffer[0].row_bytes;
-
-    gr_draw = gr_framebuffer + 1;
-
+    gr_framebuffer[1]->buffer_ =
+        gr_framebuffer[0]->buffer_ + gr_framebuffer[0]->height * gr_framebuffer[0]->row_bytes;
   } else {
     double_buffered = false;
 
-    // Without double-buffering, we allocate RAM for a buffer to
-    // draw in, and then "flipping" the buffer consists of a
-    // memcpy from the buffer we allocated to the framebuffer.
-
-    gr_draw = static_cast<GRSurface*>(malloc(sizeof(GRSurface)));
-    memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface));
-    gr_draw->data = static_cast<unsigned char*>(malloc(gr_draw->height * gr_draw->row_bytes));
-    if (!gr_draw->data) {
-      perror("failed to allocate in-memory surface");
-      return nullptr;
-    }
+    // Without double-buffering, we allocate RAM for a buffer to draw in, and then "flipping" the
+    // buffer consists of a memcpy from the buffer we allocated to the framebuffer.
+    memory_buffer.resize(gr_framebuffer[1]->height * gr_framebuffer[1]->row_bytes);
+    gr_framebuffer[1]->buffer_ = memory_buffer.data();
   }
 
-  memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes);
-  fb_fd = fd;
+  gr_draw = gr_framebuffer[1].get();
+  memset(gr_draw->buffer_, 0, gr_draw->height * gr_draw->row_bytes);
+  fb_fd = std::move(fd);
   SetDisplayedFramebuffer(0);
 
-  printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height);
+  printf("framebuffer: %d (%zu x %zu)\n", fb_fd.get(), gr_draw->width, gr_draw->height);
 
   Blank(true);
   Blank(false);
@@ -160,25 +157,13 @@
 
 GRSurface* MinuiBackendFbdev::Flip() {
   if (double_buffered) {
-    // Change gr_draw to point to the buffer currently displayed,
-    // then flip the driver so we're displaying the other buffer
-    // instead.
-    gr_draw = gr_framebuffer + displayed_buffer;
+    // Change gr_draw to point to the buffer currently displayed, then flip the driver so we're
+    // displaying the other buffer instead.
+    gr_draw = gr_framebuffer[displayed_buffer].get();
     SetDisplayedFramebuffer(1 - displayed_buffer);
   } else {
     // Copy from the in-memory surface to the framebuffer.
-    memcpy(gr_framebuffer[0].data, gr_draw->data, gr_draw->height * gr_draw->row_bytes);
+    memcpy(gr_framebuffer[0]->buffer_, gr_draw->buffer_, gr_draw->height * gr_draw->row_bytes);
   }
   return gr_draw;
 }
-
-MinuiBackendFbdev::~MinuiBackendFbdev() {
-  close(fb_fd);
-  fb_fd = -1;
-
-  if (!double_buffered && gr_draw) {
-    free(gr_draw->data);
-    free(gr_draw);
-  }
-  gr_draw = nullptr;
-}
diff --git a/minui/graphics_fbdev.h b/minui/graphics_fbdev.h
index 107e195..596ba74 100644
--- a/minui/graphics_fbdev.h
+++ b/minui/graphics_fbdev.h
@@ -14,31 +14,58 @@
  * limitations under the License.
  */
 
-#ifndef _GRAPHICS_FBDEV_H_
-#define _GRAPHICS_FBDEV_H_
+#pragma once
 
 #include <linux/fb.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include <android-base/unique_fd.h>
 
 #include "graphics.h"
 #include "minui/minui.h"
 
+class GRSurfaceFbdev : public GRSurface {
+ public:
+  // Creates and returns a GRSurfaceFbdev instance, or nullptr on error.
+  static std::unique_ptr<GRSurfaceFbdev> Create(size_t width, size_t height, size_t row_bytes,
+                                                size_t pixel_bytes);
+
+  uint8_t* data() override {
+    return buffer_;
+  }
+
+ protected:
+  using GRSurface::GRSurface;
+
+ private:
+  friend class MinuiBackendFbdev;
+
+  // Points to the start of the buffer: either the mmap'd framebuffer or one allocated in-memory.
+  uint8_t* buffer_{ nullptr };
+};
+
 class MinuiBackendFbdev : public MinuiBackend {
  public:
+  MinuiBackendFbdev() = default;
+  ~MinuiBackendFbdev() override = default;
+
   GRSurface* Init() override;
   GRSurface* Flip() override;
   void Blank(bool) override;
-  ~MinuiBackendFbdev() override;
-  MinuiBackendFbdev();
 
  private:
-  void SetDisplayedFramebuffer(unsigned n);
+  void SetDisplayedFramebuffer(size_t n);
 
-  GRSurface gr_framebuffer[2];
+  std::unique_ptr<GRSurfaceFbdev> gr_framebuffer[2];
+  // Points to the current surface (i.e. one of the two gr_framebuffer's).
+  GRSurfaceFbdev* gr_draw{ nullptr };
   bool double_buffered;
-  GRSurface* gr_draw;
-  int displayed_buffer;
+  std::vector<uint8_t> memory_buffer;
+  size_t displayed_buffer{ 0 };
   fb_var_screeninfo vi;
-  int fb_fd;
+  android::base::unique_fd fb_fd;
 };
-
-#endif  // _GRAPHICS_FBDEV_H_
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index bff146a..9c36636 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -14,27 +14,78 @@
  * limitations under the License.
  */
 
-#ifndef _MINUI_H_
-#define _MINUI_H_
+#pragma once
 
+<<<<<<< HEAD
 #ifndef TW_USE_MINUI_21
 
+=======
+#include <stdint.h>
+#include <stdlib.h>
+>>>>>>> android-10.0.0_r25
 #include <sys/types.h>
 
 #include <functional>
+#include <memory>
 #include <string>
 #include <vector>
 
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+
 //
 // Graphics.
 //
 
-struct GRSurface {
-  int width;
-  int height;
-  int row_bytes;
-  int pixel_bytes;
-  unsigned char* data;
+class GRSurface {
+ public:
+  static constexpr size_t kSurfaceDataAlignment = 8;
+
+  virtual ~GRSurface() = default;
+
+  // Creates and returns a GRSurface instance that's sufficient for storing an image of the given
+  // size (i.e. row_bytes * height). The starting address of the surface data is aligned to
+  // kSurfaceDataAlignment. Returns the created GRSurface instance (in std::unique_ptr), or nullptr
+  // on error.
+  static std::unique_ptr<GRSurface> Create(size_t width, size_t height, size_t row_bytes,
+                                           size_t pixel_bytes);
+
+  // Clones the current GRSurface instance (i.e. an image).
+  std::unique_ptr<GRSurface> Clone() const;
+
+  virtual uint8_t* data() {
+    return data_.get();
+  }
+
+  const uint8_t* data() const {
+    return const_cast<const uint8_t*>(const_cast<GRSurface*>(this)->data());
+  }
+
+  size_t data_size() const {
+    return data_size_;
+  }
+
+  size_t width;
+  size_t height;
+  size_t row_bytes;
+  size_t pixel_bytes;
+
+ protected:
+  GRSurface(size_t width, size_t height, size_t row_bytes, size_t pixel_bytes)
+      : width(width), height(height), row_bytes(row_bytes), pixel_bytes(pixel_bytes) {}
+
+ private:
+  // The deleter for data_, whose data is allocated via aligned_alloc(3).
+  struct DataDeleter {
+    void operator()(uint8_t* data) {
+      free(data);
+    }
+  };
+
+  std::unique_ptr<uint8_t, DataDeleter> data_;
+  size_t data_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(GRSurface);
 };
 
 struct GRFont {
@@ -43,14 +94,27 @@
   int char_height;
 };
 
-enum GRRotation {
-  ROTATION_NONE = 0,
-  ROTATION_RIGHT = 1,
-  ROTATION_DOWN = 2,
-  ROTATION_LEFT = 3,
+enum class GRRotation : int {
+  NONE = 0,
+  RIGHT = 1,
+  DOWN = 2,
+  LEFT = 3,
 };
 
+enum class PixelFormat : int {
+  UNKNOWN = 0,
+  ABGR = 1,
+  RGBX = 2,
+  BGRA = 3,
+};
+
+// Initializes the graphics backend and loads font file. Returns 0 on success, or -1 on error. Note
+// that the font initialization failure would be non-fatal, as caller may not need to draw any text
+// at all. Caller can check the font initialization result via gr_sys_font() as needed.
 int gr_init();
+
+// Frees the allocated resources. The function is idempotent, and safe to be called if gr_init()
+// didn't finish successfully.
 void gr_exit();
 
 int gr_fb_width();
@@ -59,10 +123,12 @@
 void gr_flip();
 void gr_fb_blank(bool blank);
 
-void gr_clear();  // clear entire surface to current color
+// Clears entire surface to current color.
+void gr_clear();
 void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
 void gr_fill(int x1, int y1, int x2, int y2);
 
+<<<<<<< HEAD
 void gr_texticon(int x, int y, GRSurface* icon);
 #ifdef TW_NO_MINUI_CUSTOM_FONTS
 void gr_text(int x, int y, const char *s, bool bold);
@@ -70,21 +136,33 @@
 void gr_font_size(int *x, int *y);
 void gr_set_font(__attribute__ ((unused))const char* name);
 #else
+=======
+void gr_texticon(int x, int y, const GRSurface* icon);
+>>>>>>> android-10.0.0_r25
 
 const GRFont* gr_sys_font();
 int gr_init_font(const char* name, GRFont** dest);
 void gr_text(const GRFont* font, int x, int y, const char* s, bool bold);
+// Returns -1 if font is nullptr.
 int gr_measure(const GRFont* font, const char* s);
+<<<<<<< HEAD
 void gr_font_size(const GRFont* font, int* x, int* y);
 #endif
+=======
+// Returns -1 if font is nullptr.
+int gr_font_size(const GRFont* font, int* x, int* y);
+>>>>>>> android-10.0.0_r25
 
-void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy);
-unsigned int gr_get_width(GRSurface* surface);
-unsigned int gr_get_height(GRSurface* surface);
+void gr_blit(const GRSurface* source, int sx, int sy, int w, int h, int dx, int dy);
+unsigned int gr_get_width(const GRSurface* surface);
+unsigned int gr_get_height(const GRSurface* surface);
 
-// Set rotation, flips gr_fb_width/height if 90 degree rotation difference
+// Sets rotation, flips gr_fb_width/height if 90 degree rotation difference
 void gr_rotate(GRRotation rotation);
 
+// Returns the current PixelFormat being used.
+PixelFormat gr_pixel_format();
+
 //
 // Input events.
 //
@@ -104,6 +182,12 @@
 
 #ifdef TW_USE_MINUI_WITH_OPTIONAL_TOUCH_EVENTS
 int ev_init(ev_callback input_cb, bool allow_touch_inputs = false);
+<<<<<<< HEAD
+=======
+void ev_exit();
+int ev_add_fd(android::base::unique_fd&& fd, ev_callback cb);
+void ev_iterate_available_keys(const std::function<void(int)>& f);
+>>>>>>> android-10.0.0_r25
 void ev_iterate_touch_inputs(const std::function<void(int)>& action);
 #else
 int ev_init(ev_callback input_cb);
@@ -170,6 +254,7 @@
 // Free a surface allocated by any of the res_create_*_surface()
 // functions.
 void res_free_surface(GRSurface* surface);
+<<<<<<< HEAD
 
 #else //ifndef TW_USE_MINUI_21
 
@@ -263,3 +348,5 @@
 
 #endif // ifndef TW_USE_MINUI_21
 #endif // ifndef _MINUI_H_
+=======
+>>>>>>> android-10.0.0_r25
diff --git a/minui/include/private/resources.h b/minui/include/private/resources.h
new file mode 100644
index 0000000..047ebe2
--- /dev/null
+++ b/minui/include/private/resources.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <stdio.h>
+
+#include <memory>
+#include <string>
+
+#include <png.h>
+
+// This class handles the PNG file parsing. It also holds the ownership of the PNG pointer and the
+// opened file pointer. Both will be destroyed / closed when this object goes out of scope.
+class PngHandler {
+ public:
+  // Constructs an instance by loading the PNG file from '/res/images/<name>.png', or '<name>'.
+  PngHandler(const std::string& name);
+
+  ~PngHandler();
+
+  png_uint_32 width() const {
+    return width_;
+  }
+
+  png_uint_32 height() const {
+    return height_;
+  }
+
+  png_byte channels() const {
+    return channels_;
+  }
+
+  int bit_depth() const {
+    return bit_depth_;
+  }
+
+  int color_type() const {
+    return color_type_;
+  }
+
+  png_structp png_ptr() const {
+    return png_ptr_;
+  }
+
+  png_infop info_ptr() const {
+    return info_ptr_;
+  }
+
+  int error_code() const {
+    return error_code_;
+  };
+
+  operator bool() const {
+    return error_code_ == 0;
+  }
+
+ private:
+  png_structp png_ptr_{ nullptr };
+  png_infop info_ptr_{ nullptr };
+  png_uint_32 width_;
+  png_uint_32 height_;
+  png_byte channels_;
+  int bit_depth_;
+  int color_type_;
+
+  // The |error_code_| is set to a negative value if an error occurs when opening the png file.
+  int error_code_{ 0 };
+  // After initialization, we'll keep the file pointer open before destruction of PngHandler.
+  std::unique_ptr<FILE, decltype(&fclose)> png_fp_{ nullptr, fclose };
+};
+
+// Overrides the default resource dir, for testing purpose.
+void res_set_resource_dir(const std::string&);
diff --git a/minui/mkfont.c b/minui/mkfont.c
deleted file mode 100644
index 61a5ede..0000000
--- a/minui/mkfont.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char *argv)
-{
-    unsigned n;
-    unsigned char *x;
-    unsigned m;
-    unsigned run_val;
-    unsigned run_count;
- 
-    n = gimp_image.width * gimp_image.height;
-    m = 0;
-    x = gimp_image.pixel_data;
-
-    printf("struct {\n");
-    printf("  unsigned width;\n");
-    printf("  unsigned height;\n");
-    printf("  unsigned cwidth;\n");
-    printf("  unsigned cheight;\n");
-    printf("  unsigned char rundata[];\n");
-    printf("} font = {\n");
-    printf("  .width = %d,\n  .height = %d,\n  .cwidth = %d,\n  .cheight = %d,\n", gimp_image.width, gimp_image.height,
-           gimp_image.width / 96, gimp_image.height);
-    printf("  .rundata = {\n");
-   
-    run_val = (*x ? 0 : 255);
-    run_count = 1;
-    n--;
-    x+=3;
-
-    while(n-- > 0) {
-        unsigned val = (*x ? 0 : 255);
-        x+=3;
-        if((val == run_val) && (run_count < 127)) {
-            run_count++;
-        } else {
-eject:
-            printf("0x%02x,",run_count | (run_val ? 0x80 : 0x00));
-            run_val = val;
-            run_count = 1;
-            m += 5;
-            if(m >= 75) {
-                printf("\n");
-                m = 0;
-            }
-        }
-    }
-    printf("0x%02x,",run_count | (run_val ? 0x80 : 0x00));
-    printf("\n0x00,");
-    printf("\n");
-    printf("  }\n};\n");
-    return 0;
-}
diff --git a/minui/resources.cpp b/minui/resources.cpp
index fd57893..8379885 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "private/resources.h"
+
 #include <fcntl.h>
 #include <linux/fb.h>
 #include <linux/kd.h>
@@ -25,89 +27,68 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <limits>
 #include <memory>
 #include <regex>
 #include <string>
 #include <vector>
 
+<<<<<<< HEAD
 //#include <android-base/stringprintf.h> // does not exist in 6.0
 //#include <android-base/strings.h> // does not exist in 6.0
+=======
+#include <android-base/strings.h>
+>>>>>>> android-10.0.0_r25
 #include <png.h>
 
 #include "minui/minui.h"
 
-#define SURFACE_DATA_ALIGNMENT 8
+static std::string g_resource_dir{ "/res/images" };
 
-static GRSurface* malloc_surface(size_t data_size) {
-    size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT;
-    unsigned char* temp = static_cast<unsigned char*>(malloc(size));
-    if (temp == NULL) return NULL;
-    GRSurface* surface = reinterpret_cast<GRSurface*>(temp);
-    surface->data = temp + sizeof(GRSurface) +
-        (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT));
-    return surface;
+std::unique_ptr<GRSurface> GRSurface::Create(size_t width, size_t height, size_t row_bytes,
+                                             size_t pixel_bytes) {
+  if (width == 0 || row_bytes == 0 || height == 0 || pixel_bytes == 0) return nullptr;
+  if (std::numeric_limits<size_t>::max() / row_bytes < height) return nullptr;
+
+  // Cannot use std::make_unique to access non-public ctor.
+  auto result = std::unique_ptr<GRSurface>(new GRSurface(width, height, row_bytes, pixel_bytes));
+  size_t data_size = row_bytes * height;
+  result->data_size_ =
+      (data_size + kSurfaceDataAlignment - 1) / kSurfaceDataAlignment * kSurfaceDataAlignment;
+  result->data_.reset(
+      static_cast<uint8_t*>(aligned_alloc(kSurfaceDataAlignment, result->data_size_)));
+  if (!result->data_) return nullptr;
+  return result;
 }
 
-// This class handles the png file parsing. It also holds the ownership of the png pointer and the
-// opened file pointer. Both will be destroyed/closed when this object goes out of scope.
-class PngHandler {
- public:
-  PngHandler(const std::string& name);
+std::unique_ptr<GRSurface> GRSurface::Clone() const {
+  auto result = GRSurface::Create(width, height, row_bytes, pixel_bytes);
+  if (!result) return nullptr;
+  memcpy(result->data(), data(), data_size_);
+  return result;
+}
 
-  ~PngHandler();
-
-  png_uint_32 width() const {
-    return width_;
-  }
-
-  png_uint_32 height() const {
-    return height_;
-  }
-
-  png_byte channels() const {
-    return channels_;
-  }
-
-  png_structp png_ptr() const {
-    return png_ptr_;
-  }
-
-  png_infop info_ptr() const {
-    return info_ptr_;
-  }
-
-  int error_code() const {
-    return error_code_;
-  };
-
-  operator bool() const {
-    return error_code_ == 0;
-  }
-
- private:
-  png_structp png_ptr_{ nullptr };
-  png_infop info_ptr_{ nullptr };
-  png_uint_32 width_;
-  png_uint_32 height_;
-  png_byte channels_;
-
-  // The |error_code_| is set to a negative value if an error occurs when opening the png file.
-  int error_code_;
-  // After initialization, we'll keep the file pointer open before destruction of PngHandler.
-  std::unique_ptr<FILE, decltype(&fclose)> png_fp_;
-};
-
+<<<<<<< HEAD
 PngHandler::PngHandler(const std::string& name) : error_code_(0), png_fp_(nullptr, fclose) {
   char res_path[PATH_MAX];
   sprintf(res_path, "/res/images/%s.png", name.c_str());
   //std::string res_path = sprintf("/res/images/%s.png", name.c_str());
   png_fp_.reset(fopen(res_path, "rbe"));
+=======
+PngHandler::PngHandler(const std::string& name) {
+  std::string res_path = g_resource_dir + "/" + name + ".png";
+  png_fp_.reset(fopen(res_path.c_str(), "rbe"));
+  // Try to read from |name| if the resource path does not work.
+  if (!png_fp_) {
+    png_fp_.reset(fopen(name.c_str(), "rbe"));
+  }
+>>>>>>> android-10.0.0_r25
   if (!png_fp_) {
     error_code_ = -1;
     return;
   }
 
-  unsigned char header[8];
+  uint8_t header[8];
   size_t bytesRead = fread(header, 1, sizeof(header), png_fp_.get());
   if (bytesRead != sizeof(header)) {
     error_code_ = -2;
@@ -140,19 +121,17 @@
   png_set_sig_bytes(png_ptr_, sizeof(header));
   png_read_info(png_ptr_, info_ptr_);
 
-  int color_type;
-  int bit_depth;
-  png_get_IHDR(png_ptr_, info_ptr_, &width_, &height_, &bit_depth, &color_type, nullptr, nullptr,
+  png_get_IHDR(png_ptr_, info_ptr_, &width_, &height_, &bit_depth_, &color_type_, nullptr, nullptr,
                nullptr);
 
   channels_ = png_get_channels(png_ptr_, info_ptr_);
 
-  if (bit_depth == 8 && channels_ == 3 && color_type == PNG_COLOR_TYPE_RGB) {
+  if (bit_depth_ == 8 && channels_ == 3 && color_type_ == PNG_COLOR_TYPE_RGB) {
     // 8-bit RGB images: great, nothing to do.
-  } else if (bit_depth <= 8 && channels_ == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
+  } else if (bit_depth_ <= 8 && channels_ == 1 && color_type_ == PNG_COLOR_TYPE_GRAY) {
     // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.
     png_set_expand_gray_1_2_4_to_8(png_ptr_);
-  } else if (bit_depth <= 8 && channels_ == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {
+  } else if (bit_depth_ <= 8 && channels_ == 1 && color_type_ == PNG_COLOR_TYPE_PALETTE) {
     // paletted images: expand to 8-bit RGB.  Note that we DON'T
     // currently expand the tRNS chunk (if any) to an alpha
     // channel, because minui doesn't support alpha channels in
@@ -160,8 +139,8 @@
     png_set_palette_to_rgb(png_ptr_);
     channels_ = 3;
   } else {
-    fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", bit_depth,
-            channels_, color_type);
+    fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", bit_depth_,
+            channels_, color_type_);
     error_code_ = -7;
   }
 }
@@ -172,70 +151,49 @@
   }
 }
 
-// "display" surfaces are transformed into the framebuffer's required
-// pixel format (currently only RGBX is supported) at load time, so
-// gr_blit() can be nothing more than a memcpy() for each row.  The
-// next two functions are the only ones that know anything about the
-// framebuffer pixel format; they need to be modified if the
-// framebuffer format changes (but nothing else should).
+// "display" surfaces are transformed into the framebuffer's required pixel format (currently only
+// RGBX is supported) at load time, so gr_blit() can be nothing more than a memcpy() for each row.
 
-// Allocate and return a GRSurface* sufficient for storing an image of
-// the indicated size in the framebuffer pixel format.
-static GRSurface* init_display_surface(png_uint_32 width, png_uint_32 height) {
-    GRSurface* surface = malloc_surface(width * height * 4);
-    if (surface == NULL) return NULL;
-
-    surface->width = width;
-    surface->height = height;
-    surface->row_bytes = width * 4;
-    surface->pixel_bytes = 4;
-
-    return surface;
-}
-
-// Copy 'input_row' to 'output_row', transforming it to the
-// framebuffer pixel format.  The input format depends on the value of
-// 'channels':
+// Copies 'input_row' to 'output_row', transforming it to the framebuffer pixel format. The input
+// format depends on the value of 'channels':
 //
 //   1 - input is 8-bit grayscale
 //   3 - input is 24-bit RGB
 //   4 - input is 32-bit RGBA/RGBX
 //
 // 'width' is the number of pixels in the row.
-static void transform_rgb_to_draw(unsigned char* input_row,
-                                  unsigned char* output_row,
-                                  int channels, int width) {
-    int x;
-    unsigned char* ip = input_row;
-    unsigned char* op = output_row;
+static void TransformRgbToDraw(const uint8_t* input_row, uint8_t* output_row, int channels,
+                               int width) {
+  const uint8_t* ip = input_row;
+  uint8_t* op = output_row;
 
-    switch (channels) {
-        case 1:
-            // expand gray level to RGBX
-            for (x = 0; x < width; ++x) {
-                *op++ = *ip;
-                *op++ = *ip;
-                *op++ = *ip;
-                *op++ = 0xff;
-                ip++;
-            }
-            break;
+  switch (channels) {
+    case 1:
+      // expand gray level to RGBX
+      for (int x = 0; x < width; ++x) {
+        *op++ = *ip;
+        *op++ = *ip;
+        *op++ = *ip;
+        *op++ = 0xff;
+        ip++;
+      }
+      break;
 
-        case 3:
-            // expand RGBA to RGBX
-            for (x = 0; x < width; ++x) {
-                *op++ = *ip++;
-                *op++ = *ip++;
-                *op++ = *ip++;
-                *op++ = 0xff;
-            }
-            break;
+    case 3:
+      // expand RGBA to RGBX
+      for (int x = 0; x < width; ++x) {
+        *op++ = *ip++;
+        *op++ = *ip++;
+        *op++ = *ip++;
+        *op++ = 0xff;
+      }
+      break;
 
-        case 4:
-            // copy RGBA to RGBX
-            memcpy(output_row, input_row, width*4);
-            break;
-    }
+    case 4:
+      // copy RGBA to RGBX
+      memcpy(output_row, input_row, width * 4);
+      break;
+  }
 }
 
 int res_create_display_surface(const char* name, GRSurface** pSurface) {
@@ -248,23 +206,24 @@
   png_uint_32 width = png_handler.width();
   png_uint_32 height = png_handler.height();
 
-  GRSurface* surface = init_display_surface(width, height);
+  auto surface = GRSurface::Create(width, height, width * 4, 4);
   if (!surface) {
     return -8;
   }
 
-#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
-  png_set_bgr(png_ptr);
-#endif
-
-  for (png_uint_32 y = 0; y < height; ++y) {
-    std::vector<unsigned char> p_row(width * 4);
-    png_read_row(png_ptr, p_row.data(), nullptr);
-    transform_rgb_to_draw(p_row.data(), surface->data + y * surface->row_bytes,
-                          png_handler.channels(), width);
+  PixelFormat pixel_format = gr_pixel_format();
+  if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) {
+    png_set_bgr(png_ptr);
   }
 
-  *pSurface = surface;
+  for (png_uint_32 y = 0; y < height; ++y) {
+    std::vector<uint8_t> p_row(width * 4);
+    png_read_row(png_ptr, p_row.data(), nullptr);
+    TransformRgbToDraw(p_row.data(), surface->data() + y * surface->row_bytes,
+                       png_handler.channels(), width);
+  }
+
+  *pSurface = surface.release();
 
   return 0;
 }
@@ -317,23 +276,24 @@
     goto exit;
   }
   for (int i = 0; i < *frames; ++i) {
-    surface[i] = init_display_surface(width, height / *frames);
-    if (!surface[i]) {
+    auto created_surface = GRSurface::Create(width, height / *frames, width * 4, 4);
+    if (!created_surface) {
       result = -8;
       goto exit;
     }
+    surface[i] = created_surface.release();
   }
 
-#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
-  png_set_bgr(png_ptr);
-#endif
+  if (gr_pixel_format() == PixelFormat::ABGR || gr_pixel_format() == PixelFormat::BGRA) {
+    png_set_bgr(png_ptr);
+  }
 
   for (png_uint_32 y = 0; y < height; ++y) {
-    std::vector<unsigned char> p_row(width * 4);
+    std::vector<uint8_t> p_row(width * 4);
     png_read_row(png_ptr, p_row.data(), nullptr);
     int frame = y % *frames;
-    unsigned char* out_row = surface[frame]->data + (y / *frames) * surface[frame]->row_bytes;
-    transform_rgb_to_draw(p_row.data(), out_row, png_handler.channels(), width);
+    uint8_t* out_row = surface[frame]->data() + (y / *frames) * surface[frame]->row_bytes;
+    TransformRgbToDraw(p_row.data(), out_row, png_handler.channels(), width);
   }
 
   *pSurface = surface;
@@ -370,29 +330,30 @@
   png_uint_32 width = png_handler.width();
   png_uint_32 height = png_handler.height();
 
-  GRSurface* surface = malloc_surface(width * height);
+  auto surface = GRSurface::Create(width, height, width, 1);
   if (!surface) {
     return -8;
   }
-  surface->width = width;
-  surface->height = height;
-  surface->row_bytes = width;
-  surface->pixel_bytes = 1;
 
-#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
-  png_set_bgr(png_ptr);
-#endif
+  PixelFormat pixel_format = gr_pixel_format();
+  if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) {
+    png_set_bgr(png_ptr);
+  }
 
   for (png_uint_32 y = 0; y < height; ++y) {
-    unsigned char* p_row = surface->data + y * surface->row_bytes;
+    uint8_t* p_row = surface->data() + y * surface->row_bytes;
     png_read_row(png_ptr, p_row, nullptr);
   }
 
-  *pSurface = surface;
+  *pSurface = surface.release();
 
   return 0;
 }
 
+void res_set_resource_dir(const std::string& dirname) {
+  g_resource_dir = dirname;
+}
+
 // This function tests if a locale string stored in PNG (prefix) matches
 // the locale string provided by the system (locale).
 bool matches_locale(const std::string& prefix, const std::string& locale) {
@@ -430,7 +391,7 @@
   }
 
   std::vector<std::string> result;
-  std::vector<unsigned char> row(png_handler.width());
+  std::vector<uint8_t> row(png_handler.width());
   for (png_uint_32 y = 0; y < png_handler.height(); ++y) {
     png_read_row(png_handler.png_ptr(), row.data(), nullptr);
     int h = (row[3] << 8) | row[2];
@@ -466,7 +427,7 @@
   png_uint_32 height = png_handler.height();
 
   for (png_uint_32 y = 0; y < height; ++y) {
-    std::vector<unsigned char> row(width);
+    std::vector<uint8_t> row(width);
     png_read_row(png_ptr, row.data(), nullptr);
     int w = (row[1] << 8) | row[0];
     int h = (row[3] << 8) | row[2];
@@ -476,21 +437,17 @@
     if (y + 1 + h >= height || matches_locale(loc, locale)) {
       printf("  %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
 
-      GRSurface* surface = malloc_surface(w * h);
+      auto surface = GRSurface::Create(w, h, w, 1);
       if (!surface) {
         return -8;
       }
-      surface->width = w;
-      surface->height = h;
-      surface->row_bytes = w;
-      surface->pixel_bytes = 1;
 
       for (int i = 0; i < h; ++i, ++y) {
         png_read_row(png_ptr, row.data(), nullptr);
-        memcpy(surface->data + i * w, row.data(), w);
+        memcpy(surface->data() + i * w, row.data(), w);
       }
 
-      *pSurface = surface;
+      *pSurface = surface.release();
       break;
     }