[Libreoffice-commits] core.git: Branch 'feature/android-viewer' - android/experimental

Tomaž Vajngerl tomaz.vajngerl at collabora.com
Mon Jun 16 07:32:20 PDT 2014


 android/experimental/LOAndroid2/.gitignore                                                             |    4 
 android/experimental/LOAndroid2/.idea/.name                                                            |    1 
 android/experimental/LOAndroid2/.idea/compiler.xml                                                     |   23 
 android/experimental/LOAndroid2/.idea/copyright/profiles_settings.xml                                  |    3 
 android/experimental/LOAndroid2/.idea/encodings.xml                                                    |    5 
 android/experimental/LOAndroid2/.idea/gradle.xml                                                       |   18 
 android/experimental/LOAndroid2/.idea/libraries/appcompat_v7_19_1_0.xml                                |   10 
 android/experimental/LOAndroid2/.idea/libraries/support_v4_19_1_0.xml                                  |   11 
 android/experimental/LOAndroid2/.idea/misc.xml                                                         |   41 
 android/experimental/LOAndroid2/.idea/modules.xml                                                      |   10 
 android/experimental/LOAndroid2/.idea/scopes/scope_settings.xml                                        |    5 
 android/experimental/LOAndroid2/.idea/vcs.xml                                                          |    7 
 android/experimental/LOAndroid2/LOAndroid.iml                                                          |   12 
 android/experimental/LOAndroid2/app/.gitignore                                                         |    1 
 android/experimental/LOAndroid2/app/app.iml                                                            |   68 
 android/experimental/LOAndroid2/app/build.gradle                                                       |   24 
 android/experimental/LOAndroid2/app/proguard-rules.txt                                                 |   17 
 android/experimental/LOAndroid2/app/src/main/AndroidManifest.xml                                       |   24 
 android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOEvent.java                         |   67 
 android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitShell.java                      |  118 +
 android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitThread.java                     |  147 +
 android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LibreOfficeMainActivity.java         |   94 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/GeckoEventListener.java            |   44 
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/BufferedCairoImage.java        |  105 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoGLInfo.java               |   67 
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoImage.java                |   58 
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoUtils.java                |   85 
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CheckerboardImage.java         |  170 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/FloatSize.java                 |   88 
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java  |  505 +++++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/InputConnectionHandler.java    |   15 
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/IntSize.java                   |  103 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/Layer.java                     |  213 ++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerClient.java               |   81 
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerController.java           |  525 +++++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerRenderer.java             |  508 +++++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerView.java                 |  215 ++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/MultiTileLayer.java            |  284 +++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/NinePatchTileLayer.java        |  124 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/PanningPerfAPI.java            |  125 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/PointUtils.java                |   96 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/RectUtils.java                 |  128 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ScrollbarLayer.java            |  229 ++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/SingleTileLayer.java           |  100 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TextLayer.java                 |  117 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TextureGenerator.java          |   73 
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TextureReaper.java             |   75 
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TileLayer.java                 |  250 ++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewportMetrics.java           |  322 +++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/WidgetTileLayer.java           |  129 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/Axis.java                       |  271 ++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/PanZoomController.java          |  929 ++++++++++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java |  332 +++
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java    |  140 +
 android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/util/FloatUtils.java               |   43 
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/base.png                                |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/calc.png                                |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/draw.png                                |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/dummy_page.png                          |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/ic_launcher.png                         |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/ic_status_logo.png                      |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/impress.png                             |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/lo_icon.png                             |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/main.png                                |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/math.png                                |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-hdpi/startcenter.png                         |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/background.png                          |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/base.png                                |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/calc.png                                |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/docu.png                                |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/draw.png                                |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/ic_launcher.png                         |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/ic_status_logo.png                      |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/impress.png                             |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/lo_icon.png                             |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/shadow.png                              |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-mdpi/writer.png                              |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-xhdpi/base.png                               |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-xhdpi/calc.png                               |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-xhdpi/draw.png                               |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-xhdpi/ic_launcher.png                        |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-xhdpi/ic_status_logo.png                     |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-xhdpi/impress.png                            |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-xhdpi/writer.png                             |binary
 android/experimental/LOAndroid2/app/src/main/res/drawable-xxhdpi/ic_launcher.png                       |binary
 android/experimental/LOAndroid2/app/src/main/res/layout/activity_main.xml                              |   15 
 android/experimental/LOAndroid2/app/src/main/res/menu/main.xml                                         |    9 
 android/experimental/LOAndroid2/app/src/main/res/values-w820dp/dimens.xml                              |    6 
 android/experimental/LOAndroid2/app/src/main/res/values/colors.xml                                     |   95 +
 android/experimental/LOAndroid2/app/src/main/res/values/dimens.xml                                     |    5 
 android/experimental/LOAndroid2/app/src/main/res/values/strings.xml                                    |    8 
 android/experimental/LOAndroid2/app/src/main/res/values/styles.xml                                     |    8 
 android/experimental/LOAndroid2/build.gradle                                                           |   16 
 android/experimental/LOAndroid2/gradle.properties                                                      |   18 
 android/experimental/LOAndroid2/gradle/wrapper/gradle-wrapper.jar                                      |binary
 android/experimental/LOAndroid2/gradle/wrapper/gradle-wrapper.properties                               |    6 
 android/experimental/LOAndroid2/gradlew                                                                |  164 +
 android/experimental/LOAndroid2/gradlew.bat                                                            |   90 
 android/experimental/LOAndroid2/settings.gradle                                                        |    1 
 99 files changed, 7700 insertions(+)

New commits:
commit c0ac526d8ab1fe2988009e3aa0bccad96b48016c
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Mon Jun 16 16:23:39 2014 +0200

    LOAndroid2: initial import of older Fennec version with LO changes
    
    rebase on mozilla-central tag RELEASE_BASE_20120531
    add LOEvent, LOThread, some LO icons
    
    Change-Id: I0c3aba6d9715c60e32d8daa2002b4961eef476f0

diff --git a/android/experimental/LOAndroid2/.gitignore b/android/experimental/LOAndroid2/.gitignore
new file mode 100644
index 0000000..d6bfc95
--- /dev/null
+++ b/android/experimental/LOAndroid2/.gitignore
@@ -0,0 +1,4 @@
+.gradle
+/local.properties
+/.idea/workspace.xml
+.DS_Store
diff --git a/android/experimental/LOAndroid2/.idea/.name b/android/experimental/LOAndroid2/.idea/.name
new file mode 100644
index 0000000..3300c56
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/.name
@@ -0,0 +1 @@
+LOAndroid
\ No newline at end of file
diff --git a/android/experimental/LOAndroid2/.idea/compiler.xml b/android/experimental/LOAndroid2/.idea/compiler.xml
new file mode 100644
index 0000000..217af47
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/compiler.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <option name="DEFAULT_COMPILER" value="Javac" />
+    <resourceExtensions />
+    <wildcardResourcePatterns>
+      <entry name="!?*.java" />
+      <entry name="!?*.form" />
+      <entry name="!?*.class" />
+      <entry name="!?*.groovy" />
+      <entry name="!?*.scala" />
+      <entry name="!?*.flex" />
+      <entry name="!?*.kt" />
+      <entry name="!?*.clj" />
+    </wildcardResourcePatterns>
+    <annotationProcessing>
+      <profile default="true" name="Default" enabled="false">
+        <processorPath useClasspath="true" />
+      </profile>
+    </annotationProcessing>
+  </component>
+</project>
+
diff --git a/android/experimental/LOAndroid2/.idea/copyright/profiles_settings.xml b/android/experimental/LOAndroid2/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..e7bedf3
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+<component name="CopyrightManager">
+  <settings default="" />
+</component>
\ No newline at end of file
diff --git a/android/experimental/LOAndroid2/.idea/encodings.xml b/android/experimental/LOAndroid2/.idea/encodings.xml
new file mode 100644
index 0000000..e206d70
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/encodings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
+</project>
+
diff --git a/android/experimental/LOAndroid2/.idea/gradle.xml b/android/experimental/LOAndroid2/.idea/gradle.xml
new file mode 100644
index 0000000..736c7b5
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/gradle.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+          </set>
+        </option>
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>
+
diff --git a/android/experimental/LOAndroid2/.idea/libraries/appcompat_v7_19_1_0.xml b/android/experimental/LOAndroid2/.idea/libraries/appcompat_v7_19_1_0.xml
new file mode 100644
index 0000000..7efbfdf
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/libraries/appcompat_v7_19_1_0.xml
@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="appcompat-v7-19.1.0">
+    <CLASSES>
+      <root url="jar://$PROJECT_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/19.1.0/classes.jar!/" />
+      <root url="file://$PROJECT_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/19.1.0/res" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>
\ No newline at end of file
diff --git a/android/experimental/LOAndroid2/.idea/libraries/support_v4_19_1_0.xml b/android/experimental/LOAndroid2/.idea/libraries/support_v4_19_1_0.xml
new file mode 100644
index 0000000..1ca1ac6
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/libraries/support_v4_19_1_0.xml
@@ -0,0 +1,11 @@
+<component name="libraryTable">
+  <library name="support-v4-19.1.0">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/Programs/android-sdk-linux/extras/android/m2repository/com/android/support/support-v4/19.1.0/support-v4-19.1.0.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="jar://$USER_HOME$/Programs/android-sdk-linux/extras/android/m2repository/com/android/support/support-v4/19.1.0/support-v4-19.1.0-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>
\ No newline at end of file
diff --git a/android/experimental/LOAndroid2/.idea/misc.xml b/android/experimental/LOAndroid2/.idea/misc.xml
new file mode 100644
index 0000000..7f0862a
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/misc.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="EntryPointsManager">
+    <entry_points version="2.0" />
+  </component>
+  <component name="ProjectInspectionProfilesVisibleTreeState">
+    <entry key="Project Default">
+      <profile-state>
+        <expanded-state>
+          <State>
+            <id />
+          </State>
+        </expanded-state>
+        <selected-state>
+          <State>
+            <id>Abstraction issues</id>
+          </State>
+        </selected-state>
+      </profile-state>
+    </entry>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="masterDetails">
+    <states>
+      <state key="ScopeChooserConfigurable.UI">
+        <settings>
+          <splitter-proportions>
+            <option name="proportions">
+              <list>
+                <option value="0.2" />
+              </list>
+            </option>
+          </splitter-proportions>
+        </settings>
+      </state>
+    </states>
+  </component>
+</project>
+
diff --git a/android/experimental/LOAndroid2/.idea/modules.xml b/android/experimental/LOAndroid2/.idea/modules.xml
new file mode 100644
index 0000000..f08135d
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/modules.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/LOAndroid.iml" filepath="$PROJECT_DIR$/LOAndroid.iml" />
+      <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
+    </modules>
+  </component>
+</project>
+
diff --git a/android/experimental/LOAndroid2/.idea/scopes/scope_settings.xml b/android/experimental/LOAndroid2/.idea/scopes/scope_settings.xml
new file mode 100644
index 0000000..922003b
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+<component name="DependencyValidationManager">
+  <state>
+    <option name="SKIP_IMPORT_STATEMENTS" value="false" />
+  </state>
+</component>
\ No newline at end of file
diff --git a/android/experimental/LOAndroid2/.idea/vcs.xml b/android/experimental/LOAndroid2/.idea/vcs.xml
new file mode 100644
index 0000000..def6a6a
--- /dev/null
+++ b/android/experimental/LOAndroid2/.idea/vcs.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="" />
+  </component>
+</project>
+
diff --git a/android/experimental/LOAndroid2/LOAndroid.iml b/android/experimental/LOAndroid2/LOAndroid.iml
new file mode 100644
index 0000000..cd51bb4
--- /dev/null
+++ b/android/experimental/LOAndroid2/LOAndroid.iml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+    </content>
+    <orderEntry type="jdk" jdkName="1.7" jdkType="JavaSDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
+
diff --git a/android/experimental/LOAndroid2/app/.gitignore b/android/experimental/LOAndroid2/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/android/experimental/LOAndroid2/app/app.iml b/android/experimental/LOAndroid2/app/app.iml
new file mode 100644
index 0000000..e89240b
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/app.iml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="LOAndroid" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="android-gradle" name="Android-Gradle">
+      <configuration>
+        <option name="GRADLE_PROJECT_PATH" value=":app" />
+      </configuration>
+    </facet>
+    <facet type="android" name="Android">
+      <configuration>
+        <option name="SELECTED_BUILD_VARIANT" value="debug" />
+        <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
+        <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugJava" />
+        <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" />
+        <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
+        <option name="ALLOW_USER_CONFIGURATION" value="false" />
+        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
+        <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
+        <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
+        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/test/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/test/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/test/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/test/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/test/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/assets" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates" />
+      <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
+    </content>
+    <orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" exported="" name="appcompat-v7-19.1.0" level="project" />
+    <orderEntry type="library" exported="" name="support-v4-19.1.0" level="project" />
+  </component>
+</module>
+
diff --git a/android/experimental/LOAndroid2/app/build.gradle b/android/experimental/LOAndroid2/app/build.gradle
new file mode 100644
index 0000000..7e98dd4c
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/build.gradle
@@ -0,0 +1,24 @@
+apply plugin: 'android'
+
+android {
+    compileSdkVersion 19
+    buildToolsVersion "19.1.0"
+
+    defaultConfig {
+        minSdkVersion 15
+        targetSdkVersion 19
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            runProguard false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+        }
+    }
+}
+
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    compile 'com.android.support:appcompat-v7:19.+'
+}
diff --git a/android/experimental/LOAndroid2/app/proguard-rules.txt b/android/experimental/LOAndroid2/app/proguard-rules.txt
new file mode 100644
index 0000000..0b0be28
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/proguard-rules.txt
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/quikee/Programs/android-sdk-linux/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
\ No newline at end of file
diff --git a/android/experimental/LOAndroid2/app/src/main/AndroidManifest.xml b/android/experimental/LOAndroid2/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..aef4bb7
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.libreoffice" >
+
+    <!-- App requires OpenGL ES 2.0 -->
+    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/main"
+        android:label="@string/app_name"
+        android:hardwareAccelerated="true"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="org.libreoffice.LibreOfficeMainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOEvent.java b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOEvent.java
new file mode 100644
index 0000000..a539669
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOEvent.java
@@ -0,0 +1,67 @@
+package org.libreoffice;
+
+import android.graphics.Rect;
+import android.util.Log;
+
+import org.mozilla.gecko.gfx.IntSize;
+import org.mozilla.gecko.gfx.ViewportMetrics;
+
+public class LOEvent {
+
+    public static final int SIZE_CHANGED = 1;
+    public static final int TILE_SIZE = 2;
+    public static final int VIEWPORT = 3;
+    public static final int DRAW = 4;
+
+    private ViewportMetrics mViewportMetrics;
+
+    public int mType;
+    private String mTypeString;
+
+    ViewportMetrics viewportMetrics;
+
+    public LOEvent(int type, int width, int height, int widthPixels, int heightPixels) {
+        mType = type;
+        mTypeString = "Size Changed";
+    }
+
+    public LOEvent(int type, IntSize tileSize) {
+        mType = type;
+        mTypeString = "Tile size";
+    }
+
+    public LOEvent(int type, ViewportMetrics viewportMetrics) {
+        mType = type;
+        mTypeString = "Viewport";
+        mViewportMetrics = viewportMetrics;
+    }
+
+    public LOEvent(int type, Rect rect) {
+        mType = type;
+        mTypeString = "Draw";
+    }
+
+    public static LOEvent draw(Rect rect) {
+        return new LOEvent(DRAW, rect);
+    }
+
+    public static LOEvent sizeChanged(int width, int height, int widthPixels, int heightPixels) {
+        return new LOEvent(SIZE_CHANGED, width, height, widthPixels, heightPixels);
+    }
+
+    public static LOEvent tileSize(IntSize tileSize) {
+        return new LOEvent(TILE_SIZE, tileSize);
+    }
+
+    public static LOEvent viewport(ViewportMetrics viewportMetrics) {
+        return new LOEvent(VIEWPORT, viewportMetrics);
+    }
+
+    public String getTypeString() {
+        return mTypeString;
+    }
+
+    public ViewportMetrics getViewport() {
+        return mViewportMetrics;
+    }
+}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitShell.java b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitShell.java
new file mode 100644
index 0000000..69b634c
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitShell.java
@@ -0,0 +1,118 @@
+package org.libreoffice;
+
+
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import org.mozilla.gecko.gfx.GeckoSoftwareLayerClient;
+import org.mozilla.gecko.gfx.IntSize;
+import org.mozilla.gecko.gfx.LayerController;
+import org.mozilla.gecko.gfx.LayerView;
+
+import java.nio.ByteBuffer;
+
+public class LOKitShell {
+    private static final String LOGTAG = LOKitShell.class.getSimpleName();
+
+    public static int getDpi() {
+        return 96;
+    }
+
+    public static int getScreenDepth() {
+        return 24;
+    }
+
+    public static float computeRenderIntegrity() {
+        return 0.0f;
+    }
+
+    public static ByteBuffer allocateDirectBuffer(int size) {
+        if (size <= 0) {
+            throw new IllegalArgumentException("Invalid size " + size);
+        }
+
+        ByteBuffer directBuffer = ByteBuffer.allocateDirect(size);
+        //ByteBuffer directBuffer = nativeAllocateDirectBuffer(size);
+        if (directBuffer == null) {
+            throw new OutOfMemoryError("allocateDirectBuffer() returned null");
+        } else if (!directBuffer.isDirect()) {
+            throw new AssertionError("allocateDirectBuffer() did not return a direct buffer");
+        }
+
+        return directBuffer;
+    }
+
+
+    public static void freeDirectBuffer(ByteBuffer buffer) {
+        if (buffer == null) {
+            return;
+        }
+
+        if (!buffer.isDirect()) {
+            throw new IllegalArgumentException("buffer must be direct");
+        }
+        //nativeFreeDirectBuffer(buffer);
+        return ;
+    }
+
+    public static void bindWidgetTexture() {
+    }
+
+    public static void sendEvent(LOEvent event) {
+        Log.i(LOGTAG, "Event: " + event.getTypeString());
+    }
+
+    public static void runGecko(String apkPath, String args, String url, boolean restoreSession) {
+        // run gecko -- it will spawn its own thread
+        // GeckoAppShell.nativeInit();
+
+        Log.i(LOGTAG, "post native init");
+
+        // Tell Gecko where the target byte buffer is for rendering
+        //GeckoAppShell.setSoftwareLayerClient(GeckoApp.mAppContext.getSoftwareLayerClient());
+
+        Log.i(LOGTAG, "setSoftwareLayerClient called");
+
+        // First argument is the .apk path
+        String combinedArgs = apkPath + " -greomni " + apkPath;
+        if (args != null)
+            combinedArgs += " " + args;
+        if (url != null)
+            combinedArgs += " -remote " + url;
+        if (restoreSession)
+            combinedArgs += " -restoresession";
+
+        DisplayMetrics metrics = new DisplayMetrics();
+        LibreOfficeMainActivity.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        combinedArgs += " -width " + metrics.widthPixels + " -height " + metrics.heightPixels;
+
+        LibreOfficeMainActivity.mAppContext.runOnUiThread(new Runnable() {
+            public void run() {
+                geckoLoaded();
+            }
+        });
+
+        //LOKitShell.nativeRun(combinedArgs);
+    }
+
+    // Called on the UI thread after Gecko loads.
+    private static void geckoLoaded() {
+        /*final LayerController layerController = LibreOfficeMainActivity.mAppContext.getLayerController();
+        LayerView v = layerController.getView();
+        mInputConnection = GeckoInputConnection.create(v);
+        v.setInputConnectionHandler(mInputConnection);
+
+        layerController.setOnTouchListener(new View.OnTouchListener() {
+            public boolean onTouch(View view, MotionEvent event) {
+                if (event == null)
+                    return true;
+                GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
+                return true;
+            }
+        });
+
+        layerController.notifyLayerClientOfGeometryChange();*/
+    }
+}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitThread.java
new file mode 100644
index 0000000..37bb51c
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitThread.java
@@ -0,0 +1,147 @@
+package org.libreoffice;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.JsonWriter;
+
+import org.mozilla.gecko.gfx.ViewportMetrics;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ShortBuffer;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class LOKitThread extends Thread {
+    private static final String LOGTAG = "GeckoThread";
+
+    public ConcurrentLinkedQueue<LOEvent> gEvents = new ConcurrentLinkedQueue<LOEvent>();
+    private ViewportMetrics mViewportMetrics;
+    private Random rand = new Random();
+
+    LOKitThread() {
+    }
+
+    private void draw() throws InterruptedException {
+        final LibreOfficeMainActivity application = LibreOfficeMainActivity.mAppContext;
+
+        Bitmap bitmap = application.getSoftwareLayerClient().getLayerController().getDrawable16("dummy_page");
+        bitmap  = convert(bitmap, Bitmap.Config.RGB_565);
+
+        application.getSoftwareLayerClient().beginDrawing(bitmap.getWidth(), bitmap.getHeight());
+        //application.getSoftwareLayerClient().beginDrawing(500,500);
+
+        ByteBuffer buffer = application.getSoftwareLayerClient().getBuffer();
+        bitmap.copyPixelsToBuffer(buffer.asIntBuffer());
+
+        /*short mainColor16 = convertTo16Bit(rand.nextInt());
+
+        short[] mainPattern = new short[500];
+        Arrays.fill(mainPattern, mainColor16);
+
+        buffer.rewind();
+        ShortBuffer shortBuffer = buffer.asShortBuffer();
+        for (int i = 0; i < 500; i++) {
+            shortBuffer.put(mainPattern);
+        }*/
+
+        StringWriter stringWriter = new StringWriter();
+
+        try {
+            JsonWriter writer = new JsonWriter(stringWriter);
+            writer.beginObject();
+            if (mViewportMetrics == null) {
+                writer.name("x").value(0);
+                writer.name("y").value(0);
+                writer.name("width").value(bitmap.getWidth());
+                writer.name("height").value(bitmap.getHeight());
+                writer.name("pageWidth").value(1000);
+                writer.name("pageHeight").value(5000);
+                writer.name("offsetX").value(0);
+                writer.name("offsetY").value(0);
+                writer.name("zoom").value(1.0);
+                writer.name("allowZoom").value(true);
+            } else {
+                writer.name("x").value(mViewportMetrics.getOrigin().x);
+                writer.name("y").value(mViewportMetrics.getOrigin().y);
+                writer.name("width").value(mViewportMetrics.getSize().width);
+                writer.name("height").value(mViewportMetrics.getSize().height);
+                writer.name("pageWidth").value(mViewportMetrics.getPageSize().width);
+                writer.name("pageHeight").value(mViewportMetrics.getPageSize().height);
+                writer.name("offsetX").value(mViewportMetrics.getViewportOffset().x);
+                writer.name("offsetY").value(mViewportMetrics.getViewportOffset().y);
+                writer.name("zoom").value(mViewportMetrics.getZoomFactor());
+                writer.name("allowZoom").value(mViewportMetrics.getAllowZoom());
+            }
+            writer.name("backgroundColor").value("rgb(255,255,255)");
+            writer.endObject();
+            writer.close();
+        } catch (IOException ex) {
+        }
+
+        application.getSoftwareLayerClient().endDrawing(0, 0, bitmap.getWidth(), bitmap.getHeight(), stringWriter.toString(), false);
+        //application.getSoftwareLayerClient().endDrawing(0, 0, 500, 500, stringWriter.toString(), false);
+        application.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                application.getSoftwareLayerClient().handleMessage("Viewport:UpdateLater", null);
+            }
+        });
+
+    }
+
+    private short convertTo16Bit(int color) {
+        int r = Color.red(color) >> 3, g = Color.green(color) >> 2, b = Color.blue(color) >> 3;
+        int c = ((r << 11) | (g << 5) | b);
+        // Swap endianness.
+        return (short) ((c >> 8) | ((c & 0xff) << 8));
+    }
+
+    private Bitmap convert(Bitmap bitmap, Bitmap.Config config) {
+        Bitmap convertedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), config);
+        Canvas canvas = new Canvas(convertedBitmap);
+        Paint paint = new Paint();
+        paint.setColor(Color.BLACK);
+        canvas.drawBitmap(bitmap, 0, 0, paint);
+        return convertedBitmap;
+    }
+
+
+    public void run() {
+        try {
+            boolean drawn = false;
+            while (true) {
+
+                if (!gEvents.isEmpty()) {
+                    processEvent(gEvents.poll());
+                } else {
+                    if(!drawn) {
+                        draw();
+                        drawn = true;
+                    }
+                    Thread.sleep(100L);
+                }
+            }
+        } catch (InterruptedException ex) {
+        }
+    }
+
+    private void processEvent(LOEvent event) throws InterruptedException {
+        switch (event.mType) {
+            case LOEvent.VIEWPORT:
+                mViewportMetrics = event.getViewport();
+                break;
+            case LOEvent.DRAW:
+                draw();
+                break;
+            case LOEvent.SIZE_CHANGED:
+                break;
+        }
+    }
+
+
+}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LibreOfficeMainActivity.java b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LibreOfficeMainActivity.java
new file mode 100644
index 0000000..a4fdf03
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LibreOfficeMainActivity.java
@@ -0,0 +1,94 @@
+package org.libreoffice;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import org.mozilla.gecko.gfx.GeckoSoftwareLayerClient;
+import org.mozilla.gecko.gfx.LayerController;
+import org.mozilla.gecko.gfx.LayerView;
+
+public class LibreOfficeMainActivity extends Activity {
+
+    private static final String LOGTAG = "LibreOfficeMainActivity";
+
+    private LinearLayout mMainLayout;
+    private RelativeLayout mGeckoLayout;
+    private static LayerController mLayerController;
+    private static GeckoSoftwareLayerClient mSoftwareLayerClient;
+    private static LOKitThread sLOKitThread;
+
+    public static LibreOfficeMainActivity mAppContext;
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle action bar item clicks here. The action bar will
+        // automatically handle clicks on the Home/Up button, so long
+        // as you specify a parent activity in AndroidManifest.xml.
+        int id = item.getItemId();
+        if (id == R.id.action_settings) {
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    public DisplayMetrics getDisplayMetrics() {
+        DisplayMetrics metrics = new DisplayMetrics();
+        getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        return metrics;
+    }
+
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        mAppContext = this;
+
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - onCreate");
+
+        setContentView(R.layout.activity_main);
+
+        // setup gecko layout
+        mGeckoLayout = (RelativeLayout) findViewById(R.id.gecko_layout);
+        mMainLayout = (LinearLayout) findViewById(R.id.main_layout);
+
+
+        if (mLayerController == null) {
+            mLayerController = new LayerController(this);
+            mSoftwareLayerClient = new GeckoSoftwareLayerClient(this);
+            mLayerController.setLayerClient(mSoftwareLayerClient);
+            mGeckoLayout.addView(mLayerController.getView(), 0);
+        }
+
+        mLayerController.notifyLayerClientOfGeometryChange();
+
+        sLOKitThread = new LOKitThread();
+        sLOKitThread.start();
+
+
+        Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - UI almost up");
+    }
+
+    public static GeckoSoftwareLayerClient getSoftwareLayerClient() {
+        return mSoftwareLayerClient;
+    }
+}
\ No newline at end of file
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/GeckoEventListener.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/GeckoEventListener.java
new file mode 100644
index 0000000..670513f
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/GeckoEventListener.java
@@ -0,0 +1,44 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sriram Ramasubramanian <sriram at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+import org.json.JSONObject;
+
+public interface GeckoEventListener {
+    public void handleMessage(String event, JSONObject message);
+}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/BufferedCairoImage.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/BufferedCairoImage.java
new file mode 100644
index 0000000..b6c3977
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/BufferedCairoImage.java
@@ -0,0 +1,105 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import android.graphics.Bitmap;
+
+import org.libreoffice.LOKitShell;
+
+import java.nio.ByteBuffer;
+
+//import org.mozilla.gecko.GeckoAppShell;
+
+/**
+ * A Cairo image that simply saves a buffer of pixel data.
+ */
+public class BufferedCairoImage extends CairoImage {
+    private ByteBuffer mBuffer;
+    private IntSize mSize;
+    private int mFormat;
+    private boolean mNeedToFreeBuffer = false;
+
+    /**
+     * Creates a buffered Cairo image from a byte buffer.
+     */
+    public BufferedCairoImage(ByteBuffer inBuffer, int inWidth, int inHeight, int inFormat) {
+        mBuffer = inBuffer;
+        mSize = new IntSize(inWidth, inHeight);
+        mFormat = inFormat;
+    }
+
+    /**
+     * Creates a buffered Cairo image from an Android bitmap.
+     */
+    public BufferedCairoImage(Bitmap bitmap) {
+        mFormat = CairoUtils.bitmapConfigToCairoFormat(bitmap.getConfig());
+        mSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
+        mNeedToFreeBuffer = true;
+        // XXX Why is this * 4? Shouldn't it depend on mFormat?
+        mBuffer = /*GeckoAppShell*/LOKitShell.allocateDirectBuffer(mSize.getArea() * 4);
+
+        bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            if (mNeedToFreeBuffer && mBuffer != null)
+                /*GeckoAppShell*/ LOKitShell.freeDirectBuffer(mBuffer);
+            mNeedToFreeBuffer = false;
+            mBuffer = null;
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public ByteBuffer getBuffer() {
+        return mBuffer;
+    }
+
+    @Override
+    public IntSize getSize() {
+        return mSize;
+    }
+
+    @Override
+    public int getFormat() {
+        return mFormat;
+    }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoGLInfo.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoGLInfo.java
new file mode 100644
index 0000000..16417e1
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoGLInfo.java
@@ -0,0 +1,67 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import javax.microedition.khronos.opengles.GL10;
+
+/** Information needed to render Cairo bitmaps using OpenGL ES. */
+public class CairoGLInfo {
+    public final int internalFormat;
+    public final int format;
+    public final int type;
+
+    public CairoGLInfo(int cairoFormat) {
+        switch (cairoFormat) {
+        case CairoImage.FORMAT_ARGB32:
+            internalFormat = format = GL10.GL_RGBA; type = GL10.GL_UNSIGNED_BYTE;
+            break;
+        case CairoImage.FORMAT_RGB24:
+            internalFormat = format = GL10.GL_RGB; type = GL10.GL_UNSIGNED_BYTE;
+            break;
+        case CairoImage.FORMAT_RGB16_565:
+            internalFormat = format = GL10.GL_RGB; type = GL10.GL_UNSIGNED_SHORT_5_6_5;
+            break;
+        case CairoImage.FORMAT_A8:
+        case CairoImage.FORMAT_A1:
+            throw new RuntimeException("Cairo FORMAT_A1 and FORMAT_A8 unsupported");
+        default:
+            throw new RuntimeException("Unknown Cairo format");
+        }
+    }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoImage.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoImage.java
new file mode 100644
index 0000000..06c389d
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoImage.java
@@ -0,0 +1,58 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import java.nio.ByteBuffer;
+
+/*
+ * A bitmap with pixel data in one of the formats that Cairo understands.
+ */
+public abstract class CairoImage {
+    public abstract ByteBuffer getBuffer();
+
+    public abstract IntSize getSize();
+    public abstract int getFormat();
+
+    public static final int FORMAT_INVALID = -1;
+    public static final int FORMAT_ARGB32 = 0;
+    public static final int FORMAT_RGB24 = 1;
+    public static final int FORMAT_A8 = 2;
+    public static final int FORMAT_A1 = 3;
+    public static final int FORMAT_RGB16_565 = 4;
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoUtils.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoUtils.java
new file mode 100644
index 0000000..00bd896
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoUtils.java
@@ -0,0 +1,85 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import org.mozilla.gecko.gfx.CairoImage;
+import android.graphics.Bitmap;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Utility methods useful when displaying Cairo bitmaps using OpenGL ES.
+ */
+public class CairoUtils {
+    private CairoUtils() { /* Don't call me. */ }
+
+    public static int bitsPerPixelForCairoFormat(int cairoFormat) {
+        switch (cairoFormat) {
+        case CairoImage.FORMAT_A1:          return 1;
+        case CairoImage.FORMAT_A8:          return 8;
+        case CairoImage.FORMAT_RGB16_565:   return 16;
+        case CairoImage.FORMAT_RGB24:       return 24;
+        case CairoImage.FORMAT_ARGB32:      return 32;
+        default:
+            throw new RuntimeException("Unknown Cairo format");
+        }
+    }
+
+    public static int bitmapConfigToCairoFormat(Bitmap.Config config) {
+        if (config == null)
+            return CairoImage.FORMAT_ARGB32;    /* Droid Pro fix. */
+
+        switch (config) {
+        case ALPHA_8:   return CairoImage.FORMAT_A8;
+        case ARGB_4444: throw new RuntimeException("ARGB_444 unsupported");
+        case ARGB_8888: return CairoImage.FORMAT_ARGB32;
+        case RGB_565:   return CairoImage.FORMAT_RGB16_565;
+        default:        throw new RuntimeException("Unknown Skia bitmap config");
+        }
+    }
+
+    public static Bitmap.Config cairoFormatTobitmapConfig(int format) {
+        switch (format) {
+        case CairoImage.FORMAT_A8:        return Bitmap.Config.ALPHA_8;
+        case CairoImage.FORMAT_ARGB32:    return Bitmap.Config.ARGB_8888;
+        case CairoImage.FORMAT_RGB16_565: return Bitmap.Config.RGB_565;
+        default:
+            throw new RuntimeException("Unknown CairoImage format");
+        }
+    }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CheckerboardImage.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CheckerboardImage.java
new file mode 100644
index 0000000..f9ff966
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CheckerboardImage.java
@@ -0,0 +1,170 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import org.libreoffice.LOKitShell;
+//import org.mozilla.gecko.GeckoAppShell;
+import android.graphics.Color;
+import java.nio.ByteBuffer;
+import java.nio.ShortBuffer;
+import java.util.Arrays;
+
+/** A Cairo image that displays a tinted checkerboard. */
+public class CheckerboardImage extends CairoImage {
+    // The width and height of the checkerboard tile.
+    private static final int SIZE = 16;
+    // The pixel format of the checkerboard tile.
+    private static final int FORMAT = CairoImage.FORMAT_RGB16_565;
+    // The color to mix in to tint the background color.
+    private static final int TINT_COLOR = Color.GRAY;
+    // The amount to mix in.
+    private static final float TINT_OPACITY = 0.4f;
+
+    private ByteBuffer mBuffer;
+    private int mMainColor;
+    private boolean mShowChecks;
+
+    /** Creates a new checkerboard image. */
+    public CheckerboardImage() {
+        int bpp = CairoUtils.bitsPerPixelForCairoFormat(FORMAT);
+        mBuffer = /*GeckoAppShell*/LOKitShell.allocateDirectBuffer(SIZE * SIZE * bpp / 8);
+        update(true, Color.WHITE);
+    }
+
+    /** Returns the current color of the checkerboard. */
+    public int getColor() {
+        return mMainColor;
+    }
+
+    /** Returns whether or not we are currently showing checks on the checkerboard. */
+    public boolean getShowChecks() {
+        return mShowChecks;
+    }
+
+    /** Updates the checkerboard image. If showChecks is true, then create a
+     checkerboard image that is tinted to the color. Otherwise just return a flat
+     image of the color. */
+    public void update(boolean showChecks, int color) {
+        mMainColor = color;
+        mShowChecks = showChecks;
+
+        short mainColor16 = convertTo16Bit(mMainColor);
+
+        mBuffer.rewind();
+        ShortBuffer shortBuffer = mBuffer.asShortBuffer();
+
+        if (!mShowChecks) {
+            short color16 = convertTo16Bit(mMainColor);
+            short[] fillBuffer = new short[SIZE];
+            Arrays.fill(fillBuffer, color16);
+
+            for (int i = 0; i < SIZE; i++) {
+                shortBuffer.put(fillBuffer);
+            }
+
+            return;
+        }
+
+        short tintColor16 = convertTo16Bit(tint(mMainColor));
+
+        short[] mainPattern = new short[SIZE / 2], tintPattern = new short[SIZE / 2];
+        Arrays.fill(mainPattern, mainColor16);
+        Arrays.fill(tintPattern, tintColor16);
+
+        // The checkerboard pattern looks like this:
+        //
+        // +---+---+
+        // | N | T |  N = normal
+        // +---+---+  T = tinted
+        // | T | N |
+        // +---+---+
+
+        for (int i = 0; i < SIZE / 2; i++) {
+            shortBuffer.put(mainPattern);
+            shortBuffer.put(tintPattern);
+        }
+        for (int i = SIZE / 2; i < SIZE; i++) {
+            shortBuffer.put(tintPattern);
+            shortBuffer.put(mainPattern);
+        }
+    }
+
+    // Tints the given color appropriately and returns the tinted color.
+    private int tint(int color) {
+        float negTintOpacity = 1.0f - TINT_OPACITY;
+        float r = Color.red(color) * negTintOpacity + Color.red(TINT_COLOR) * TINT_OPACITY;
+        float g = Color.green(color) * negTintOpacity + Color.green(TINT_COLOR) * TINT_OPACITY;
+        float b = Color.blue(color) * negTintOpacity + Color.blue(TINT_COLOR) * TINT_OPACITY;
+        return Color.rgb(Math.round(r), Math.round(g), Math.round(b));
+    }
+
+    // Converts a 32-bit ARGB color to 16-bit R5G6B5, truncating values and discarding the alpha
+    // channel.
+    private short convertTo16Bit(int color) {
+        int r = Color.red(color) >> 3, g = Color.green(color) >> 2, b = Color.blue(color) >> 3;
+        int c = ((r << 11) | (g << 5) | b);
+        // Swap endianness.
+        return (short)((c >> 8) | ((c & 0xff) << 8));
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mBuffer != null) {
+                /*GeckoAppShell*/LOKitShell.freeDirectBuffer(mBuffer);
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public ByteBuffer getBuffer() {
+        return mBuffer;
+    }
+
+    @Override
+    public IntSize getSize() {
+        return new IntSize(SIZE, SIZE);
+    }
+
+    @Override
+    public int getFormat() {
+        return FORMAT;
+    }
+}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/FloatSize.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/FloatSize.java
new file mode 100644
index 0000000..21a712c
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/FloatSize.java
@@ -0,0 +1,88 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *   Chris Lord <chrislord.net at gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import org.mozilla.gecko.util.FloatUtils;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class FloatSize {
+    public final float width, height;
+
+    public FloatSize(FloatSize size) { width = size.width; height = size.height; }
+    public FloatSize(IntSize size) { width = size.width; height = size.height; }
+    public FloatSize(float aWidth, float aHeight) { width = aWidth; height = aHeight; }
+
+    public FloatSize(JSONObject json) {
+        try {
+            width = (float)json.getDouble("width");
+            height = (float)json.getDouble("height");
+        } catch (JSONException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "(" + width + "," + height + ")";
+    }
+
+    public boolean isPositive() {
+        return (width > 0 && height > 0);
+    }
+
+    public boolean fuzzyEquals(FloatSize size) {
+        return (FloatUtils.fuzzyEquals(size.width, width) &&
+                FloatUtils.fuzzyEquals(size.height, height));
+    }
+
+    public FloatSize scale(float factor) {
+        return new FloatSize(width * factor, height * factor);
+    }
+
+    /*
+     * Returns the size that represents a linear transition between this size and `to` at time `t`,
+     * which is on the scale [0, 1).
+     */
+    public FloatSize interpolate(FloatSize to, float t) {
+        return new FloatSize(FloatUtils.interpolate(width, to.width, t),
+                             FloatUtils.interpolate(height, to.height, t));
+    }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java
new file mode 100644
index 0000000..9385d81
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java
@@ -0,0 +1,505 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *   Chris Lord <chrislord.net at gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.libreoffice.LOEvent;
+import org.libreoffice.LOKitShell;
+import org.libreoffice.LibreOfficeMainActivity;
+import org.mozilla.gecko.GeckoEventListener;
+import org.mozilla.gecko.util.FloatUtils;
+
+import java.nio.ByteBuffer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+//import org.mozilla.gecko.GeckoApp;
+//import org.mozilla.gecko.GeckoAppShell;
+//import org.mozilla.gecko.GeckoEvent;
+
+/**
+ * Transfers a software-rendered Gecko to an ImageLayer so that it can be rendered by our
+ * compositor.
+ * <p/>
+ * TODO: Throttle down Gecko's priority when we pan and zoom.
+ */
+public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventListener {
+    private static final String LOGTAG = "GeckoSoftwareLayerClient";
+    private static final IntSize TILE_SIZE = new IntSize(256, 256);
+    private static final long MIN_VIEWPORT_CHANGE_DELAY = 350L;
+    private static Pattern sColorPattern;
+    private Context mContext;
+    private int mFormat;
+    private IntSize mScreenSize;
+    private IntSize mBufferSize;
+    private ByteBuffer mBuffer;
+    private Layer mTileLayer;
+    /* The viewport rect that Gecko is currently displaying. */
+    private ViewportMetrics mGeckoViewport;
+    private CairoImage mCairoImage;
+    private long mLastViewportChangeTime;
+    private boolean mPendingViewportAdjust;
+    private boolean mViewportSizeChanged;
+    // Whether or not the last paint we got used direct texturing
+    private boolean mHasDirectTexture;
+    // mUpdateViewportOnEndDraw is used to indicate that we received a
+    // viewport update notification while drawing. therefore, when the
+    // draw finishes, we need to update the entire viewport rather than
+    // just the page size. this boolean should always be accessed from
+    // inside a transaction, so no synchronization is needed.
+    private boolean mUpdateViewportOnEndDraw;
+
+    public GeckoSoftwareLayerClient(Context context) {
+        mContext = context;
+
+        mScreenSize = new IntSize(0, 0);
+        mBufferSize = new IntSize(0, 0);
+        mFormat = CairoImage.FORMAT_RGB16_565;
+
+        mCairoImage = new CairoImage() {
+            @Override
+            public ByteBuffer getBuffer() {
+                return mBuffer;
+            }
+
+            @Override
+            public IntSize getSize() {
+                return mBufferSize;
+            }
+
+            @Override
+            public int getFormat() {
+                return mFormat;
+            }
+        };
+
+        mTileLayer = new MultiTileLayer(mCairoImage, TILE_SIZE);
+    }
+
+    // Parses a color from an RGB triple of the form "rgb([0-9]+, [0-9]+, [0-9]+)". If the color
+    // cannot be parsed, returns white.
+    private static int parseColorFromGecko(String string) {
+        if (sColorPattern == null) {
+            sColorPattern = Pattern.compile("rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)");
+        }
+
+        Matcher matcher = sColorPattern.matcher(string);
+        if (!matcher.matches()) {
+            return Color.WHITE;
+        }
+
+        int r = Integer.parseInt(matcher.group(1));
+        int g = Integer.parseInt(matcher.group(2));
+        int b = Integer.parseInt(matcher.group(3));
+        return Color.rgb(r, g, b);
+    }
+
+    public int getWidth() {
+        return mBufferSize.width;
+    }
+
+    public int getHeight() {
+        return mBufferSize.height;
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            if (mBuffer != null)
+                /*GeckoAppShell*/ LOKitShell.freeDirectBuffer(mBuffer);
+            mBuffer = null;
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Attaches the root layer to the layer controller so that Gecko appears.
+     */
+    @Override
+    public void setLayerController(LayerController layerController) {
+        super.setLayerController(layerController);
+
+        layerController.setRoot(mTileLayer);
+        if (mGeckoViewport != null) {
+            layerController.setViewportMetrics(mGeckoViewport);
+        }
+
+        //GeckoAppShell.registerGeckoEventListener("Viewport:UpdateAndDraw", this);
+        //GeckoAppShell.registerGeckoEventListener("Viewport:UpdateLater", this);
+
+        // This needs to happen before a call to sendResizeEventIfNecessary
+        // happens, but only needs to be called once. As that is only called by
+        // the layer controller or this, here is a safe place to do so.
+        if (mTileLayer instanceof MultiTileLayer) {
+            //GeckoEvent event = new GeckoEvent(GeckoEvent.TILE_SIZE, TILE_SIZE);
+            //GeckoAppShell.sendEventToGecko(event);
+            LOKitShell.sendEvent(LOEvent.tileSize(TILE_SIZE));
+        }
+
+        sendResizeEventIfNecessary();
+    }
+
+    private void setHasDirectTexture(boolean hasDirectTexture) {
+        if (hasDirectTexture == mHasDirectTexture)
+            return;
+
+        mHasDirectTexture = hasDirectTexture;
+
+        IntSize tileSize;
+        if (mHasDirectTexture) {
+            mTileLayer = new WidgetTileLayer(mCairoImage);
+            tileSize = new IntSize(0, 0);
+        } else {
+            mTileLayer = new MultiTileLayer(mCairoImage, TILE_SIZE);
+            tileSize = TILE_SIZE;
+        }
+
+        getLayerController().setRoot(mTileLayer);
+
+        //GeckoEvent event = new GeckoEvent(GeckoEvent.TILE_SIZE, tileSize);
+        //GeckoAppShell.sendEventToGecko(event);
+        LOKitShell.sendEvent(LOEvent.tileSize(tileSize));
+
+        // Force a resize event to be sent because the results of this
+        // are different depending on what tile system we're using
+        sendResizeEventIfNecessary(true);
+    }
+
+    public void beginDrawing(int width, int height) {
+        beginTransaction(mTileLayer);
+
+        if (mBufferSize.width != width || mBufferSize.height != height) {
+            mBufferSize = new IntSize(width, height);
+
+            // Reallocate the buffer if necessary
+
+            // * 2 because it's a 16-bit buffer (so 2 bytes per pixel).
+            int size = mBufferSize.getArea() * 2;
+            if (mBuffer == null || mBuffer.capacity() != size) {
+                // Free the old buffer
+                if (mBuffer != null) {
+                    /*GeckoAppShell*/
+                    LOKitShell.freeDirectBuffer(mBuffer);
+                    mBuffer = null;
+                }
+
+                mBuffer = /*GeckoAppShell*/LOKitShell.allocateDirectBuffer(size);
+            }
+        }
+    }
+
+    private void updateViewport(String viewportDescription, final boolean onlyUpdatePageSize) {
+        try {
+            JSONObject viewportObject = new JSONObject(viewportDescription);
+
+            // save and restore the viewport size stored in java; never let the
+            // JS-side viewport dimensions override the java-side ones because
+            // java is the One True Source of this information, and allowing JS
+            // to override can lead to race conditions where this data gets clobbered.
+            FloatSize viewportSize = getLayerController().getViewportSize();
+            mGeckoViewport = new ViewportMetrics(viewportObject);
+            mGeckoViewport.setSize(viewportSize);
+
+            LayerController controller = getLayerController();
+            PointF displayportOrigin = mGeckoViewport.getDisplayportOrigin();
+            mTileLayer.setOrigin(PointUtils.round(displayportOrigin));
+            mTileLayer.setResolution(mGeckoViewport.getZoomFactor());
+
+            if (onlyUpdatePageSize) {
+                // Don't adjust page size when zooming unless zoom levels are
+                // approximately equal.
+                if (FloatUtils.fuzzyEquals(controller.getZoomFactor(),
+                        mGeckoViewport.getZoomFactor()))
+                    controller.setPageSize(mGeckoViewport.getPageSize());
+            } else {
+                Log.d(LOGTAG, "Received viewport update from gecko");
+                controller.setViewportMetrics(mGeckoViewport);
+                controller.abortPanZoomAnimation();
+            }
+
+            // Update the background color, if it's present.
+            String backgroundColorString = viewportObject.optString("backgroundColor");
+            if (backgroundColorString != null) {
+                controller.setCheckerboardColor(parseColorFromGecko(backgroundColorString));
+            }
+        } catch (JSONException e) {
+            Log.e(LOGTAG, "Bad viewport description: " + viewportDescription);
+            throw new RuntimeException(e);
+        }
+    }
+
+    public ByteBuffer getBuffer() {
+        return mBuffer;
+    }
+
+    /*
+         * TODO: Would be cleaner if this took an android.graphics.Rect instead, but that would require
+         * a little more JNI magic.
+         */
+    public void endDrawing(int x, int y, int width, int height, String metadata, boolean hasDirectTexture) {
+        synchronized (getLayerController()) {
+            try {
+                updateViewport(metadata, !mUpdateViewportOnEndDraw);
+                mUpdateViewportOnEndDraw = false;
+                Rect rect = new Rect(x, y, x + width, y + height);
+
+                setHasDirectTexture(hasDirectTexture);
+
+                if (!mHasDirectTexture)
+                    ((MultiTileLayer) mTileLayer).invalidate(rect);
+            } finally {
+                endTransaction(mTileLayer);
+            }
+        }
+    }
+
+    public ViewportMetrics getGeckoViewportMetrics() {
+        // Return a copy, as we modify this inside the Gecko thread
+        if (mGeckoViewport != null)
+            return new ViewportMetrics(mGeckoViewport);
+        return null;
+    }
+
+    public void copyPixelsFromMultiTileLayer(Bitmap target) {
+        Canvas canvas = new Canvas(target);
+        ByteBuffer tileBuffer = mBuffer.slice();
+        int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8;
+
+        for (int y = 0; y < mBufferSize.height; y += TILE_SIZE.height) {
+            for (int x = 0; x < mBufferSize.width; x += TILE_SIZE.width) {
+                // Calculate tile size
+                IntSize tileSize = new IntSize(Math.min(mBufferSize.width - x, TILE_SIZE.width),
+                        Math.min(mBufferSize.height - y, TILE_SIZE.height));
+
+                // Create a Bitmap from this tile
+                Bitmap tile = Bitmap.createBitmap(tileSize.width, tileSize.height,
+                        CairoUtils.cairoFormatTobitmapConfig(mFormat));
+                tile.copyPixelsFromBuffer(tileBuffer.asIntBuffer());
+
+                // Copy the tile to the master Bitmap and recycle it
+                canvas.drawBitmap(tile, x, y, null);
+                tile.recycle();
+
+                // Progress the buffer to the next tile
+                tileBuffer.position(tileSize.getArea() * bpp);
+                tileBuffer = tileBuffer.slice();
+            }
+        }
+    }
+
+    public Bitmap getBitmap() {
+        // Begin a tile transaction, otherwise the buffer can be destroyed while
+        // we're reading from it.
+        beginTransaction(mTileLayer);
+        try {
+            if (mBuffer == null || mBufferSize.width <= 0 || mBufferSize.height <= 0)
+                return null;
+            try {
+                Bitmap bitmap = null;
+
+                if (mTileLayer instanceof MultiTileLayer) {
+                    bitmap = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,
+                            CairoUtils.cairoFormatTobitmapConfig(mFormat));
+                    copyPixelsFromMultiTileLayer(bitmap);
+                } else if (mTileLayer instanceof SingleTileLayer) {
+                    bitmap = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,
+                            CairoUtils.cairoFormatTobitmapConfig(mFormat));
+                    bitmap.copyPixelsFromBuffer(mBuffer.asIntBuffer());
+                } else {
+                    Log.w(LOGTAG, "getBitmap() called on a layer (" + mTileLayer + ") we don't know how to get a bitmap from");
+                }
+
+                return bitmap;
+            } catch (OutOfMemoryError oom) {
+                Log.w(LOGTAG, "Unable to create bitmap", oom);
+                return null;
+            }
+        } finally {
+            endTransaction(mTileLayer);
+        }
+    }
+
+    /**
+     * Returns the back buffer. This function is for Gecko to use.
+     */
+    public ByteBuffer lockBuffer() {
+        return mBuffer;
+    }
+
+    /**
+     * Gecko calls this function to signal that it is done with the back buffer. After this call,
+     * it is forbidden for Gecko to touch the buffer.
+     */
+    public void unlockBuffer() {
+        /* no-op */
+    }
+
+    @Override
+    public void geometryChanged() {
+        /* Let Gecko know if the screensize has changed */
+        sendResizeEventIfNecessary();
+        render();
+    }
+
+    private void sendResizeEventIfNecessary() {
+        sendResizeEventIfNecessary(false);
+    }
+
+    /* Informs Gecko that the screen size has changed. */
+    private void sendResizeEventIfNecessary(boolean force) {
+        DisplayMetrics metrics = new DisplayMetrics();
+        //GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        LibreOfficeMainActivity.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+
+        // Return immediately if the screen size hasn't changed or the viewport
+        // size is zero (which indicates that the rendering surface hasn't been
+        // allocated yet).
+        boolean screenSizeChanged = (metrics.widthPixels != mScreenSize.width ||
+                metrics.heightPixels != mScreenSize.height);
+        boolean viewportSizeValid = (getLayerController() != null &&
+                getLayerController().getViewportSize().isPositive());
+        if (!(force || (screenSizeChanged && viewportSizeValid))) {
+            return;
+        }
+
+        mScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
+        IntSize bufferSize;
+
+        // Round up depending on layer implementation to remove texture wastage
+        if (mTileLayer instanceof MultiTileLayer) {
+            // Round to the next multiple of the tile size, respecting maximum texture size
+            bufferSize = new IntSize(((mScreenSize.width + LayerController.MIN_BUFFER.width - 1) / TILE_SIZE.width + 1) * TILE_SIZE.width,
+                    ((mScreenSize.height + LayerController.MIN_BUFFER.height - 1) / TILE_SIZE.height + 1) * TILE_SIZE.height);
+
+        } else {
+            int maxSize = getLayerController().getView().getMaxTextureSize();
+
+            // XXX Integrate gralloc/tiling work to circumvent this
+            if (mScreenSize.width > maxSize || mScreenSize.height > maxSize)
+                throw new RuntimeException("Screen size of " + mScreenSize + " larger than maximum texture size of " + maxSize);
+
+            // Round to next power of two until we have NPOT texture support
+            bufferSize = new IntSize(Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.width + LayerController.MIN_BUFFER.width)),
+                    Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.height + LayerController.MIN_BUFFER.height)));
+        }
+
+        Log.i(LOGTAG, "Screen-size changed to " + mScreenSize);
+
+        /*GeckoEvent event = new GeckoEvent(GeckoEvent.SIZE_CHANGED,
+                                          bufferSize.width, bufferSize.height,
+                                          metrics.widthPixels, metrics.heightPixels);
+        GeckoAppShell.sendEventToGecko(event);*/
+        LOKitShell.sendEvent(LOEvent.sizeChanged(bufferSize.width, bufferSize.height, metrics.widthPixels, metrics.heightPixels));
+    }
+
+    @Override
+    public void viewportSizeChanged() {
+        mViewportSizeChanged = true;
+    }
+
+    @Override
+    public void render() {
+        adjustViewportWithThrottling();
+    }
+
+    private void adjustViewportWithThrottling() {
+        if (!getLayerController().getRedrawHint())
+            return;
+
+        if (mPendingViewportAdjust)
+            return;
+
+        long timeDelta = System.currentTimeMillis() - mLastViewportChangeTime;
+        if (timeDelta < MIN_VIEWPORT_CHANGE_DELAY) {
+            getLayerController().getView().postDelayed(
+                    new Runnable() {
+                        public void run() {
+                            mPendingViewportAdjust = false;
+                            adjustViewport();
+                        }
+                    }, MIN_VIEWPORT_CHANGE_DELAY - timeDelta
+            );
+            mPendingViewportAdjust = true;
+            return;
+        }
+
+        adjustViewport();
+    }
+
+    private void adjustViewport() {
+        ViewportMetrics viewportMetrics = new ViewportMetrics(getLayerController().getViewportMetrics());
+
+        PointF viewportOffset = viewportMetrics.getOptimumViewportOffset(mBufferSize);
+        viewportMetrics.setViewportOffset(viewportOffset);
+        viewportMetrics.setViewport(viewportMetrics.getClampedViewport());
+
+        //GeckoAppShell.sendEventToGecko(new GeckoEvent(viewportMetrics));
+        LOKitShell.sendEvent(LOEvent.viewport(viewportMetrics));
+        if (mViewportSizeChanged) {
+            mViewportSizeChanged = false;
+            //GeckoAppShell.viewSizeChanged();
+        }
+
+        mLastViewportChangeTime = System.currentTimeMillis();
+    }
+
+    public void handleMessage(String event, JSONObject message) {
+        if ("Viewport:UpdateAndDraw".equals(event)) {
+            mUpdateViewportOnEndDraw = true;
+
+            // Redraw everything.
+            Rect rect = new Rect(0, 0, mBufferSize.width, mBufferSize.height);
+            //GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.DRAW, rect));
+            LOKitShell.sendEvent(LOEvent.draw(rect));
+        } else if ("Viewport:UpdateLater".equals(event)) {
+            mUpdateViewportOnEndDraw = true;
+        }
+    }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/InputConnectionHandler.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/InputConnectionHandler.java
new file mode 100644
index 0000000..6fef53f
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/InputConnectionHandler.java
@@ -0,0 +1,15 @@
+package org.mozilla.gecko.gfx;
+
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.KeyEvent;
+
+public interface InputConnectionHandler
+{
+    InputConnection onCreateInputConnection(EditorInfo outAttrs);
+    boolean onKeyPreIme(int keyCode, KeyEvent event);
+    boolean onKeyDown(int keyCode, KeyEvent event);
+    boolean onKeyLongPress(int keyCode, KeyEvent event);
+    boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event);
+    boolean onKeyUp(int keyCode, KeyEvent event);
+}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/IntSize.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/IntSize.java
new file mode 100644
index 0000000..ee43b1b
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/IntSize.java
@@ -0,0 +1,103 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import org.mozilla.gecko.gfx.FloatSize;
+import org.json.JSONException;
+import org.json.JSONObject;
+import java.lang.Math;
+
+public class IntSize {
+    public final int width, height;
+
+    public IntSize(IntSize size) { width = size.width; height = size.height; }
+    public IntSize(int inWidth, int inHeight) { width = inWidth; height = inHeight; }
+
+    public IntSize(FloatSize size) {
+        width = Math.round(size.width);
+        height = Math.round(size.height);
+    }
+
+    public IntSize(JSONObject json) {
+        try {
+            width = json.getInt("width");
+            height = json.getInt("height");
+        } catch (JSONException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public int getArea() {
+        return width * height;
+    }
+
+    public boolean equals(IntSize size) {
+        return ((size.width == width) && (size.height == height));
+    }
+
+    public boolean isPositive() {
+        return (width > 0 && height > 0);
+    }
+
+    @Override
+    public String toString() { return "(" + width + "," + height + ")"; }
+
+    public IntSize scale(float factor) {
+        return new IntSize(Math.round(width * factor),
+                           Math.round(height * factor));
+    }
+
+    /* Returns the power of two that is greater than or equal to value */
+    public static int nextPowerOfTwo(int value) {
+        // code taken from http://acius2.blogspot.com/2007/11/calculating-next-power-of-2.html
+        if (0 == value--) {
+            return 1;
+        }
+        value = (value >> 1) | value;
+        value = (value >> 2) | value;
+        value = (value >> 4) | value;
+        value = (value >> 8) | value;
+        value = (value >> 16) | value;
+        return value + 1;
+    }
+
+    public IntSize nextPowerOfTwo() {
+        return new IntSize(nextPowerOfTwo(width), nextPowerOfTwo(height));
+    }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/Layer.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/Layer.java
new file mode 100644
index 0000000..17ecbba
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/Layer.java
@@ -0,0 +1,213 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *   Chris Lord <chrislord.net at gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.util.Log;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.microedition.khronos.opengles.GL10;
+import org.mozilla.gecko.util.FloatUtils;
+
+public abstract class Layer {
+    private final ReentrantLock mTransactionLock;
+    private boolean mInTransaction;
+    private Point mNewOrigin;
+    private float mNewResolution;
+    private LayerView mView;
+
+    protected Point mOrigin;
+    protected float mResolution;
+
+    public Layer() {
+        mTransactionLock = new ReentrantLock();
+        mOrigin = new Point(0, 0);
+        mResolution = 1.0f;
+    }
+
+    /**
+     * Updates the layer. This returns false if there is still work to be done
+     * after this update.
+     */
+    public final boolean update(GL10 gl, RenderContext context) {
+        if (mTransactionLock.isHeldByCurrentThread()) {
+            throw new RuntimeException("draw() called while transaction lock held by this " +
+                    "thread?!");
+        }
+
+        if (mTransactionLock.tryLock()) {
+            try {
+                return performUpdates(gl, context);
+            } finally {
+                mTransactionLock.unlock();
+            }
+        }
+
+        return false;
+    }
+
+    /** Subclasses override this function to draw the layer. */
+    public abstract void draw(RenderContext context);
+
+    /** Subclasses override this function to provide access to the size of the layer. */
+    public abstract IntSize getSize();
+
+    /** Given the intrinsic size of the layer, returns the pixel boundaries of the layer rect. */
+    protected RectF getBounds(RenderContext context, FloatSize size) {
+        float scaleFactor = context.zoomFactor / mResolution;
+        float x = mOrigin.x * scaleFactor, y = mOrigin.y * scaleFactor;
+        float width = size.width * scaleFactor, height = size.height * scaleFactor;
+        return new RectF(x, y, x + width, y + height);
+    }
+
+    /**
+     * Returns the region of the layer that is considered valid. The default
+     * implementation of this will return the bounds of the layer, but this
+     * may be overridden.
+     */
+    public Region getValidRegion(RenderContext context) {
+        return new Region(RectUtils.round(getBounds(context, new FloatSize(getSize()))));
+    }
+
+    /**
+     * Call this before modifying the layer. Note that, for TileLayers, "modifying the layer"
+     * includes altering the underlying CairoImage in any way. Thus you must call this function
+     * before modifying the byte buffer associated with this layer.
+     *
+     * This function may block, so you should never call this on the main UI thread.
+     */
+    public void beginTransaction(LayerView aView) {
+        if (mTransactionLock.isHeldByCurrentThread())
+            throw new RuntimeException("Nested transactions are not supported");
+        mTransactionLock.lock();
+        mView = aView;
+        mInTransaction = true;
+        mNewResolution = mResolution;
+    }
+
+    public void beginTransaction() {
+        beginTransaction(null);
+    }
+
+    /** Call this when you're done modifying the layer. */
+    public void endTransaction() {
+        if (!mInTransaction)
+            throw new RuntimeException("endTransaction() called outside a transaction");
+        mInTransaction = false;
+        mTransactionLock.unlock();
+
+        if (mView != null)
+            mView.requestRender();
+    }
+
+    /** Returns true if the layer is currently in a transaction and false otherwise. */
+    protected boolean inTransaction() {
+        return mInTransaction;
+    }
+
+    /** Returns the current layer origin. */
+    public Point getOrigin() {
+        return mOrigin;
+    }
+
+    /** Sets the origin. Only valid inside a transaction. */
+    public void setOrigin(Point newOrigin) {
+        if (!mInTransaction)
+            throw new RuntimeException("setOrigin() is only valid inside a transaction");
+        mNewOrigin = newOrigin;
+    }
+
+    /** Returns the current layer's resolution. */
+    public float getResolution() {
+        return mResolution;
+    }
+
+    /**
+     * Sets the layer resolution. This value is used to determine how many pixels per
+     * device pixel this layer was rendered at. This will be reflected by scaling by
+     * the reciprocal of the resolution in the layer's transform() function.
+     * Only valid inside a transaction. */
+    public void setResolution(float newResolution) {
+        if (!mInTransaction)
+            throw new RuntimeException("setResolution() is only valid inside a transaction");
+        mNewResolution = newResolution;
+    }
+
+    /**
+     * Subclasses may override this method to perform custom layer updates. This will be called
+     * with the transaction lock held. Subclass implementations of this method must call the
+     * superclass implementation. Returns false if there is still work to be done after this
+     * update is complete.
+     */
+    protected boolean performUpdates(GL10 gl, RenderContext context) {
+        if (mNewOrigin != null) {
+            mOrigin = mNewOrigin;
+            mNewOrigin = null;
+        }
+        if (mNewResolution != 0.0f) {
+            mResolution = mNewResolution;
+            mNewResolution = 0.0f;
+        }
+
+        return true;
+    }
+
+    public static class RenderContext {
+        public final RectF viewport;
+        public final FloatSize pageSize;
+        public final float zoomFactor;
+
+        public RenderContext(RectF aViewport, FloatSize aPageSize, float aZoomFactor) {
+            viewport = aViewport;
+            pageSize = aPageSize;
+            zoomFactor = aZoomFactor;
+        }
+
+        public boolean fuzzyEquals(RenderContext other) {
+            if (other == null) {
+                return false;
+            }
+            return RectUtils.fuzzyEquals(viewport, other.viewport)
+                    && pageSize.fuzzyEquals(other.pageSize)
+                    && FloatUtils.fuzzyEquals(zoomFactor, other.zoomFactor);
+        }
+    }
+}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerClient.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerClient.java
new file mode 100644
index 0000000..4f46108
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerClient.java
@@ -0,0 +1,81 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+/**
+ * A layer client provides tiles and manages other information used by the layer controller.
+ */
+public abstract class LayerClient {
+    private LayerController mLayerController;
+
+    public abstract void geometryChanged();
+
+    public abstract void viewportSizeChanged();
+
+    protected abstract void render();
+
+    public LayerController getLayerController() {
+        return mLayerController;
+    }
+
+    public void setLayerController(LayerController layerController) {
+        mLayerController = layerController;
+    }
+
+    /**
+     * A utility function for calling Layer.beginTransaction with the
+     * appropriate LayerView.
+     */
+    public void beginTransaction(Layer aLayer) {
+        if (mLayerController != null) {
+            LayerView view = mLayerController.getView();
+            if (view != null) {
+                aLayer.beginTransaction(view);
+                return;
+            }
+        }
+
+        aLayer.beginTransaction();
+    }
+
+    // Included for symmetry.
+    public void endTransaction(Layer aLayer) {
+        aLayer.endTransaction();
+    }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerController.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerController.java
new file mode 100644
index 0000000..fb08238
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerController.java
@@ -0,0 +1,525 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *   Chris Lord <chrislord.net at gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list