Add support for TrueType fonts

* Keeps original font system in place
* Uses the same API as original font system:
   - You can render only one line at a time
   - You can only use one font and color for one gr_text* call
* Caches all rendered text, with a string cache limited to 400
  entries, then it trucates to 250, which results in memory
  usage hovering around 5-10MB

Change-Id: I36107b9dcd8d57bae4486fce8b8f64e49ef3d906
Signed-off-by: Vojtech Bocek <vbocek@gmail.com>
diff --git a/gui/Android.mk b/gui/Android.mk
index 52d5f55..baae3ed 100644
--- a/gui/Android.mk
+++ b/gui/Android.mk
@@ -59,6 +59,9 @@
 ifeq ($(TW_OEM_BUILD), true)
     LOCAL_CFLAGS += -DTW_OEM_BUILD
 endif
+ifeq ($(TW_DISABLE_TTF), true)
+    LOCAL_CFLAGS += -DTW_DISABLE_TTF
+endif
 
 ifeq ($(DEVICE_RESOLUTION),)
 $(warning ********************************************************************************)
@@ -104,6 +107,13 @@
 else
 	TWRP_THEME_LOC := $(TW_CUSTOM_THEME)
 endif
+
+ifeq ($(TW_DISABLE_TTF), true)
+	TWRP_REMOVE_FONT := rm -f $(TARGET_RECOVERY_ROOT_OUT)/res/fonts/*.ttf
+else
+	TWRP_REMOVE_FONT := rm -f $(TARGET_RECOVERY_ROOT_OUT)/res/fonts/*.dat
+endif
+
 TWRP_RES_GEN := $(intermediates)/twrp
 ifneq ($(TW_USE_TOOLBOX), true)
 	TWRP_SH_TARGET := /sbin/busybox
@@ -116,6 +126,7 @@
 	cp -fr $(TWRP_RES_LOC)/* $(TARGET_RECOVERY_ROOT_OUT)/res/
 	cp -fr $(TWRP_THEME_LOC)/* $(TARGET_RECOVERY_ROOT_OUT)/res/
 	$(TWRP_COMMON_XML)
+	$(TWRP_REMOVE_FONT)
 	mkdir -p $(TARGET_RECOVERY_ROOT_OUT)/sbin/
 	ln -sf $(TWRP_SH_TARGET) $(TARGET_RECOVERY_ROOT_OUT)/sbin/sh
 	ln -sf /sbin/pigz $(TARGET_RECOVERY_ROOT_OUT)/sbin/gzip
diff --git a/gui/console.cpp b/gui/console.cpp
index 897c582..aad392c 100644
--- a/gui/console.cpp
+++ b/gui/console.cpp
@@ -177,7 +177,7 @@
 		}
 	}
 
-	gr_getFontDetails(mFont, &mFontHeight, NULL);
+	mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL);
 	SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
 	SetRenderPos(mConsoleX, mConsoleY);
 	return;
diff --git a/gui/devices/1024x600/res/ui.xml b/gui/devices/1024x600/res/ui.xml
index 87248a6..4d6f317 100644
--- a/gui/devices/1024x600/res/ui.xml
+++ b/gui/devices/1024x600/res/ui.xml
@@ -14,7 +14,7 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Regular-20" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
 		<resource name="base" type="image" filename="background.jpg" />
 		<resource name="main_button" type="image" filename="button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/1024x768/res/ui.xml b/gui/devices/1024x768/res/ui.xml
index 407e18b..29f1690 100644
--- a/gui/devices/1024x768/res/ui.xml
+++ b/gui/devices/1024x768/res/ui.xml
@@ -14,7 +14,7 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Regular-20" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
 		<resource name="base" type="image" filename="background.jpg" />
 		<resource name="main_button" type="image" filename="button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/1080x1920/res/ui.xml b/gui/devices/1080x1920/res/ui.xml
index 0d547a6..95c48a5 100644
--- a/gui/devices/1080x1920/res/ui.xml
+++ b/gui/devices/1080x1920/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-40" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-40" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-40" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Condensed-40" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Condensed-40" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Condensed-40" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/1200x1920/res/ui.xml b/gui/devices/1200x1920/res/ui.xml
index 0778692..428880d 100644
--- a/gui/devices/1200x1920/res/ui.xml
+++ b/gui/devices/1200x1920/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-40" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-40" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-40" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Condensed-40" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Condensed-40" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Condensed-40" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/1280x800/res/ui.xml b/gui/devices/1280x800/res/ui.xml
index bfb1a3a..6f6c2bd 100644
--- a/gui/devices/1280x800/res/ui.xml
+++ b/gui/devices/1280x800/res/ui.xml
@@ -14,7 +14,7 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Regular-20" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
 		<resource name="base" type="image" filename="background.jpg" />
 		<resource name="main_button" type="image" filename="button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/1440x2560/res/ui.xml b/gui/devices/1440x2560/res/ui.xml
index ae25d33..fe55dfd 100644
--- a/gui/devices/1440x2560/res/ui.xml
+++ b/gui/devices/1440x2560/res/ui.xml
@@ -14,9 +14,9 @@
     </include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-50" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-50" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-50" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="50" fallback="Roboto-Condensed-50" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="50" fallback="Roboto-Condensed-50" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="50" fallback="Roboto-Condensed-50" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/1600x2560/res/ui.xml b/gui/devices/1600x2560/res/ui.xml
index 9703881..8561b2d 100644
--- a/gui/devices/1600x2560/res/ui.xml
+++ b/gui/devices/1600x2560/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-40" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-40" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-40" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Condensed-40" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Condensed-40" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Condensed-40" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/1920x1200/res/ui.xml b/gui/devices/1920x1200/res/ui.xml
index d8d8a7d..3e8c9f1 100644
--- a/gui/devices/1920x1200/res/ui.xml
+++ b/gui/devices/1920x1200/res/ui.xml
@@ -14,7 +14,7 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Regular-30" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="30" fallback="Roboto-Regular-30" />
 		<resource name="base" type="image" filename="background.jpg" />
 		<resource name="main_button" type="image" filename="button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/240x240/res/ui.xml b/gui/devices/240x240/res/ui.xml
index 4cc25dd..294e595 100644
--- a/gui/devices/240x240/res/ui.xml
+++ b/gui/devices/240x240/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-12" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-12" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-12" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="12" fallback="Roboto-Condensed-12" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="12" fallback="Roboto-Condensed-12" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="12" fallback="Roboto-Condensed-12" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/2560x1600/res/ui.xml b/gui/devices/2560x1600/res/ui.xml
index ca0d883..cb0c12e 100644
--- a/gui/devices/2560x1600/res/ui.xml
+++ b/gui/devices/2560x1600/res/ui.xml
@@ -14,7 +14,7 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Regular-40" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="40" fallback="Roboto-Regular-40" />
 		<resource name="base" type="image" filename="background.jpg" />
 		<resource name="main_button" type="image" filename="button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/280x280/res/ui.xml b/gui/devices/280x280/res/ui.xml
index 5a705a0..99532ed 100644
--- a/gui/devices/280x280/res/ui.xml
+++ b/gui/devices/280x280/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-12" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-12" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-12" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="12" fallback="Roboto-Condensed-12" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="12" fallback="Roboto-Condensed-12" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="12" fallback="Roboto-Condensed-12" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/320x320/res/ui.xml b/gui/devices/320x320/res/ui.xml
index a9be8c9..f668529 100644
--- a/gui/devices/320x320/res/ui.xml
+++ b/gui/devices/320x320/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-14" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-14" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-14" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="14" fallback="Roboto-Condensed-14" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="14" fallback="Roboto-Condensed-14" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="14" fallback="Roboto-Condensed-14" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/320x480/res/ui.xml b/gui/devices/320x480/res/ui.xml
index 57baf5f..cccd5b3 100644
--- a/gui/devices/320x480/res/ui.xml
+++ b/gui/devices/320x480/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-16" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-14" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-14" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="14" fallback="Roboto-Condensed-16" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="14" fallback="Roboto-Condensed-14" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="14" fallback="Roboto-Condensed-14" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml
index aad9822..940ad43 100644
--- a/gui/devices/480x800/res/ui.xml
+++ b/gui/devices/480x800/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Regular-20" />
-		<resource name="mediumfont" type="font" filename="Roboto-Regular-20" />
-		<resource name="filelist" type="font" filename="Roboto-Regular-20" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/480x854/res/ui.xml b/gui/devices/480x854/res/ui.xml
index ea0cf77..dce1d88 100644
--- a/gui/devices/480x854/res/ui.xml
+++ b/gui/devices/480x854/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Regular-20" />
-		<resource name="mediumfont" type="font" filename="Roboto-Regular-20" />
-		<resource name="filelist" type="font" filename="Roboto-Regular-20" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/540x960/res/ui.xml b/gui/devices/540x960/res/ui.xml
index 58d6c9d..37c3e26 100644
--- a/gui/devices/540x960/res/ui.xml
+++ b/gui/devices/540x960/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Regular-20" />
-		<resource name="mediumfont" type="font" filename="Roboto-Regular-20" />
-		<resource name="filelist" type="font" filename="Roboto-Regular-25" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-20" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="20" fallback="Roboto-Regular-25" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="qhd-menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/720x1280/res/ui.xml b/gui/devices/720x1280/res/ui.xml
index f44998f..a7ff192 100644
--- a/gui/devices/720x1280/res/ui.xml
+++ b/gui/devices/720x1280/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-30" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-30" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-30" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="30" fallback="Roboto-Condensed-30" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="30" fallback="Roboto-Condensed-30" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="30" fallback="Roboto-Condensed-30" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/800x1280/res/ui.xml b/gui/devices/800x1280/res/ui.xml
index b074931..e0036bf 100644
--- a/gui/devices/800x1280/res/ui.xml
+++ b/gui/devices/800x1280/res/ui.xml
@@ -14,9 +14,9 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-30" />
-		<resource name="mediumfont" type="font" filename="Roboto-Condensed-30" />
-		<resource name="filelist" type="font" filename="Roboto-Condensed-30" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="30" fallback="Roboto-Condensed-30" />
+		<resource name="mediumfont" type="font" filename="RobotoCondensed-Regular.ttf" size="30" fallback="Roboto-Condensed-30" />
+		<resource name="filelist" type="font" filename="RobotoCondensed-Regular.ttf" size="30" fallback="Roboto-Condensed-30" />
 		<resource name="top_bar" type="image" filename="top-bar.jpg" />
 		<resource name="main_button" type="image" filename="menu-button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/800x480/res/ui.xml b/gui/devices/800x480/res/ui.xml
index 0ee0e94..9acb7a1 100644
--- a/gui/devices/800x480/res/ui.xml
+++ b/gui/devices/800x480/res/ui.xml
@@ -14,7 +14,7 @@
 	</include>
 
 	<resources>
-		<resource name="font" type="font" filename="Roboto-Condensed-16" />
+		<resource name="font" type="font" filename="RobotoCondensed-Regular.ttf" size="16" fallback="Roboto-Condensed-16" />
 		<resource name="base" type="image" filename="background.jpg" />
 		<resource name="main_button" type="image" filename="button" />
 		<resource name="file_icon" type="image" filename="file" />
diff --git a/gui/devices/common/res/fonts/RobotoCondensed-Regular.ttf b/gui/devices/common/res/fonts/RobotoCondensed-Regular.ttf
new file mode 100644
index 0000000..b9fc49c
--- /dev/null
+++ b/gui/devices/common/res/fonts/RobotoCondensed-Regular.ttf
Binary files differ
diff --git a/gui/fileselector.cpp b/gui/fileselector.cpp
index 4f90ca3..cf7a9a9 100644
--- a/gui/fileselector.cpp
+++ b/gui/fileselector.cpp
@@ -333,7 +333,7 @@
 	}
 
 	// Retrieve the line height
-	gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
+	mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL);
 	mLineHeight = mFontHeight;
 	mHeaderH = mFontHeight;
 
diff --git a/gui/input.cpp b/gui/input.cpp
index 61b0cff..84ee17b 100644
--- a/gui/input.cpp
+++ b/gui/input.cpp
@@ -139,7 +139,7 @@
 		attr = child->first_attribute("resource");
 		if (attr) {
 			mFont = PageManager::FindResource(attr->value());
-			gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
+			mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL);
 		}
 	}
 
diff --git a/gui/listbox.cpp b/gui/listbox.cpp
index e09ec53..851b373 100644
--- a/gui/listbox.cpp
+++ b/gui/listbox.cpp
@@ -271,7 +271,7 @@
 	}
 
 	// Retrieve the line height
-	gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
+	mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL);
 	mLineHeight = mFontHeight;
 	mHeaderH = mFontHeight;
 
diff --git a/gui/partitionlist.cpp b/gui/partitionlist.cpp
index 317e178..2d464e1 100644
--- a/gui/partitionlist.cpp
+++ b/gui/partitionlist.cpp
@@ -273,7 +273,7 @@
 	}
 
 	// Retrieve the line height
-	gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
+	mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL);
 	mLineHeight = mFontHeight;
 	mHeaderH = mFontHeight;
 
diff --git a/gui/resources.cpp b/gui/resources.cpp
index 8d430b1..4fce0ca 100644
--- a/gui/resources.cpp
+++ b/gui/resources.cpp
@@ -65,27 +65,82 @@
  : Resource(node, pZip)
 {
 	std::string file;
+	xml_attribute<>* attr;
 
 	mFont = NULL;
 	if (!node)
 		return;
 
-	if (node->first_attribute("filename"))
-		file = node->first_attribute("filename")->value();
+	attr = node->first_attribute("filename");
+	if (!attr)
+		return;
 
-	if (ExtractResource(pZip, "fonts", file, ".dat", TMP_RESOURCE_NAME) == 0)
+	file = attr->value();
+
+#ifndef TW_DISABLE_TTF
+	if(file.size() >= 4 && file.compare(file.size()-4, 4, ".ttf") == 0)
 	{
-		mFont = gr_loadFont(TMP_RESOURCE_NAME);
-		unlink(TMP_RESOURCE_NAME);
+		m_type = TYPE_TTF;
+
+		attr = node->first_attribute("size");
+		if(!attr)
+			return;
+
+		int size = atoi(attr->value());
+		int dpi = 300;
+
+		attr = node->first_attribute("dpi");
+		if(attr)
+			dpi = atoi(attr->value());
+
+		if (ExtractResource(pZip, "fonts", file, "", TMP_RESOURCE_NAME) == 0)
+		{
+			mFont = gr_ttf_loadFont(TMP_RESOURCE_NAME, size, dpi);
+			unlink(TMP_RESOURCE_NAME);
+		}
+		else
+		{
+			file = std::string("/res/fonts/") + file;
+			mFont = gr_ttf_loadFont(file.c_str(), size, dpi);
+		}
 	}
 	else
+#endif
 	{
-		mFont = gr_loadFont(file.c_str());
+		m_type = TYPE_TWRP;
+
+		if(file.size() >= 4 && file.compare(file.size()-4, 4, ".ttf") == 0)
+		{
+			attr = node->first_attribute("fallback");
+			if (!attr)
+				return;
+
+			file = attr->value();
+		}
+
+		if (ExtractResource(pZip, "fonts", file, ".dat", TMP_RESOURCE_NAME) == 0)
+		{
+			mFont = gr_loadFont(TMP_RESOURCE_NAME);
+			unlink(TMP_RESOURCE_NAME);
+		}
+		else
+		{
+			mFont = gr_loadFont(file.c_str());
+		}
 	}
 }
 
 FontResource::~FontResource()
 {
+	if(mFont)
+	{
+#ifndef TW_DISABLE_TTF
+		if(m_type == TYPE_TTF)
+			gr_ttf_freeFont(mFont);
+		else
+#endif
+			gr_freeFont(mFont);
+	}
 }
 
 ImageResource::ImageResource(xml_node<>* node, ZipArchive* pZip)
diff --git a/gui/resources.hpp b/gui/resources.hpp
index 874836e..3cb5281 100644
--- a/gui/resources.hpp
+++ b/gui/resources.hpp
@@ -38,6 +38,14 @@
 class FontResource : public Resource
 {
 public:
+	enum Type
+	{
+		TYPE_TWRP,
+#ifndef TW_DISABLE_TTF
+		TYPE_TTF,
+#endif
+	};
+
 	FontResource(xml_node<>* node, ZipArchive* pZip);
 	virtual ~FontResource();
 
@@ -46,6 +54,7 @@
 
 protected:
 	void* mFont;
+	Type m_type;
 };
 
 class ImageResource : public Resource
diff --git a/gui/slidervalue.cpp b/gui/slidervalue.cpp
index 5b4d57f..700d7d5 100644
--- a/gui/slidervalue.cpp
+++ b/gui/slidervalue.cpp
@@ -198,7 +198,7 @@
 		}
 	}
 
-	gr_getFontDetails(mFont ? mFont->GetResource() : NULL, (unsigned*) &mFontHeight, NULL);
+	mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL);
 
 	if(mShowCurr)
 	{
diff --git a/gui/text.cpp b/gui/text.cpp
index c594f48..29d7ad9 100644
--- a/gui/text.cpp
+++ b/gui/text.cpp
@@ -97,7 +97,7 @@
 	mLastValue = parseText();
 	if (mLastValue != mText)   mIsStatic = 0;
 
-	gr_getFontDetails(mFont ? mFont->GetResource() : NULL, (unsigned*) &mFontHeight, NULL);
+	mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL);
 	return;
 }
 
diff --git a/minuitwrp/Android.mk b/minuitwrp/Android.mk
index ba81f27..bc4e054 100644
--- a/minuitwrp/Android.mk
+++ b/minuitwrp/Android.mk
@@ -107,8 +107,16 @@
   LOCAL_CFLAGS += -DWHITELIST_INPUT=$(TW_WHITELIST_INPUT)
 endif
 
-LOCAL_SHARED_LIBRARIES += libz libc libcutils libjpeg
-LOCAL_STATIC_LIBRARIES += libpng libpixelflinger_static
+ifeq ($(TW_DISABLE_TTF), true)
+    LOCAL_CFLAGS += -DTW_DISABLE_TTF
+else
+    LOCAL_SHARED_LIBRARIES += libft2
+    LOCAL_C_INCLUDES += external/freetype/include
+    LOCAL_SRC_FILES += truetype.c
+endif
+
+LOCAL_SHARED_LIBRARIES += libz libc libcutils libjpeg libpng
+LOCAL_STATIC_LIBRARIES += libpixelflinger_static
 LOCAL_MODULE_TAGS := eng
 LOCAL_MODULE := libminuitwrp
 
diff --git a/minuitwrp/graphics.c b/minuitwrp/graphics.c
index 79b1e9a..9926904 100644
--- a/minuitwrp/graphics.c
+++ b/minuitwrp/graphics.c
@@ -58,6 +58,7 @@
 // #define PRINT_SCREENINFO 1 // Enables printing of screen info to log
 
 typedef struct {
+    int type;
     GGLSurface texture;
     unsigned offset[97];
     unsigned cheight;
@@ -392,6 +393,11 @@
 
     if (!fnt)   fnt = gr_font;
 
+#ifndef TW_DISABLE_TTF
+    if(fnt->type == FONT_TYPE_TTF)
+        return gr_ttf_measureEx(s, font);
+#endif
+
     while ((off = *s++))
     {
         off -= 32;
@@ -410,6 +416,11 @@
 
     if (!fnt)   fnt = gr_font;
 
+#ifndef TW_DISABLE_TTF
+    if(fnt->type == FONT_TYPE_TTF)
+        return gr_ttf_maxExW(s, font, max_width);
+#endif
+
     while ((off = *s++))
     {
         off -= 32;
@@ -425,21 +436,6 @@
     return total;
 }
 
-unsigned character_width(const char *s, void* pFont)
-{
-	GRFont *font = (GRFont*) pFont;
-	unsigned off;
-
-	/* Handle default font */
-    if (!font)  font = gr_font;
-
-	off = *s - 32;
-	if (off == 0)
-		return 0;
-
-	return font->offset[off+1] - font->offset[off];
-}
-
 int gr_textEx(int x, int y, const char *s, void* pFont)
 {
     GGLContext *gl = gr_context;
@@ -450,6 +446,11 @@
     /* Handle default font */
     if (!font)  font = gr_font;
 
+#ifndef TW_DISABLE_TTF
+    if(font->type == FONT_TYPE_TTF)
+        return gr_ttf_textExWH(gl, x, y, s, pFont, -1, -1);
+#endif
+
     gl->bindTexture(gl, &font->texture);
     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
@@ -480,6 +481,11 @@
     /* Handle default font */
     if (!font)  font = gr_font;
 
+#ifndef TW_DISABLE_TTF
+    if(font->type == FONT_TYPE_TTF)
+        return gr_ttf_textExWH(gl, x, y, s, pFont, max_width, -1);
+#endif
+
     gl->bindTexture(gl, &font->texture);
     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
@@ -518,6 +524,11 @@
     /* Handle default font */
     if (!font)  font = gr_font;
 
+#ifndef TW_DISABLE_TTF
+    if(font->type == FONT_TYPE_TTF)
+        return gr_ttf_textExWH(gl, x, y, s, pFont, max_width, max_height);
+#endif
+
     gl->bindTexture(gl, &font->texture);
     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
@@ -549,34 +560,6 @@
     return x;
 }
 
-int twgr_text(int x, int y, const char *s)
-{
-    GGLContext *gl = gr_context;
-    GRFont *font = gr_font;
-    unsigned off;
-    unsigned cwidth = 0;
-
-    y -= font->ascent;
-
-    gl->bindTexture(gl, &font->texture);
-    gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
-    gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
-    gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
-    gl->enable(gl, GGL_TEXTURE_2D);
-
-    while((off = *s++)) {
-        off -= 32;
-        if (off < 96) {
-            cwidth = font->offset[off+1] - font->offset[off];
-            gl->texCoord2i(gl, (off * cwidth) - x, 0 - y);
-            gl->recti(gl, x, y, x + cwidth, y + font->cheight);
-        }
-        x += cwidth;
-    }
-
-    return x;
-}
-
 void gr_fill(int x, int y, int w, int h)
 {
     GGLContext *gl = gr_context;
@@ -682,33 +665,32 @@
     ftex->stride = width;
     ftex->data = (void*) bits;
     ftex->format = GGL_PIXEL_FORMAT_A_8;
+    font->type = FONT_TYPE_TWRP;
     font->cheight = height;
     font->ascent = height - 2;
     return (void*) font;
 }
 
-int gr_getFontDetails(void* font, unsigned* cheight, unsigned* maxwidth)
+void gr_freeFont(void *font)
+{
+    GRFont *f = font;
+    free(f->texture.data);
+    free(f);
+}
+
+int gr_getMaxFontHeight(void *font)
 {
     GRFont *fnt = (GRFont*) font;
 
     if (!fnt)   fnt = gr_font;
     if (!fnt)   return -1;
 
-    if (cheight)    *cheight = fnt->cheight;
-    if (maxwidth)
-    {
-        int pos;
-        *maxwidth = 0;
-        for (pos = 0; pos < 96; pos++)
-        {
-            unsigned int width = fnt->offset[pos+1] - fnt->offset[pos];
-            if (width > *maxwidth)
-            {
-                *maxwidth = width;
-            }
-        }
-    }
-    return 0;
+#ifndef TW_DISABLE_TTF
+    if(fnt->type == FONT_TYPE_TTF)
+        return gr_ttf_getMaxFontHeight(font);
+#endif
+
+    return fnt->cheight;
 }
 
 static void gr_init_font(void)
@@ -746,6 +728,7 @@
     ftex->stride = width;
     ftex->data = (void*) bits;
     ftex->format = GGL_PIXEL_FORMAT_A_8;
+    gr_font->type = FONT_TYPE_TWRP;
     gr_font->cheight = height;
     gr_font->ascent = height - 2;
     return;
diff --git a/minuitwrp/minui.h b/minuitwrp/minui.h
index f04f518..cb9f8a3 100644
--- a/minuitwrp/minui.h
+++ b/minuitwrp/minui.h
@@ -20,6 +20,12 @@
 typedef void* gr_surface;
 typedef unsigned short gr_pixel;
 
+#define FONT_TYPE_TWRP 0
+
+#ifndef TW_DISABLE_TTF
+#define FONT_TYPE_TTF  1
+#endif
+
 int gr_init(void);
 void gr_exit(void);
 
@@ -35,16 +41,25 @@
 int gr_textEx(int x, int y, const char *s, void* font);
 int gr_textExW(int x, int y, const char *s, void* font, int max_width);
 int gr_textExWH(int x, int y, const char *s, void* pFont, int max_width, int max_height);
-int twgr_text(int x, int y, const char *s);
 static inline int gr_text(int x, int y, const char *s)     { return gr_textEx(x, y, s, NULL); }
 int gr_measureEx(const char *s, void* font);
 static inline int gr_measure(const char *s)                { return gr_measureEx(s, NULL); }
 int gr_maxExW(const char *s, void* font, int max_width);
 
-int gr_getFontDetails(void* font, unsigned* cheight, unsigned* maxwidth);
-static inline void gr_font_size(int *x, int *y)            { gr_getFontDetails(NULL, (unsigned*) y, (unsigned*) x); }
+int gr_getMaxFontHeight(void *font);
 
 void* gr_loadFont(const char* fontName);
+void gr_freeFont(void *font);
+
+#ifndef TW_DISABLE_TTF
+void *gr_ttf_loadFont(const char *filename, int size, int dpi);
+void gr_ttf_freeFont(void *font);
+int gr_ttf_textExWH(void *context, int x, int y, const char *s, void *pFont, int max_width, int max_height);
+int gr_ttf_measureEx(const char *s, void *font);
+int gr_ttf_maxExW(const char *s, void *font, int max_width);
+int gr_ttf_getMaxFontHeight(void *font);
+void gr_ttf_dump_stats(void);
+#endif
 
 void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy);
 unsigned int gr_get_width(gr_surface surface);
diff --git a/minuitwrp/truetype.c b/minuitwrp/truetype.c
new file mode 100644
index 0000000..8e0df42
--- /dev/null
+++ b/minuitwrp/truetype.c
@@ -0,0 +1,731 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "minui.h"
+
+#include <cutils/hashmap.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+#include <pixelflinger/pixelflinger.h>
+#include <pthread.h>
+
+#define STRING_CACHE_MAX_ENTRIES 400
+#define STRING_CACHE_TRUNCATE_ENTRIES 150
+
+typedef struct
+{
+    int size;
+    int dpi;
+    char *path;
+} TrueTypeFontKey;
+
+typedef struct
+{
+    int type;
+    int refcount;
+    int size;
+    int dpi;
+    int max_height;
+    int base;
+    FT_Face face;
+    Hashmap *glyph_cache;
+    Hashmap *string_cache;
+    struct StringCacheEntry *string_cache_head;
+    struct StringCacheEntry *string_cache_tail;
+    pthread_mutex_t mutex;
+    TrueTypeFontKey *key;
+} TrueTypeFont;
+
+typedef struct
+{
+    FT_BBox bbox;
+    FT_BitmapGlyph glyph;
+} TrueTypeCacheEntry;
+
+typedef struct
+{
+    char *text;
+    int max_width;
+} StringCacheKey;
+
+struct StringCacheEntry
+{
+    GGLSurface surface;
+    int rendered_len;
+    StringCacheKey *key;
+    struct StringCacheEntry *prev;
+    struct StringCacheEntry *next;
+};
+
+typedef struct StringCacheEntry StringCacheEntry;
+
+typedef struct 
+{
+    FT_Library ft_library;
+    Hashmap *fonts;
+    pthread_mutex_t mutex;
+} FontData;
+
+static FontData font_data = {
+    .ft_library = NULL,
+    .fonts = NULL,
+    .mutex = PTHREAD_MUTEX_INITIALIZER,
+};
+
+#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
+#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
+
+// 32bit FNV-1a hash algorithm
+// http://isthe.com/chongo/tech/comp/fnv/#FNV-1a
+static const uint32_t FNV_prime = 16777619U;
+static const uint32_t offset_basis = 2166136261U;
+
+static uint32_t fnv_hash(void *data, uint32_t len)
+{
+    uint8_t *d8 = data;
+    uint32_t *d32 = data;
+    uint32_t i, max;
+    uint32_t hash = offset_basis;
+
+    max = len/4;
+
+    // 32 bit data
+    for(i = 0; i < max; ++i)
+    {
+        hash ^= *d32++;
+        hash *= FNV_prime;
+    }
+
+    // last bits
+    for(i *= 4; i < len; ++i)
+    {
+        hash ^= (uint32_t) d8[i];
+        hash *= FNV_prime;
+    }
+    return hash;
+}
+
+static inline uint32_t fnv_hash_add(uint32_t cur_hash, uint32_t word)
+{
+    cur_hash ^= word;
+    cur_hash *= FNV_prime;
+    return cur_hash;
+}
+
+static bool gr_ttf_string_cache_equals(void *keyA, void *keyB)
+{
+    StringCacheKey *a = keyA;
+    StringCacheKey *b = keyB;
+    return a->max_width == b->max_width && strcmp(a->text, b->text) == 0;
+}
+
+static int gr_ttf_string_cache_hash(void *key)
+{
+    StringCacheKey *k = key;
+    return fnv_hash(k->text, strlen(k->text));
+}
+
+static bool gr_ttf_font_cache_equals(void *keyA, void *keyB)
+{
+    TrueTypeFontKey *a = keyA;
+    TrueTypeFontKey *b = keyB;
+    return (a->size == b->size) && (a->dpi == b->dpi) && !strcmp(a->path, b->path);
+}
+
+static int gr_ttf_font_cache_hash(void *key)
+{
+    TrueTypeFontKey *k = key;
+
+    uint32_t hash = fnv_hash(k->path, strlen(k->path));
+    hash = fnv_hash_add(hash, k->size);
+    hash = fnv_hash_add(hash, k->dpi);
+    return hash;
+}
+
+void *gr_ttf_loadFont(const char *filename, int size, int dpi)
+{
+    int error;
+    TrueTypeFont *res = NULL;
+
+    pthread_mutex_lock(&font_data.mutex);
+
+    if(font_data.fonts)
+    {
+        TrueTypeFontKey k = {
+            .size = size,
+            .dpi = dpi,
+            .path = (char*)filename
+        };
+
+        res = hashmapGet(font_data.fonts, &k);
+        if(res)
+        {
+            ++res->refcount;
+            goto exit;
+        }
+    }
+
+    if(!font_data.ft_library)
+    {
+        error = FT_Init_FreeType(&font_data.ft_library);
+        if(error)
+        {
+            fprintf(stderr, "Failed to init libfreetype! %d\n", error);
+            goto exit;
+        }
+    }
+
+    FT_Face face;
+    error = FT_New_Face(font_data.ft_library, filename, 0, &face);
+    if(error)
+    {
+        fprintf(stderr, "Failed to load truetype face %s: %d\n", filename, error);
+        goto exit;
+    }
+
+    error = FT_Set_Char_Size(face, 0, size*16, dpi, dpi);
+    if(error)
+    {
+         fprintf(stderr, "Failed to set truetype face size to %d, dpi %d: %d\n", size, dpi, error);
+         FT_Done_Face(face);
+         goto exit;
+    }
+
+    res = malloc(sizeof(TrueTypeFont));
+    memset(res, 0, sizeof(TrueTypeFont));
+    res->type = FONT_TYPE_TTF;
+    res->size = size;
+    res->dpi = dpi;
+    res->face = face;
+    res->max_height = -1;
+    res->base = -1;
+    res->refcount = 1;
+    res->glyph_cache = hashmapCreate(32, hashmapIntHash, hashmapIntEquals);
+    res->string_cache = hashmapCreate(128, gr_ttf_string_cache_hash, gr_ttf_string_cache_equals);
+    pthread_mutex_init(&res->mutex, 0);
+
+    if(!font_data.fonts)
+        font_data.fonts = hashmapCreate(4, gr_ttf_font_cache_hash, gr_ttf_font_cache_equals);
+
+    TrueTypeFontKey *key = malloc(sizeof(TrueTypeFontKey));
+    memset(key, 0, sizeof(TrueTypeFontKey));
+    key->path = strdup(filename);
+    key->size = size;
+    key->dpi = dpi;
+
+    res->key = key;
+
+    hashmapPut(font_data.fonts, key, res);
+
+exit:
+    pthread_mutex_unlock(&font_data.mutex);
+    return res;
+}
+
+static bool gr_ttf_freeFontCache(void *key, void *value, void *context)
+{
+    TrueTypeCacheEntry *e = value;
+    FT_Done_Glyph((FT_Glyph)e->glyph);
+    free(e);
+    free(key);
+    return true;
+}
+
+static bool gr_ttf_freeStringCache(void *key, void *value, void *context)
+{
+    StringCacheKey *k = key;
+    free(k->text);
+    free(k);
+
+    StringCacheEntry *e = value;
+    free(e->surface.data);
+    free(e);
+    return true;
+}
+
+void gr_ttf_freeFont(void *font)
+{
+    pthread_mutex_lock(&font_data.mutex);
+
+    TrueTypeFont *d = font;
+
+    if(--d->refcount == 0)
+    {
+        hashmapRemove(font_data.fonts, d->key);
+
+        if(hashmapSize(font_data.fonts) == 0)
+        {
+            hashmapFree(font_data.fonts);
+            font_data.fonts = NULL;
+        }
+
+        free(d->key->path);
+        free(d->key);
+
+        FT_Done_Face(d->face);
+        hashmapForEach(d->string_cache, gr_ttf_freeStringCache, NULL);
+        hashmapFree(d->string_cache);
+        hashmapForEach(d->glyph_cache, gr_ttf_freeFontCache, NULL);
+        hashmapFree(d->glyph_cache);
+        pthread_mutex_destroy(&d->mutex);
+        free(d);
+    }
+
+    pthread_mutex_unlock(&font_data.mutex);
+}
+
+static TrueTypeCacheEntry *gr_ttf_glyph_cache_peek(TrueTypeFont *font, int char_index)
+{
+    return hashmapGet(font->glyph_cache, &char_index);
+}
+
+static TrueTypeCacheEntry *gr_ttf_glyph_cache_get(TrueTypeFont *font, int char_index)
+{
+    TrueTypeCacheEntry *res = hashmapGet(font->glyph_cache, &char_index);
+    if(!res)
+    {
+        int error = FT_Load_Glyph(font->face, char_index, FT_LOAD_RENDER);
+        if(error)
+        {
+            fprintf(stderr, "Failed to load glyph idx %d: %d\n", char_index, error);
+            return NULL;
+        }
+
+        FT_BitmapGlyph glyph;
+        error = FT_Get_Glyph(font->face->glyph, (FT_Glyph*)&glyph);
+        if(error)
+        {
+            fprintf(stderr, "Failed to copy glyph %d: %d\n", char_index, error);
+            return NULL;
+        }
+
+        res = malloc(sizeof(TrueTypeCacheEntry));
+        memset(res, 0, sizeof(TrueTypeCacheEntry));
+        res->glyph = glyph;
+        FT_Glyph_Get_CBox((FT_Glyph)glyph, FT_GLYPH_BBOX_PIXELS, &res->bbox);
+
+        int *key = malloc(sizeof(int));
+        *key = char_index;
+
+        hashmapPut(font->glyph_cache, key, res);
+    }
+
+    return res;
+}
+
+static int gr_ttf_copy_glyph_to_surface(GGLSurface *dest, FT_BitmapGlyph glyph, int offX, int offY, int base)
+{
+    int y;
+    uint8_t *src_itr = glyph->bitmap.buffer;
+    uint8_t *dest_itr = dest->data;
+
+    if(glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
+    {
+        fprintf(stderr, "Unsupported pixel mode in FT_BitmapGlyph %d\n", glyph->bitmap.pixel_mode);
+        return -1;
+    }
+
+    dest_itr += (offY + base - glyph->top)*dest->stride + (offX + glyph->left);
+
+    for(y = 0; y < glyph->bitmap.rows; ++y)
+    {
+        memcpy(dest_itr, src_itr, glyph->bitmap.width);
+        src_itr += glyph->bitmap.pitch;
+        dest_itr += dest->stride;
+    }
+    return 0;
+}
+
+static int gr_ttf_render_text(TrueTypeFont *font, GGLSurface *surface, const char *text, int max_width)
+{
+    TrueTypeFont *f = font;
+    TrueTypeCacheEntry *ent;
+    int max_len = 0, total_w = 0;
+    char c;
+    int i, x, diff, char_idx, prev_idx = 0;
+    int height, base;
+    FT_Vector delta;
+    uint8_t *data = NULL;
+    const char *text_itr = text;
+
+    while((c = *text_itr++))
+    {
+        char_idx = FT_Get_Char_Index(f->face, c);
+        ent = gr_ttf_glyph_cache_get(f, char_idx);
+        if(ent)
+        {
+            diff = ent->glyph->root.advance.x >> 16;
+
+            if(FT_HAS_KERNING(f->face) && prev_idx && char_idx)
+            {
+                FT_Get_Kerning(f->face, prev_idx, char_idx, FT_KERNING_DEFAULT, &delta);
+                diff += delta.x >> 6;
+            }
+
+            if(max_width != -1 && total_w + diff > max_width)
+                break;
+
+            total_w += diff;
+        }
+        prev_idx = char_idx;
+        ++max_len;
+    }
+
+    if(font->max_height == -1)
+        gr_ttf_getMaxFontHeight(font);
+
+    if(font->max_height == -1)
+        return -1;
+
+    height = font->max_height;
+
+    data = malloc(total_w*height);
+    memset(data, 0, total_w*height);
+    x = 0;
+    prev_idx = 0;
+
+    surface->version = sizeof(*surface);
+    surface->width = total_w;
+    surface->height = height;
+    surface->stride = total_w;
+    surface->data = (void*)data;
+    surface->format = GGL_PIXEL_FORMAT_A_8;
+
+    for(i = 0; i < max_len; ++i)
+    {
+        char_idx = FT_Get_Char_Index(f->face, text[i]);
+        if(FT_HAS_KERNING(f->face) && prev_idx && char_idx)
+        {
+            FT_Get_Kerning(f->face, prev_idx, char_idx, FT_KERNING_DEFAULT, &delta);
+            x += delta.x >> 6;
+        }
+
+        ent = gr_ttf_glyph_cache_get(f, char_idx);
+        if(ent)
+        {
+            gr_ttf_copy_glyph_to_surface(surface, ent->glyph, x, 0, font->base);
+            x += ent->glyph->root.advance.x >> 16;
+        }
+
+        prev_idx = char_idx;
+    }
+
+    return max_len;
+}
+
+static StringCacheEntry *gr_ttf_string_cache_peek(TrueTypeFont *font, const char *text, int max_width)
+{
+    StringCacheEntry *res;
+    StringCacheKey k = {
+        .text = (char*)text,
+        .max_width = max_width
+    };
+
+    return hashmapGet(font->string_cache, &k);
+}
+
+static StringCacheEntry *gr_ttf_string_cache_get(TrueTypeFont *font, const char *text, int max_width)
+{
+    StringCacheEntry *res;
+    StringCacheKey k = {
+        .text = (char*)text,
+        .max_width = max_width
+    };
+
+    res = hashmapGet(font->string_cache, &k);
+    if(!res)
+    {
+        res = malloc(sizeof(StringCacheEntry));
+        memset(res, 0, sizeof(StringCacheEntry));
+        res->rendered_len = gr_ttf_render_text(font, &res->surface, text, max_width);
+        if(res->rendered_len < 0)
+        {
+            free(res);
+            return NULL;
+        }
+
+        StringCacheKey *new_key = malloc(sizeof(StringCacheKey));
+        memset(new_key, 0, sizeof(StringCacheKey));
+        new_key->max_width = max_width;
+        new_key->text = strdup(text);
+
+        res->key = new_key;
+
+        if(font->string_cache_tail)
+        {
+            res->prev = font->string_cache_tail;
+            res->prev->next = res;
+        }
+        else
+            font->string_cache_head = res;
+        font->string_cache_tail = res;
+
+        hashmapPut(font->string_cache, new_key, res);
+    }
+    else if(res->next)
+    {
+        // move this entry to the tail of the linked list
+        // if it isn't already there
+        if(res->prev)
+            res->prev->next = res->next;
+
+        res->next->prev = res->prev;
+
+        if(!res->prev)
+            font->string_cache_head = res->next;
+
+        res->next = NULL;
+        res->prev = font->string_cache_tail;
+        res->prev->next = res;
+        font->string_cache_tail = res;
+
+        // truncate old entries
+        if(hashmapSize(font->string_cache) >= STRING_CACHE_MAX_ENTRIES)
+        {
+            printf("Truncating string cache entries.\n");
+            int i;
+            StringCacheEntry *ent;
+            for(i = 0; i < STRING_CACHE_TRUNCATE_ENTRIES; ++i)
+            {
+                ent = font->string_cache_head;
+                font->string_cache_head = ent->next;
+                font->string_cache_head->prev = NULL;
+
+                hashmapRemove(font->string_cache, ent->key);
+
+                gr_ttf_freeStringCache(ent->key, ent, NULL);
+            }
+        }
+    }
+    return res;
+}
+
+int gr_ttf_measureEx(const char *s, void *font)
+{
+    TrueTypeFont *f = font;
+    int res = -1;
+
+    pthread_mutex_lock(&f->mutex);
+    StringCacheEntry *e = gr_ttf_string_cache_get(font, s, -1);
+    if(e)
+        res = e->surface.width;
+    pthread_mutex_unlock(&f->mutex);
+
+    return res;
+}
+
+int gr_ttf_maxExW(const char *s, void *font, int max_width)
+{
+    TrueTypeFont *f = font;
+    TrueTypeCacheEntry *ent;
+    int max_len = 0, total_w = 0;
+    char c;
+    int char_idx, prev_idx = 0;
+    FT_Vector delta;
+    StringCacheEntry *e;
+
+    pthread_mutex_lock(&f->mutex);
+
+    e = gr_ttf_string_cache_peek(font, s, max_width);
+    if(e)
+    {
+        max_len = e->rendered_len;
+        pthread_mutex_unlock(&f->mutex);
+        return max_len;
+    }
+
+    for(; (c = *s++); ++max_len)
+    {
+        char_idx = FT_Get_Char_Index(f->face, c);
+        if(FT_HAS_KERNING(f->face) && prev_idx && char_idx)
+        {
+            FT_Get_Kerning(f->face, prev_idx, char_idx, FT_KERNING_DEFAULT, &delta);
+            total_w += delta.x >> 6;
+        }
+        prev_idx = char_idx;
+
+        if(total_w > max_width)
+            break;
+
+        ent = gr_ttf_glyph_cache_get(f, char_idx);
+        if(!ent)
+            continue;
+
+        total_w += ent->glyph->root.advance.x >> 16;
+    }
+    pthread_mutex_unlock(&f->mutex);
+    return max_len > 0 ? max_len - 1 : 0;
+}
+
+int gr_ttf_textExWH(void *context, int x, int y, const char *s, void *pFont, int max_width, int max_height)
+{
+    GGLContext *gl = context;
+    TrueTypeFont *font = pFont;
+
+    // not actualy max width, but max_width + x
+    if(max_width != -1)
+    {
+        max_width -= x;
+        if(max_width <= 0)
+            return 0;
+    }
+
+    pthread_mutex_lock(&font->mutex);
+
+    StringCacheEntry *e = gr_ttf_string_cache_get(font, s, max_width);
+    if(!e)
+    {
+        pthread_mutex_unlock(&font->mutex);
+        return -1;
+    }
+
+    int y_bottom = y + e->surface.height;
+    int res = e->rendered_len;
+
+    if(max_height != -1 && max_height < y_bottom)
+    {
+        y_bottom = max_height;
+        if(y_bottom <= y)
+        {
+            pthread_mutex_unlock(&font->mutex);
+            return 0;
+        }
+    }
+
+    gl->bindTexture(gl, &e->surface);
+    gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
+    gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+    gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+    gl->enable(gl, GGL_TEXTURE_2D);
+
+    gl->texCoord2i(gl, -x, -y);
+    gl->recti(gl, x, y, x + e->surface.width, y_bottom);
+
+    pthread_mutex_unlock(&font->mutex);
+    return res;
+}
+
+int gr_ttf_getMaxFontHeight(void *font)
+{
+    int res;
+    TrueTypeFont *f = font;
+
+    pthread_mutex_lock(&f->mutex);
+
+    if(f->max_height == -1)
+    {
+        char c;
+        int char_idx;
+        int error;
+        FT_Glyph glyph;
+        FT_BBox bbox;
+        FT_BBox bbox_glyph;
+        TrueTypeCacheEntry *ent;
+
+        bbox.yMin = bbox_glyph.yMin = LONG_MAX;
+        bbox.yMax = bbox_glyph.yMax = LONG_MIN;
+
+        for(c = '!'; c <= '~'; ++c)
+        {
+            char_idx = FT_Get_Char_Index(f->face, c);
+            ent = gr_ttf_glyph_cache_peek(f, char_idx);
+            if(ent)
+            {
+                bbox.yMin = MIN(bbox.yMin, ent->bbox.yMin);
+                bbox.yMax = MAX(bbox.yMax, ent->bbox.yMax);
+            }
+            else
+            {
+                error = FT_Load_Glyph(f->face, char_idx, 0);
+                if(error)
+                    continue;
+
+                error = FT_Get_Glyph(f->face->glyph, &glyph);
+                if(error)
+                    continue;
+
+                FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox_glyph);
+                bbox.yMin = MIN(bbox.yMin, bbox_glyph.yMin);
+                bbox.yMax = MAX(bbox.yMax, bbox_glyph.yMax);
+
+                FT_Done_Glyph(glyph);
+            }
+        }
+
+        if(bbox.yMin > bbox.yMax)
+            bbox.yMin = bbox.yMax = 0;
+
+        f->max_height = bbox.yMax - bbox.yMin;
+        f->base = bbox.yMax;
+
+        // FIXME: twrp fonts have some padding on top, I'll add it here
+        // Should be fixed in the themes
+        f->max_height += f->size / 4;
+        f->base += f->size / 4;
+    }
+
+    res = f->max_height;
+
+    pthread_mutex_unlock(&f->mutex);
+    return res;
+}
+
+static bool gr_ttf_dump_stats_count_string_cache(void *key, void *value, void *context)
+{
+    int *string_cache_size = context;
+    StringCacheEntry *e = value;
+    *string_cache_size += e->surface.height*e->surface.width + sizeof(StringCacheEntry);
+    return true;
+}
+
+static bool gr_ttf_dump_stats_font(void *key, void *value, void *context)
+{
+    TrueTypeFontKey *k = key;
+    TrueTypeFont *f = value;
+    int *total_string_cache_size = context;
+    int string_cache_size = 0;
+
+    pthread_mutex_lock(&f->mutex);
+
+    hashmapForEach(f->string_cache, gr_ttf_dump_stats_count_string_cache, &string_cache_size);
+
+    printf("  Font %s (size %d, dpi %d):\n"
+            "    refcount: %d\n"
+            "    max_height: %d\n"
+            "    base: %d\n"
+            "    glyph_cache: %d entries\n"
+            "    string_cache: %d entries (%.2f kB)\n",
+            k->path, k->size, k->dpi,
+            f->refcount, f->max_height, f->base,
+            hashmapSize(f->glyph_cache),
+            hashmapSize(f->string_cache), ((double)string_cache_size)/1024);
+
+    pthread_mutex_unlock(&f->mutex);
+
+    *total_string_cache_size += string_cache_size;
+    return true;
+}
+
+void gr_ttf_dump_stats(void)
+{
+    pthread_mutex_lock(&font_data.mutex);
+
+    printf("TrueType fonts system stats: ");
+    if(!font_data.fonts)
+        printf("no truetype fonts loaded.\n");
+    else
+    {
+        int total_string_cache_size = 0;
+        printf("%d fonts loaded.\n", hashmapSize(font_data.fonts));
+        hashmapForEach(font_data.fonts, gr_ttf_dump_stats_font, &total_string_cache_size);
+        printf("  Total string cache size: %.2f kB\n", ((double)total_string_cache_size)/1024);
+    }
+
+    pthread_mutex_unlock(&font_data.mutex);
+}
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 1526a9f..07962c5 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -40,6 +40,7 @@
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2fs.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_profile.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_uuid.so
+RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libpng.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/liblog.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libm.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libstdc++.so
@@ -122,6 +123,9 @@
 ifneq ($(wildcard system/core/reboot/Android.mk),)
     RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/reboot
 endif
+ifneq ($(TW_DISABLE_TTF), true)
+    RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libft2.so
+endif
 
 TWRP_AUTOGEN := $(intermediates)/teamwin