summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.com>2014-06-17 13:05:33 +0200
committerFridrich Štrba <fridrich.strba@bluewin.ch>2014-06-30 14:56:28 +0200
commit6a48e0b2da2bb377e857448afab9c73858dde15c (patch)
treea2db4e7189edc37e41809dd4d0a88d623537cccf
parent16a35d46972b947c182d2dc23e21e1eb9778d2c3 (diff)
LOAndroid2: use GLES2, latest GeckoSoftwareLayerClient
Additionally add GeckoGLLayerClient as an alternative LayerClient Change-Id: I250b5d806f520231ad9a9b84ef8387e8830bb364
-rw-r--r--android/experimental/LOAndroid/.idea/misc.xml3
-rw-r--r--android/experimental/LOAndroid2/.idea/modules.xml1
-rw-r--r--android/experimental/LOAndroid2/LOAndroid2.iml12
-rw-r--r--android/experimental/LOAndroid2/app/app.iml2
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOEvent.java6
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitShell.java13
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitThread.java58
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LibreOfficeMainActivity.java18
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CairoGLInfo.java35
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CheckerboardImage.java6
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/FlexibleGLSurfaceView.java218
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/FloatSize.java25
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GLController.java279
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GLThread.java181
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoGLLayerClient.java265
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java414
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java433
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/Layer.java71
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerController.java101
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerRenderer.java499
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerView.java27
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/MultiTileLayer.java172
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/RectUtils.java47
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ScrollbarLayer.java282
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/SingleTileLayer.java51
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TextureReaper.java7
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TileLayer.java74
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewTransform.java51
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewportMetrics.java126
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/VirtualLayer.java80
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/WidgetTileLayer.java69
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/Axis.java4
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/PanZoomController.java30
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java54
-rw-r--r--android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java16
35 files changed, 2789 insertions, 941 deletions
diff --git a/android/experimental/LOAndroid/.idea/misc.xml b/android/experimental/LOAndroid/.idea/misc.xml
index d0225fc0c171..589a3ed5fd78 100644
--- a/android/experimental/LOAndroid/.idea/misc.xml
+++ b/android/experimental/LOAndroid/.idea/misc.xml
@@ -3,6 +3,9 @@
<component name="DaemonCodeAnalyzer">
<disable_hints />
</component>
+ <component name="EntryPointsManager">
+ <entry_points version="2.0" />
+ </component>
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
diff --git a/android/experimental/LOAndroid2/.idea/modules.xml b/android/experimental/LOAndroid2/.idea/modules.xml
index f08135d5d6bf..d5e166fb414b 100644
--- a/android/experimental/LOAndroid2/.idea/modules.xml
+++ b/android/experimental/LOAndroid2/.idea/modules.xml
@@ -3,6 +3,7 @@
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/LOAndroid.iml" filepath="$PROJECT_DIR$/LOAndroid.iml" />
+ <module fileurl="file://$PROJECT_DIR$/LOAndroid2.iml" filepath="$PROJECT_DIR$/LOAndroid2.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
diff --git a/android/experimental/LOAndroid2/LOAndroid2.iml b/android/experimental/LOAndroid2/LOAndroid2.iml
new file mode 100644
index 000000000000..edb62a65fa47
--- /dev/null
+++ b/android/experimental/LOAndroid2/LOAndroid2.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="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module>
+
diff --git a/android/experimental/LOAndroid2/app/app.iml b/android/experimental/LOAndroid2/app/app.iml
index e89240b42923..34b87a5df4f4 100644
--- a/android/experimental/LOAndroid2/app/app.iml
+++ b/android/experimental/LOAndroid2/app/app.iml
@@ -1,5 +1,5 @@
<?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">
+<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="LOAndroid2" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
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
index a5396693de89..bf4f98b845da 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOEvent.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOEvent.java
@@ -20,7 +20,7 @@ public class LOEvent {
ViewportMetrics viewportMetrics;
- public LOEvent(int type, int width, int height, int widthPixels, int heightPixels) {
+ public LOEvent(int type, int width, int height, int widthPixels, int heightPixels, int tileWidth, int tileHeight) {
mType = type;
mTypeString = "Size Changed";
}
@@ -45,8 +45,8 @@ public class LOEvent {
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 sizeChanged(int width, int height, int widthPixels, int heightPixels, int tileWidth, int tileHeight) {
+ return new LOEvent(SIZE_CHANGED, width, height, widthPixels, heightPixels, tileWidth, tileHeight);
}
public static LOEvent tileSize(IntSize tileSize) {
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
index 69b634cc2231..9dde7906d020 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitShell.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitShell.java
@@ -115,4 +115,17 @@ public class LOKitShell {
layerController.notifyLayerClientOfGeometryChange();*/
}
+
+ public static void viewSizeChanged() {
+ }
+
+ public static void scheduleComposite() {
+ }
+
+ public static void schedulePauseComposition() {
+ }
+
+ public static void scheduleResumeComposition() {
+
+ }
}
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
index 37bb51c00926..08c49493cbd8 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitThread.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LOKitThread.java
@@ -4,6 +4,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.util.JsonWriter;
import org.mozilla.gecko.gfx.ViewportMetrics;
@@ -11,8 +12,6 @@ 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;
@@ -26,28 +25,11 @@ public class LOKitThread extends Thread {
LOKitThread() {
}
- private void draw() throws InterruptedException {
+ private boolean 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);
- }*/
+ Bitmap bitmap = application.getLayerClient().getLayerController().getDrawable16("dummy_page");
+ bitmap = convert(bitmap, Bitmap.Config.RGB_565);
StringWriter stringWriter = new StringWriter();
@@ -64,7 +46,6 @@ public class LOKitThread extends Thread {
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);
@@ -75,7 +56,6 @@ public class LOKitThread extends Thread {
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();
@@ -83,15 +63,24 @@ public class LOKitThread extends Thread {
} 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);
- }
- });
+ Rect bufferRect = application.getLayerClient().beginDrawing(bitmap.getWidth(), bitmap.getHeight(), 256, 256, stringWriter.toString(), false);
+
+ if (bufferRect == null) {
+ return false;
+ }
+ ByteBuffer buffer = application.getLayerClient().lockBuffer();
+ bitmap.copyPixelsToBuffer(buffer.asIntBuffer());
+ application.getLayerClient().unlockBuffer();
+ application.getLayerClient().endDrawing(0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+ application.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ application.getLayerClient().handleMessage("Viewport:UpdateLater", null);
+ }
+ });
+ return true;
}
private short convertTo16Bit(int color) {
@@ -119,9 +108,8 @@ public class LOKitThread extends Thread {
if (!gEvents.isEmpty()) {
processEvent(gEvents.poll());
} else {
- if(!drawn) {
- draw();
- drawn = true;
+ if (!drawn) {
+ drawn = draw();
}
Thread.sleep(100L);
}
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
index a4fdf03c6503..934464d2dea6 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LibreOfficeMainActivity.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/libreoffice/LibreOfficeMainActivity.java
@@ -23,7 +23,7 @@ public class LibreOfficeMainActivity extends Activity {
private LinearLayout mMainLayout;
private RelativeLayout mGeckoLayout;
private static LayerController mLayerController;
- private static GeckoSoftwareLayerClient mSoftwareLayerClient;
+ private static GeckoSoftwareLayerClient mLayerClient;
private static LOKitThread sLOKitThread;
public static LibreOfficeMainActivity mAppContext;
@@ -74,8 +74,12 @@ public class LibreOfficeMainActivity extends Activity {
if (mLayerController == null) {
mLayerController = new LayerController(this);
- mSoftwareLayerClient = new GeckoSoftwareLayerClient(this);
- mLayerController.setLayerClient(mSoftwareLayerClient);
+
+ Log.e(LOGTAG, "### Creating GeckoSoftwareLayerClient");
+ mLayerClient = new GeckoSoftwareLayerClient(this);
+ Log.e(LOGTAG, "### Done creating GeckoSoftwareLayerClient");
+
+ mLayerController.setLayerClient(mLayerClient);
mGeckoLayout.addView(mLayerController.getView(), 0);
}
@@ -88,7 +92,11 @@ public class LibreOfficeMainActivity extends Activity {
Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - UI almost up");
}
- public static GeckoSoftwareLayerClient getSoftwareLayerClient() {
- return mSoftwareLayerClient;
+ public static GeckoSoftwareLayerClient getLayerClient() {
+ return mLayerClient;
+ }
+
+ public static LayerController getLayerController() {
+ return mLayerController;
}
} \ No newline at end of file
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
index 16417e17b51f..bd4eedcaf951 100644
--- 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
@@ -39,7 +39,9 @@ package org.mozilla.gecko.gfx;
import javax.microedition.khronos.opengles.GL10;
-/** Information needed to render Cairo bitmaps using OpenGL ES. */
+/**
+ * Information needed to render Cairo bitmaps using OpenGL ES.
+ */
public class CairoGLInfo {
public final int internalFormat;
public final int format;
@@ -47,20 +49,23 @@ public class CairoGLInfo {
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");
+ 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/CheckerboardImage.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/CheckerboardImage.java
index f9ff9664bc62..392d7e8d8463 100644
--- 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
@@ -38,7 +38,6 @@
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;
@@ -62,7 +61,7 @@ public class CheckerboardImage extends CairoImage {
/** Creates a new checkerboard image. */
public CheckerboardImage() {
int bpp = CairoUtils.bitsPerPixelForCairoFormat(FORMAT);
- mBuffer = /*GeckoAppShell*/LOKitShell.allocateDirectBuffer(SIZE * SIZE * bpp / 8);
+ mBuffer = LOKitShell.allocateDirectBuffer(SIZE * SIZE * bpp / 8);
update(true, Color.WHITE);
}
@@ -146,7 +145,7 @@ public class CheckerboardImage extends CairoImage {
protected void finalize() throws Throwable {
try {
if (mBuffer != null) {
- /*GeckoAppShell*/LOKitShell.freeDirectBuffer(mBuffer);
+ LOKitShell.freeDirectBuffer(mBuffer);
}
} finally {
super.finalize();
@@ -168,3 +167,4 @@ public class CheckerboardImage extends CairoImage {
return FORMAT;
}
}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/FlexibleGLSurfaceView.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/FlexibleGLSurfaceView.java
new file mode 100644
index 000000000000..dc20077b0457
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/FlexibleGLSurfaceView.java
@@ -0,0 +1,218 @@
+/* -*- 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) 2011-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@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.GeckoApp;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import org.libreoffice.LibreOfficeMainActivity;
+
+public class FlexibleGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+ private static final String LOGTAG = "GeckoFlexibleGLSurfaceView";
+
+ private GLSurfaceView.Renderer mRenderer;
+ private GLThread mGLThread; // Protected by this class's monitor.
+ private GLController mController;
+ private Listener mListener;
+
+ public FlexibleGLSurfaceView(Context context) {
+ super(context);
+ init();
+ }
+
+ public FlexibleGLSurfaceView(Context context, AttributeSet attributeSet) {
+ super(context, attributeSet);
+ init();
+ }
+
+ public void init() {
+ SurfaceHolder holder = getHolder();
+ holder.addCallback(this);
+ holder.setFormat(PixelFormat.RGB_565);
+
+ mController = new GLController(this);
+ }
+
+ public void setRenderer(GLSurfaceView.Renderer renderer) {
+ mRenderer = renderer;
+ }
+
+ public GLSurfaceView.Renderer getRenderer() {
+ return mRenderer;
+ }
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ public synchronized void requestRender() {
+ if (mGLThread != null) {
+ mGLThread.renderFrame();
+ }
+ if (mListener != null) {
+ mListener.renderRequested();
+ }
+ }
+
+ /**
+ * Creates a Java GL thread. After this is called, the FlexibleGLSurfaceView may be used just
+ * like a GLSurfaceView. It is illegal to access the controller after this has been called.
+ */
+ public synchronized void createGLThread() {
+ if (mGLThread != null) {
+ throw new FlexibleGLSurfaceViewException("createGLThread() called with a GL thread " +
+ "already in place!");
+ }
+
+ Log.e(LOGTAG, "### Creating GL thread!");
+ mGLThread = new GLThread(mController);
+ mGLThread.start();
+ notifyAll();
+ }
+
+ /**
+ * Destroys the Java GL thread. Returns a Thread that completes when the Java GL thread is
+ * fully shut down.
+ */
+ public synchronized Thread destroyGLThread() {
+ // Wait for the GL thread to be started.
+ Log.e(LOGTAG, "### Waiting for GL thread to be created...");
+ while (mGLThread == null) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ Log.e(LOGTAG, "### Destroying GL thread!");
+ Thread glThread = mGLThread;
+ mGLThread.shutdown();
+ mGLThread = null;
+ return glThread;
+ }
+
+ public synchronized void recreateSurface() {
+ if (mGLThread == null) {
+ throw new FlexibleGLSurfaceViewException("recreateSurface() called with no GL " +
+ "thread active!");
+ }
+
+ mGLThread.recreateSurface();
+ }
+
+ public synchronized GLController getGLController() {
+ if (mGLThread != null) {
+ throw new FlexibleGLSurfaceViewException("getGLController() called with a GL thread " +
+ "active; shut down the GL thread first!");
+ }
+
+ return mController;
+ }
+
+ public synchronized void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+ mController.sizeChanged(width, height);
+ if (mGLThread != null) {
+ mGLThread.surfaceChanged(width, height);
+ }
+
+ if (mListener != null) {
+ mListener.surfaceChanged(width, height);
+ }
+ }
+
+ public synchronized void surfaceCreated(SurfaceHolder holder) {
+ mController.surfaceCreated();
+ if (mGLThread != null) {
+ mGLThread.surfaceCreated();
+ }
+ }
+
+ public synchronized void surfaceDestroyed(SurfaceHolder holder) {
+ mController.surfaceDestroyed();
+ if (mGLThread != null) {
+ mGLThread.surfaceDestroyed();
+ }
+
+ if (mListener != null) {
+ mListener.compositionPauseRequested();
+ }
+ }
+
+ // Called from the compositor thread
+ public static GLController registerCxxCompositor() {
+ try {
+ Log.e(LOGTAG, "### registerCxxCompositor point A");
+ System.out.println("register layer comp");
+ Log.e(LOGTAG, "### registerCxxCompositor point B");
+ FlexibleGLSurfaceView flexView = (FlexibleGLSurfaceView) /*GeckoApp*/LibreOfficeMainActivity.mAppContext.getLayerController().getView();
+ Log.e(LOGTAG, "### registerCxxCompositor point C: " + flexView);
+ try {
+ flexView.destroyGLThread().join();
+ } catch (InterruptedException e) {}
+ Log.e(LOGTAG, "### registerCxxCompositor point D: " + flexView.getGLController());
+ return flexView.getGLController();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "### Exception! " + e);
+ return null;
+ }
+ }
+
+ public interface Listener {
+ void renderRequested();
+ void compositionPauseRequested();
+ void compositionResumeRequested();
+ void surfaceChanged(int width, int height);
+ }
+
+ public static class FlexibleGLSurfaceViewException extends RuntimeException {
+ public static final long serialVersionUID = 1L;
+
+ FlexibleGLSurfaceViewException(String e) {
+ super(e);
+ }
+ }
+}
+
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
index 21a712ca7318..5fb73ec18df9 100644
--- 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
@@ -38,21 +38,32 @@
package org.mozilla.gecko.gfx;
-import org.mozilla.gecko.util.FloatUtils;
import org.json.JSONException;
import org.json.JSONObject;
+import org.mozilla.gecko.util.FloatUtils;
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(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");
+ width = (float) json.getDouble("width");
+ height = (float) json.getDouble("height");
} catch (JSONException e) {
throw new RuntimeException(e);
}
@@ -82,7 +93,7 @@ public class FloatSize {
*/
public FloatSize interpolate(FloatSize to, float t) {
return new FloatSize(FloatUtils.interpolate(width, to.width, t),
- FloatUtils.interpolate(height, to.height, t));
+ FloatUtils.interpolate(height, to.height, t));
}
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GLController.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GLController.java
new file mode 100644
index 000000000000..e8f201228666
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GLController.java
@@ -0,0 +1,279 @@
+/* -*- 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) 2011-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@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.util.Log;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL;
+import javax.microedition.khronos.opengles.GL10;
+
+public class GLController {
+ private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ private static final String LOGTAG = "GeckoGLController";
+
+ private FlexibleGLSurfaceView mView;
+ private int mGLVersion;
+ private boolean mSurfaceValid;
+ private int mWidth, mHeight;
+
+ private EGL10 mEGL;
+ private EGLDisplay mEGLDisplay;
+ private EGLConfig mEGLConfig;
+ private EGLContext mEGLContext;
+ private EGLSurface mEGLSurface;
+
+ private GL mGL;
+
+ private static final int LOCAL_EGL_OPENGL_ES2_BIT = 4;
+
+ private static final int[] CONFIG_SPEC = {
+ EGL10.EGL_RED_SIZE, 5,
+ EGL10.EGL_GREEN_SIZE, 6,
+ EGL10.EGL_BLUE_SIZE, 5,
+ EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
+ EGL10.EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+
+ public GLController(FlexibleGLSurfaceView view) {
+ mView = view;
+ mGLVersion = 2;
+ mSurfaceValid = false;
+ }
+
+ public void setGLVersion(int version) {
+ mGLVersion = version;
+ }
+
+ /** You must call this on the same thread you intend to use OpenGL on. */
+ public void initGLContext() {
+ initEGLContext();
+ createEGLSurface();
+ }
+
+ public void disposeGLContext() {
+ if (!mEGL.eglMakeCurrent(mEGLDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_CONTEXT)) {
+ throw new GLControllerException("EGL context could not be released!");
+ }
+
+ if (mEGLSurface != null) {
+ if (!mEGL.eglDestroySurface(mEGLDisplay, mEGLSurface)) {
+ throw new GLControllerException("EGL surface could not be destroyed!");
+ }
+
+ mEGLSurface = null;
+ }
+
+ if (mEGLContext == null) {
+ if (!mEGL.eglDestroyContext(mEGLDisplay, mEGLContext)) {
+ throw new GLControllerException("EGL context could not be destroyed!");
+ }
+
+ mGL = null;
+ mEGLDisplay = null;
+ mEGLConfig = null;
+ mEGLContext = null;
+ }
+ }
+
+ public GL getGL() { return mEGLContext.getGL(); }
+ public EGLDisplay getEGLDisplay() { return mEGLDisplay; }
+ public EGLConfig getEGLConfig() { return mEGLConfig; }
+ public EGLContext getEGLContext() { return mEGLContext; }
+ public EGLSurface getEGLSurface() { return mEGLSurface; }
+ public FlexibleGLSurfaceView getView() { return mView; }
+
+ public boolean hasSurface() {
+ return mEGLSurface != null;
+ }
+
+ public boolean swapBuffers() {
+ return mEGL.eglSwapBuffers(mEGLDisplay, mEGLSurface);
+ }
+
+ public boolean checkForLostContext() {
+ if (mEGL.eglGetError() != EGL11.EGL_CONTEXT_LOST) {
+ return false;
+ }
+
+ mEGLDisplay = null;
+ mEGLConfig = null;
+ mEGLContext = null;
+ mEGLSurface = null;
+ mGL = null;
+ return true;
+ }
+
+ public synchronized void waitForValidSurface() {
+ while (!mSurfaceValid) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public synchronized int getWidth() {
+ return mWidth;
+ }
+
+ public synchronized int getHeight() {
+ return mHeight;
+ }
+
+ synchronized void surfaceCreated() {
+ mSurfaceValid = true;
+ notifyAll();
+ }
+
+ synchronized void surfaceDestroyed() {
+ mSurfaceValid = false;
+ notifyAll();
+ }
+
+ synchronized void sizeChanged(int newWidth, int newHeight) {
+ mWidth = newWidth;
+ mHeight = newHeight;
+ }
+
+ private void initEGL() {
+ mEGL = (EGL10)EGLContext.getEGL();
+
+ mEGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ if (mEGLDisplay == EGL10.EGL_NO_DISPLAY) {
+ throw new GLControllerException("eglGetDisplay() failed");
+ }
+
+ int[] version = new int[2];
+ if (!mEGL.eglInitialize(mEGLDisplay, version)) {
+ throw new GLControllerException("eglInitialize() failed");
+ }
+
+ mEGLConfig = chooseConfig();
+ }
+
+ private void initEGLContext() {
+ initEGL();
+
+ int[] attribList = { EGL_CONTEXT_CLIENT_VERSION, mGLVersion, EGL10.EGL_NONE };
+ mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, EGL10.EGL_NO_CONTEXT,
+ attribList);
+ if (mEGLContext == null || mEGLContext == EGL10.EGL_NO_CONTEXT) {
+ throw new GLControllerException("createContext() failed");
+ }
+ }
+
+ private EGLConfig chooseConfig() {
+ int[] numConfigs = new int[1];
+ if (!mEGL.eglChooseConfig(mEGLDisplay, CONFIG_SPEC, null, 0, numConfigs) ||
+ numConfigs[0] <= 0) {
+ throw new GLControllerException("No available EGL configurations");
+ }
+
+ EGLConfig[] configs = new EGLConfig[numConfigs[0]];
+ if (!mEGL.eglChooseConfig(mEGLDisplay, CONFIG_SPEC, configs, numConfigs[0], numConfigs)) {
+ throw new GLControllerException("No EGL configuration for that specification");
+ }
+
+ // Select the first 565 RGB configuration.
+ int[] red = new int[1], green = new int[1], blue = new int[1];
+ for (EGLConfig config : configs) {
+ mEGL.eglGetConfigAttrib(mEGLDisplay, config, EGL10.EGL_RED_SIZE, red);
+ mEGL.eglGetConfigAttrib(mEGLDisplay, config, EGL10.EGL_GREEN_SIZE, green);
+ mEGL.eglGetConfigAttrib(mEGLDisplay, config, EGL10.EGL_BLUE_SIZE, blue);
+ if (red[0] == 5 && green[0] == 6 && blue[0] == 5) {
+ return config;
+ }
+ }
+
+ throw new GLControllerException("No suitable EGL configuration found");
+ }
+
+ private void createEGLSurface() {
+ SurfaceHolder surfaceHolder = mView.getHolder();
+ mEGLSurface = mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surfaceHolder, null);
+ if (mEGLSurface == null || mEGLSurface == EGL10.EGL_NO_SURFACE) {
+ throw new GLControllerException("EGL window surface could not be created!");
+ }
+
+ if (!mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) {
+ throw new GLControllerException("EGL surface could not be made into the current " +
+ "surface!");
+ }
+
+ mGL = mEGLContext.getGL();
+
+ if (mView.getRenderer() != null) {
+ mView.getRenderer().onSurfaceCreated((GL10)mGL, mEGLConfig);
+ mView.getRenderer().onSurfaceChanged((GL10)mGL, mView.getWidth(), mView.getHeight());
+ }
+ }
+
+ // Provides an EGLSurface without assuming ownership of this surface.
+ private EGLSurface provideEGLSurface() {
+ if (mEGL == null) {
+ initEGL();
+ }
+
+ SurfaceHolder surfaceHolder = mView.getHolder();
+ mEGLSurface = mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surfaceHolder, null);
+ if (mEGLSurface == null || mEGLSurface == EGL10.EGL_NO_SURFACE) {
+ throw new GLControllerException("EGL window surface could not be created!");
+ }
+
+ return mEGLSurface;
+ }
+
+ public static class GLControllerException extends RuntimeException {
+ public static final long serialVersionUID = 1L;
+
+ GLControllerException(String e) {
+ super(e);
+ }
+ }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GLThread.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GLThread.java
new file mode 100644
index 000000000000..4f788f64ebcb
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GLThread.java
@@ -0,0 +1,181 @@
+/* -*- 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) 2011-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@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.opengl.GLSurfaceView;
+import android.view.SurfaceHolder;
+import javax.microedition.khronos.opengles.GL10;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+
+// A GL thread managed by Java. It is not necessary to use this class to use the
+// FlexibleGLSurfaceView, but it can be helpful, especially if the GL rendering is to be done
+// entirely in Java.
+class GLThread extends Thread {
+ private LinkedBlockingQueue<Runnable> mQueue;
+ private GLController mController;
+ private boolean mRenderQueued;
+
+ public GLThread(GLController controller) {
+ mQueue = new LinkedBlockingQueue<Runnable>();
+ mController = controller;
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ Runnable runnable;
+ try {
+ runnable = mQueue.take();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ runnable.run();
+ if (runnable instanceof ShutdownMessage) {
+ break;
+ }
+ }
+ }
+
+ public void recreateSurface() {
+ mQueue.add(new RecreateSurfaceMessage());
+ }
+
+ public void renderFrame() {
+ // Make sure there's only one render event in the queue at a time.
+ synchronized (this) {
+ if (!mRenderQueued) {
+ mQueue.add(new RenderFrameMessage());
+ mRenderQueued = true;
+ }
+ }
+ }
+
+ public void shutdown() {
+ mQueue.add(new ShutdownMessage());
+ }
+
+ public void surfaceChanged(int width, int height) {
+ mQueue.add(new SizeChangedMessage(width, height));
+ }
+
+ public void surfaceCreated() {
+ mQueue.add(new SurfaceCreatedMessage());
+ }
+
+ public void surfaceDestroyed() {
+ mQueue.add(new SurfaceDestroyedMessage());
+ }
+
+ private void doRecreateSurface() {
+ mController.disposeGLContext();
+ mController.initGLContext();
+ }
+
+ private GLSurfaceView.Renderer getRenderer() {
+ return mController.getView().getRenderer();
+ }
+
+ private class RecreateSurfaceMessage implements Runnable {
+ public void run() {
+ doRecreateSurface();
+ }
+ }
+
+ private class RenderFrameMessage implements Runnable {
+ public void run() {
+ synchronized (GLThread.this) {
+ mRenderQueued = false;
+ }
+
+ // Bail out if the surface was lost.
+ if (mController.getEGLSurface() == null) {
+ return;
+ }
+
+ GLSurfaceView.Renderer renderer = getRenderer();
+ if (renderer != null) {
+ renderer.onDrawFrame((GL10)mController.getGL());
+ }
+
+ mController.swapBuffers();
+ //if (!mController.swapBuffers() && mController.checkForLostContext()) {
+ // doRecreateSurface();
+ //}
+ }
+ }
+
+ private class ShutdownMessage implements Runnable {
+ public void run() {
+ mController.disposeGLContext();
+ mController = null;
+ }
+ }
+
+ private class SizeChangedMessage implements Runnable {
+ private int mWidth, mHeight;
+
+ public SizeChangedMessage(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ }
+
+ public void run() {
+ GLSurfaceView.Renderer renderer = getRenderer();
+ if (renderer != null) {
+ renderer.onSurfaceChanged((GL10)mController.getGL(), mWidth, mHeight);
+ }
+ }
+ }
+
+ private class SurfaceCreatedMessage implements Runnable {
+ public void run() {
+ if (!mController.hasSurface()) {
+ mController.initGLContext();
+ }
+ }
+ }
+
+ private class SurfaceDestroyedMessage implements Runnable {
+ public void run() {
+ mController.disposeGLContext();
+ }
+ }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoGLLayerClient.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoGLLayerClient.java
new file mode 100644
index 000000000000..9e4f376e7ad2
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoGLLayerClient.java
@@ -0,0 +1,265 @@
+/* -*- 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@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.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.View;
+
+import org.libreoffice.LOEvent;
+import org.libreoffice.LOKitShell;
+
+public class GeckoGLLayerClient extends GeckoLayerClient
+ implements FlexibleGLSurfaceView.Listener, VirtualLayer.Listener {
+ private static final String LOGTAG = "GeckoGLLayerClient";
+
+ private LayerRenderer mLayerRenderer;
+ private boolean mLayerRendererInitialized;
+
+ public GeckoGLLayerClient(Context context) {
+ super(context);
+ }
+
+ @Override
+ public Rect beginDrawing(int width, int height, int tileWidth, int tileHeight,
+ String metadata, boolean hasDirectTexture) {
+ Rect bufferRect = super.beginDrawing(width, height, tileWidth, tileHeight,
+ metadata, hasDirectTexture);
+ if (bufferRect == null) {
+ return null;
+ }
+
+ // Be sure to adjust the buffer size; if it's not at least as large as the viewport size,
+ // ViewportMetrics.getOptimumViewportOffset() gets awfully confused and severe display
+ // corruption results!
+ if (mBufferSize.width != width || mBufferSize.height != height) {
+ mBufferSize = new IntSize(width, height);
+ }
+
+ return bufferRect;
+ }
+
+ @Override
+ protected boolean handleDirectTextureChange(boolean hasDirectTexture) {
+ Log.e(LOGTAG, "### handleDirectTextureChange");
+ if (mTileLayer != null) {
+ return false;
+ }
+
+ Log.e(LOGTAG, "### Creating virtual layer");
+ VirtualLayer virtualLayer = new VirtualLayer();
+ virtualLayer.setListener(this);
+ virtualLayer.setSize(getBufferSize());
+ getLayerController().setRoot(virtualLayer);
+ mTileLayer = virtualLayer;
+
+ sendResizeEventIfNecessary(true);
+ return true;
+ }
+
+ @Override
+ public void setLayerController(LayerController layerController) {
+ super.setLayerController(layerController);
+
+ LayerView view = layerController.getView();
+ view.setListener(this);
+
+ mLayerRenderer = new LayerRenderer(view);
+ }
+
+ @Override
+ protected boolean shouldDrawProceed(int tileWidth, int tileHeight) {
+ Log.e(LOGTAG, "### shouldDrawProceed");
+ // Always draw.
+ return true;
+ }
+
+ @Override
+ protected void updateLayerAfterDraw(Rect updatedRect) {
+ Log.e(LOGTAG, "### updateLayerAfterDraw");
+ // Nothing to do.
+ }
+
+ @Override
+ protected IntSize getBufferSize() {
+ View view = (View) getLayerController().getView();
+ IntSize size = new IntSize(view.getWidth(), view.getHeight());
+ Log.e(LOGTAG, "### getBufferSize " + size);
+ return size;
+ }
+
+ @Override
+ protected IntSize getTileSize() {
+ Log.e(LOGTAG, "### getTileSize " + getBufferSize());
+ return getBufferSize();
+ }
+
+ @Override
+ protected void tileLayerUpdated() {
+ // Set the new origin and resolution instantly.
+ mTileLayer.performUpdates(null);
+ }
+
+ @Override
+ public Bitmap getBitmap() {
+ Log.e(LOGTAG, "### getBitmap");
+ IntSize size = getBufferSize();
+ try {
+ return Bitmap.createBitmap(size.width, size.height, Bitmap.Config.RGB_565);
+ } catch (OutOfMemoryError oom) {
+ Log.e(LOGTAG, "Unable to create bitmap", oom);
+ return null;
+ }
+ }
+
+ @Override
+ public int getType() {
+ Log.e(LOGTAG, "### getType");
+ return LAYER_CLIENT_TYPE_GL;
+ }
+
+ public void dimensionsChanged(Point newOrigin, float newResolution) {
+ Log.e(LOGTAG, "### dimensionsChanged " + newOrigin + " " + newResolution);
+ }
+
+ /* Informs Gecko that the screen size has changed. */
+ @Override
+ protected void sendResizeEventIfNecessary(boolean force) {
+ Log.e(LOGTAG, "### sendResizeEventIfNecessary " + force);
+
+ IntSize newSize = getBufferSize();
+ if (!force && mScreenSize != null && mScreenSize.equals(newSize)) {
+ return;
+ }
+
+ mScreenSize = newSize;
+
+ Log.e(LOGTAG, "### Screen-size changed to " + mScreenSize);
+ //GeckoEvent event = GeckoEvent.createSizeChangedEvent(mScreenSize.width, mScreenSize.height,
+ // mScreenSize.width, mScreenSize.height,
+ // mScreenSize.width, mScreenSize.height);
+ //GeckoAppShell.sendEventToGecko(event);
+ LOEvent event = LOEvent.sizeChanged(mScreenSize.width, mScreenSize.height,
+ mScreenSize.width, mScreenSize.height,
+ mScreenSize.width, mScreenSize.height);
+ LOKitShell.sendEvent(event);
+
+ }
+
+ /**
+ * For Gecko to use.
+ */
+ public ViewTransform getViewTransform() {
+ Log.e(LOGTAG, "### getViewTransform()");
+
+ // NB: We don't begin a transaction here because this can be called in a synchronous
+ // manner between beginDrawing() and endDrawing(), and that will cause a deadlock.
+
+ LayerController layerController = getLayerController();
+ synchronized (layerController) {
+ ViewportMetrics viewportMetrics = layerController.getViewportMetrics();
+ PointF viewportOrigin = viewportMetrics.getOrigin();
+ Point tileOrigin = mTileLayer.getOrigin();
+ float scrollX = viewportOrigin.x;
+ float scrollY = viewportOrigin.y;
+ float zoomFactor = viewportMetrics.getZoomFactor();
+ Log.e(LOGTAG, "### Viewport metrics = " + viewportMetrics + " tile reso = " +
+ mTileLayer.getResolution());
+ return new ViewTransform(scrollX, scrollY, zoomFactor);
+ }
+ }
+
+ public void renderRequested() {
+ Log.e(LOGTAG, "### Render requested, scheduling composite");
+ LOKitShell.scheduleComposite();
+ }
+
+ public void compositionPauseRequested() {
+ Log.e(LOGTAG, "### Scheduling PauseComposition");
+ LOKitShell.schedulePauseComposition();
+ }
+
+ public void compositionResumeRequested() {
+ Log.e(LOGTAG, "### Scheduling ResumeComposition");
+ LOKitShell.scheduleResumeComposition();
+ }
+
+ public void surfaceChanged(int width, int height) {
+ compositionPauseRequested();
+ LayerController layerController = getLayerController();
+ layerController.setViewportSize(new FloatSize(width, height));
+ compositionResumeRequested();
+ renderRequested();
+ }
+
+ /**
+ * For Gecko to use.
+ */
+ public LayerRenderer.Frame createFrame() {
+ // Create the shaders and textures if necessary.
+ if (!mLayerRendererInitialized) {
+ mLayerRenderer.createProgram();
+ mLayerRendererInitialized = true;
+ }
+
+ // Build the contexts and create the frame.
+ Layer.RenderContext pageContext = mLayerRenderer.createPageContext();
+ Layer.RenderContext screenContext = mLayerRenderer.createScreenContext();
+ return mLayerRenderer.createFrame(pageContext, screenContext);
+ }
+
+ /**
+ * For Gecko to use.
+ */
+ public void activateProgram() {
+ mLayerRenderer.activateProgram();
+ }
+
+ /**
+ * For Gecko to use.
+ */
+ public void deactivateProgram() {
+ mLayerRenderer.deactivateProgram();
+ }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
new file mode 100644
index 000000000000..09349b4eea07
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
@@ -0,0 +1,414 @@
+/* -*- 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@mozilla.com>
+ * Chris Lord <chrislord.net@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.libreoffice.LOEvent;
+import org.libreoffice.LOKitShell;
+import org.libreoffice.LibreOfficeMainActivity;
+import org.mozilla.gecko.util.FloatUtils;
+//import org.mozilla.gecko.GeckoApp;
+//import org.mozilla.gecko.GeckoAppShell;
+//import org.mozilla.gecko.GeckoEvent;
+import org.mozilla.gecko.GeckoEventListener;
+import org.json.JSONException;
+import org.json.JSONObject;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class GeckoLayerClient extends LayerClient implements GeckoEventListener {
+ private static final String LOGTAG = "GeckoLayerClient";
+
+ public static final int LAYER_CLIENT_TYPE_NONE = 0;
+ public static final int LAYER_CLIENT_TYPE_SOFTWARE = 1;
+ public static final int LAYER_CLIENT_TYPE_GL = 2;
+
+ protected IntSize mScreenSize;
+ protected IntSize mBufferSize;
+
+ protected Layer mTileLayer;
+
+ /* The viewport that Gecko is currently displaying. */
+ protected ViewportMetrics mGeckoViewport;
+
+ /* The viewport that Gecko will display when drawing is finished */
+ protected ViewportMetrics mNewGeckoViewport;
+
+ private static final long MIN_VIEWPORT_CHANGE_DELAY = 25L;
+ private long mLastViewportChangeTime;
+ private boolean mPendingViewportAdjust;
+ private boolean mViewportSizeChanged;
+
+ // 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;
+
+ private String mLastCheckerboardColor;
+
+ private static Pattern sColorPattern;
+
+ /* Used by robocop for testing purposes */
+ private DrawListener mDrawListener;
+
+ protected abstract boolean handleDirectTextureChange(boolean hasDirectTexture);
+ protected abstract boolean shouldDrawProceed(int tileWidth, int tileHeight);
+ protected abstract void updateLayerAfterDraw(Rect updatedRect);
+ protected abstract IntSize getBufferSize();
+ protected abstract IntSize getTileSize();
+ protected abstract void tileLayerUpdated();
+ public abstract Bitmap getBitmap();
+ public abstract int getType();
+
+ public GeckoLayerClient(Context context) {
+ mScreenSize = new IntSize(0, 0);
+ mBufferSize = new IntSize(0, 0);
+ }
+
+ /** 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);
+
+ sendResizeEventIfNecessary();
+ }
+
+ public Rect beginDrawing(int width, int height, int tileWidth, int tileHeight,
+ String metadata, boolean hasDirectTexture) {
+ Log.e(LOGTAG, "### beginDrawing " + width + " " + height + " " + tileWidth + " " +
+ tileHeight + " " + hasDirectTexture);
+
+ // If we've changed surface types, cancel this draw
+ if (handleDirectTextureChange(hasDirectTexture)) {
+ Log.e(LOGTAG, "### Cancelling draw due to direct texture change");
+ return null;
+ }
+
+ if (!shouldDrawProceed(tileWidth, tileHeight)) {
+ Log.e(LOGTAG, "### Cancelling draw due to shouldDrawProceed()");
+ return null;
+ }
+
+ LayerController controller = getLayerController();
+
+ try {
+ JSONObject viewportObject = new JSONObject(metadata);
+ mNewGeckoViewport = new ViewportMetrics(viewportObject);
+
+ Log.e(LOGTAG, "### beginDrawing new Gecko viewport " + mNewGeckoViewport);
+
+ // Update the background color, if it's present.
+ String backgroundColorString = viewportObject.optString("backgroundColor");
+ if (backgroundColorString != null && !backgroundColorString.equals(mLastCheckerboardColor)) {
+ mLastCheckerboardColor = backgroundColorString;
+ controller.setCheckerboardColor(parseColorFromGecko(backgroundColorString));
+ }
+ } catch (JSONException e) {
+ Log.e(LOGTAG, "Aborting draw, bad viewport description: " + metadata);
+ return null;
+ }
+
+
+ // Make sure we don't spend time painting areas we aren't interested in.
+ // Only do this if the Gecko viewport isn't going to override our viewport.
+ Rect bufferRect = new Rect(0, 0, width, height);
+
+ if (!mUpdateViewportOnEndDraw) {
+ // First, find out our ideal displayport. We do this by taking the
+ // clamped viewport origin and taking away the optimum viewport offset.
+ // This would be what we would send to Gecko if adjustViewport were
+ // called now.
+ ViewportMetrics currentMetrics = controller.getViewportMetrics();
+ PointF currentBestOrigin = RectUtils.getOrigin(currentMetrics.getClampedViewport());
+ PointF viewportOffset = currentMetrics.getOptimumViewportOffset(new IntSize(width, height));
+ currentBestOrigin.offset(-viewportOffset.x, -viewportOffset.y);
+
+ Rect currentRect = RectUtils.round(new RectF(currentBestOrigin.x, currentBestOrigin.y,
+ currentBestOrigin.x + width, currentBestOrigin.y + height));
+
+ // Second, store Gecko's displayport.
+ PointF currentOrigin = mNewGeckoViewport.getDisplayportOrigin();
+ bufferRect = RectUtils.round(new RectF(currentOrigin.x, currentOrigin.y,
+ currentOrigin.x + width, currentOrigin.y + height));
+
+
+ // Take the intersection of the two as the area we're interested in rendering.
+ if (!bufferRect.intersect(currentRect)) {
+ // If there's no intersection, we have no need to render anything,
+ // but make sure to update the viewport size.
+ beginTransaction(mTileLayer);
+ try {
+ updateViewport(true);
+ } finally {
+ endTransaction(mTileLayer);
+ }
+ return null;
+ }
+ bufferRect.offset(Math.round(-currentOrigin.x), Math.round(-currentOrigin.y));
+ }
+
+ beginTransaction(mTileLayer);
+ return bufferRect;
+ }
+
+ /*
+ * 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) {
+ synchronized (getLayerController()) {
+ try {
+ updateViewport(!mUpdateViewportOnEndDraw);
+ mUpdateViewportOnEndDraw = false;
+
+ Rect rect = new Rect(x, y, x + width, y + height);
+ updateLayerAfterDraw(rect);
+ } finally {
+ endTransaction(mTileLayer);
+ }
+ }
+ Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - endDrawing");
+
+ /* Used by robocop for testing purposes */
+ if (mDrawListener != null) {
+ mDrawListener.drawFinished(x, y, width, height);
+ }
+ }
+
+ protected void updateViewport(boolean onlyUpdatePageSize) {
+ // 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 = mNewGeckoViewport;
+ mGeckoViewport.setSize(viewportSize);
+
+ LayerController controller = getLayerController();
+ PointF displayportOrigin = mGeckoViewport.getDisplayportOrigin();
+ mTileLayer.setOrigin(PointUtils.round(displayportOrigin));
+ mTileLayer.setResolution(mGeckoViewport.getZoomFactor());
+
+ this.tileLayerUpdated();
+ Log.e(LOGTAG, "### updateViewport onlyUpdatePageSize=" + onlyUpdatePageSize +
+ " getTileViewport " + mGeckoViewport);
+
+ 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 {
+ controller.setViewportMetrics(mGeckoViewport);
+ controller.abortPanZoomAnimation();
+ }
+ }
+
+ /* Informs Gecko that the screen size has changed. */
+ protected void sendResizeEventIfNecessary(boolean force) {
+ Log.e(LOGTAG, "### sendResizeEventIfNecessary " + force);
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ /*GeckoApp*/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 = getBufferSize(), tileSize = getTileSize();
+
+ Log.e(LOGTAG, "### Screen-size changed to " + mScreenSize);
+ //GeckoEvent event = GeckoEvent.createSizeChangedEvent(bufferSize.width, bufferSize.height,
+ // metrics.widthPixels, metrics.heightPixels,
+ // tileSize.width, tileSize.height);
+ //GeckoAppShell.sendEventToGecko(event);
+ LOEvent event = LOEvent.sizeChanged(bufferSize.width, bufferSize.height,
+ metrics.widthPixels, metrics.heightPixels,
+ tileSize.width, tileSize.height);
+ }
+
+ // 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);
+ }
+
+ @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();
+ }
+
+ @Override
+ public void viewportSizeChanged() {
+ mViewportSizeChanged = true;
+ }
+
+ private void adjustViewport() {
+ ViewportMetrics viewportMetrics =
+ new ViewportMetrics(getLayerController().getViewportMetrics());
+
+ PointF viewportOffset = viewportMetrics.getOptimumViewportOffset(mBufferSize);
+ viewportMetrics.setViewportOffset(viewportOffset);
+ viewportMetrics.setViewport(viewportMetrics.getClampedViewport());
+
+ //GeckoAppShell.sendEventToGecko(GeckoEvent.createViewportEvent(viewportMetrics));
+ LOKitShell.sendEvent(LOEvent.viewport(viewportMetrics));
+ if (mViewportSizeChanged) {
+ mViewportSizeChanged = false;
+ //GeckoAppShell.viewSizeChanged();
+ LOKitShell.viewSizeChanged();
+ }
+
+ mLastViewportChangeTime = System.currentTimeMillis();
+ }
+
+ public void handleMessage(String event, JSONObject message) {
+ if ("Viewport:UpdateAndDraw".equals(event)) {
+ Log.e(LOGTAG, "### Java side Viewport:UpdateAndDraw()!");
+ mUpdateViewportOnEndDraw = true;
+
+ // Redraw everything.
+ Rect rect = new Rect(0, 0, mBufferSize.width, mBufferSize.height);
+ //GeckoAppShell.sendEventToGecko(GeckoEvent.createDrawEvent(rect));
+ LOKitShell.sendEvent(LOEvent.draw(rect));
+ } else if ("Viewport:UpdateLater".equals(event)) {
+ Log.e(LOGTAG, "### Java side Viewport:UpdateLater()!");
+ mUpdateViewportOnEndDraw = true;
+ }
+ }
+
+ @Override
+ public void geometryChanged() {
+ /* Let Gecko know if the screensize has changed */
+ sendResizeEventIfNecessary();
+ render();
+ }
+
+ public int getWidth() {
+ return mBufferSize.width;
+ }
+
+ public int getHeight() {
+ return mBufferSize.height;
+ }
+
+ public ViewportMetrics getGeckoViewportMetrics() {
+ // Return a copy, as we modify this inside the Gecko thread
+ if (mGeckoViewport != null)
+ return new ViewportMetrics(mGeckoViewport);
+ return null;
+ }
+
+ private void sendResizeEventIfNecessary() {
+ sendResizeEventIfNecessary(false);
+ }
+
+ /** Used by robocop for testing purposes. Not for production use! This is called via reflection by robocop. */
+ public void setDrawListener(DrawListener listener) {
+ mDrawListener = listener;
+ }
+
+ /** Used by robocop for testing purposes. Not for production use! This is used via reflection by robocop. */
+ public interface DrawListener {
+ public void drawFinished(int x, int y, int width, int height);
+ }
+}
+
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
index 9385d8185bf0..97cbfb49acf8 100644
--- 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
@@ -38,130 +38,70 @@
package org.mozilla.gecko.gfx;
+import org.libreoffice.LOKitShell;
+import org.mozilla.gecko.gfx.CairoImage;
+import org.mozilla.gecko.gfx.IntSize;
+import org.mozilla.gecko.gfx.LayerClient;
+import org.mozilla.gecko.gfx.LayerController;
+import org.mozilla.gecko.gfx.LayerRenderer;
+import org.mozilla.gecko.gfx.MultiTileLayer;
+import org.mozilla.gecko.gfx.PointUtils;
+import org.mozilla.gecko.gfx.WidgetTileLayer;
+//import org.mozilla.gecko.GeckoAppShell;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PointF;
+import android.graphics.Point;
import android.graphics.Rect;
-import android.util.DisplayMetrics;
+import android.graphics.RectF;
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 {
+public class GeckoSoftwareLayerClient extends GeckoLayerClient {
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 IntSize mViewportSize;
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;
+
+ private static final IntSize TILE_SIZE = new IntSize(256, 256);
+
// 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;
+ super(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;
- }
-
+ public ByteBuffer getBuffer() { return mBuffer; }
@Override
- public IntSize getSize() {
- return mBufferSize;
- }
-
+ public IntSize getSize() { return mBufferSize; }
@Override
- public int getFormat() {
- return mFormat;
- }
+ 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);
+ 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);
@@ -172,142 +112,100 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
//GeckoAppShell.registerGeckoEventListener("Viewport:UpdateAndDraw", this);
//GeckoAppShell.registerGeckoEventListener("Viewport:UpdateLater", this);
+ //GeckoAppShell.registerGeckoEventListener("Checkerboard:Toggle", 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();
+ // XXX: Review pcwalton. This signature changed on m-c, should force = false here?
+ sendResizeEventIfNecessary(false);
}
- private void setHasDirectTexture(boolean hasDirectTexture) {
- if (hasDirectTexture == mHasDirectTexture)
- return;
+ @Override
+ protected boolean handleDirectTextureChange(boolean hasDirectTexture) {
+ if (mTileLayer != null && hasDirectTexture == mHasDirectTexture)
+ return false;
mHasDirectTexture = hasDirectTexture;
- IntSize tileSize;
if (mHasDirectTexture) {
+ Log.i(LOGTAG, "Creating WidgetTileLayer");
mTileLayer = new WidgetTileLayer(mCairoImage);
- tileSize = new IntSize(0, 0);
} else {
+ Log.i(LOGTAG, "Creating MultiTileLayer");
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);
- }
- }
+ return true;
}
- 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();
+ @Override
+ protected boolean shouldDrawProceed(int tileWidth, int tileHeight) {
+ // Make sure the tile-size matches. If it doesn't, we could crash trying
+ // to access invalid memory.
+ if (mHasDirectTexture) {
+ if (tileWidth != 0 || tileHeight != 0) {
+ Log.e(LOGTAG, "Aborting draw, incorrect tile size of " + tileWidth + "x" +
+ tileHeight);
+ return false;
}
-
- // Update the background color, if it's present.
- String backgroundColorString = viewportObject.optString("backgroundColor");
- if (backgroundColorString != null) {
- controller.setCheckerboardColor(parseColorFromGecko(backgroundColorString));
+ } else {
+ if (tileWidth != TILE_SIZE.width || tileHeight != TILE_SIZE.height) {
+ Log.e(LOGTAG, "Aborting draw, incorrect tile size of " + tileWidth + "x" +
+ tileHeight);
+ return false;
}
- } catch (JSONException e) {
- Log.e(LOGTAG, "Bad viewport description: " + viewportDescription);
- throw new RuntimeException(e);
}
- }
- public ByteBuffer getBuffer() {
- return mBuffer;
+ return true;
}
- /*
- * 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);
+ @Override
+ public Rect beginDrawing(int width, int height, int tileWidth, int tileHeight,
+ String metadata, boolean hasDirectTexture) {
+ Rect bufferRect = super.beginDrawing(width, height, tileWidth, tileHeight,
+ metadata, hasDirectTexture);
+ if (bufferRect == null) {
+ return bufferRect;
+ }
- setHasDirectTexture(hasDirectTexture);
+ // If the window size has changed, reallocate the buffer to match.
+ if (mBufferSize.width != width || mBufferSize.height != height) {
+ mBufferSize = new IntSize(width, height);
- if (!mHasDirectTexture)
- ((MultiTileLayer) mTileLayer).invalidate(rect);
- } finally {
- endTransaction(mTileLayer);
+ // Reallocate the buffer if necessary
+ if (mTileLayer instanceof MultiTileLayer) {
+ int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8;
+ int size = mBufferSize.getArea() * bpp;
+ if (mBuffer == null || mBuffer.capacity() != size) {
+ // Free the old buffer
+ if (mBuffer != null) {
+ LOKitShell.freeDirectBuffer(mBuffer);
+ mBuffer = null;
+ }
+
+ mBuffer = LOKitShell.allocateDirectBuffer(size);
+ }
}
}
+
+ return bufferRect;
}
- public ViewportMetrics getGeckoViewportMetrics() {
- // Return a copy, as we modify this inside the Gecko thread
- if (mGeckoViewport != null)
- return new ViewportMetrics(mGeckoViewport);
- return null;
+ @Override
+ protected void updateLayerAfterDraw(Rect updatedRect) {
+ if (!(mTileLayer instanceof MultiTileLayer)) {
+ return;
+ }
+
+ ((MultiTileLayer)mTileLayer).invalidate(updatedRect);
}
- public void copyPixelsFromMultiTileLayer(Bitmap target) {
- Canvas canvas = new Canvas(target);
+ private void copyPixelsFromMultiTileLayer(Bitmap target) {
+ Canvas c = new Canvas(target);
ByteBuffer tileBuffer = mBuffer.slice();
int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8;
@@ -323,7 +221,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
tile.copyPixelsFromBuffer(tileBuffer.asIntBuffer());
// Copy the tile to the master Bitmap and recycle it
- canvas.drawBitmap(tile, x, y, null);
+ c.drawBitmap(tile, x, y, null);
tile.recycle();
// Progress the buffer to the next tile
@@ -333,7 +231,16 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
}
}
+ @Override
+ protected void tileLayerUpdated() {
+ /* No-op. */
+ }
+
+ @Override
public Bitmap getBitmap() {
+ if (mTileLayer == null)
+ return null;
+
// Begin a tile transaction, otherwise the buffer can be destroyed while
// we're reading from it.
beginTransaction(mTileLayer);
@@ -341,21 +248,17 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
if (mBuffer == null || mBufferSize.width <= 0 || mBufferSize.height <= 0)
return null;
try {
- Bitmap bitmap = null;
+ Bitmap b = null;
if (mTileLayer instanceof MultiTileLayer) {
- bitmap = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,
+ b = 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());
+ copyPixelsFromMultiTileLayer(b);
} else {
Log.w(LOGTAG, "getBitmap() called on a layer (" + mTileLayer + ") we don't know how to get a bitmap from");
}
- return bitmap;
+ return b;
} catch (OutOfMemoryError oom) {
Log.w(LOGTAG, "Unable to create bitmap", oom);
return null;
@@ -365,9 +268,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
}
}
- /**
- * Returns the back buffer. This function is for Gecko to use.
- */
+ /** Returns the back buffer. This function is for Gecko to use. */
public ByteBuffer lockBuffer() {
return mBuffer;
}
@@ -381,125 +282,41 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
}
@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;
+ public int getType() {
+ return LAYER_CLIENT_TYPE_SOFTWARE;
}
@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;
+ protected IntSize getBufferSize() {
+ // Round up depending on layer implementation to remove texture wastage
+ if (!mHasDirectTexture) {
+ // Round to the next multiple of the tile size
+ return 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);
}
- adjustViewport();
- }
-
- private void adjustViewport() {
- ViewportMetrics viewportMetrics = new ViewportMetrics(getLayerController().getViewportMetrics());
+ int maxSize = getLayerController().getView().getMaxTextureSize();
- 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();
+ // 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);
}
- mLastViewportChangeTime = System.currentTimeMillis();
+ // Round to next power of two until we have NPOT texture support, respecting maximum
+ // texture size
+ return new IntSize(Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.width +
+ LayerController.MIN_BUFFER.width)),
+ Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.height +
+ LayerController.MIN_BUFFER.height)));
}
- 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;
- }
+ @Override
+ protected IntSize getTileSize() {
+ // Round up depending on layer implementation to remove texture wastage
+ return !mHasDirectTexture ? TILE_SIZE : new IntSize(0, 0);
}
}
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
index 17ecbba4058b..2dd3316f0016 100644
--- 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
@@ -21,6 +21,7 @@
* Contributor(s):
* Patrick Walton <pcwalton@mozilla.com>
* Chris Lord <chrislord.net@gmail.com>
+ * Arkady Blyakher <rkadyb@mit.edu>
*
* 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
@@ -39,24 +40,23 @@
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;
+import java.nio.FloatBuffer;
+import java.util.concurrent.locks.ReentrantLock;
+
public abstract class Layer {
private final ReentrantLock mTransactionLock;
+ protected Point mOrigin;
+ protected float mResolution;
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);
@@ -67,7 +67,7 @@ public abstract class Layer {
* 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) {
+ public final boolean update(RenderContext context) {
if (mTransactionLock.isHeldByCurrentThread()) {
throw new RuntimeException("draw() called while transaction lock held by this " +
"thread?!");
@@ -75,7 +75,7 @@ public abstract class Layer {
if (mTransactionLock.tryLock()) {
try {
- return performUpdates(gl, context);
+ return performUpdates(context);
} finally {
mTransactionLock.unlock();
}
@@ -84,13 +84,19 @@ public abstract class Layer {
return false;
}
- /** Subclasses override this function to draw the layer. */
+ /**
+ * 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. */
+ /**
+ * 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. */
+ /**
+ * 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;
@@ -111,7 +117,7 @@ public abstract class Layer {
* 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.
- *
+ * <p/>
* This function may block, so you should never call this on the main UI thread.
*/
public void beginTransaction(LayerView aView) {
@@ -127,7 +133,9 @@ public abstract class Layer {
beginTransaction(null);
}
- /** Call this when you're done modifying the layer. */
+ /**
+ * Call this when you're done modifying the layer.
+ */
public void endTransaction() {
if (!mInTransaction)
throw new RuntimeException("endTransaction() called outside a transaction");
@@ -138,24 +146,32 @@ public abstract class Layer {
mView.requestRender();
}
- /** Returns true if the layer is currently in a transaction and false otherwise. */
+ /**
+ * Returns true if the layer is currently in a transaction and false otherwise.
+ */
protected boolean inTransaction() {
return mInTransaction;
}
- /** Returns the current layer origin. */
+ /**
+ * Returns the current layer origin.
+ */
public Point getOrigin() {
return mOrigin;
}
- /** Sets the origin. Only valid inside a transaction. */
+ /**
+ * 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. */
+ /**
+ * Returns the current layer's resolution.
+ */
public float getResolution() {
return mResolution;
}
@@ -164,7 +180,8 @@ public abstract class Layer {
* 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. */
+ * Only valid inside a transaction.
+ */
public void setResolution(float newResolution) {
if (!mInTransaction)
throw new RuntimeException("setResolution() is only valid inside a transaction");
@@ -177,7 +194,7 @@ public abstract class Layer {
* superclass implementation. Returns false if there is still work to be done after this
* update is complete.
*/
- protected boolean performUpdates(GL10 gl, RenderContext context) {
+ protected boolean performUpdates(RenderContext context) {
if (mNewOrigin != null) {
mOrigin = mNewOrigin;
mNewOrigin = null;
@@ -190,15 +207,26 @@ public abstract class Layer {
return true;
}
+ protected boolean dimensionChangesPending() {
+ return (mNewOrigin != null) || (mNewResolution != 0.0f);
+ }
+
public static class RenderContext {
public final RectF viewport;
public final FloatSize pageSize;
public final float zoomFactor;
+ public final int positionHandle;
+ public final int textureHandle;
+ public final FloatBuffer coordBuffer;
- public RenderContext(RectF aViewport, FloatSize aPageSize, float aZoomFactor) {
+ public RenderContext(RectF aViewport, FloatSize aPageSize, float aZoomFactor,
+ int aPositionHandle, int aTextureHandle, FloatBuffer aCoordBuffer) {
viewport = aViewport;
pageSize = aPageSize;
zoomFactor = aZoomFactor;
+ positionHandle = aPositionHandle;
+ textureHandle = aTextureHandle;
+ coordBuffer = aCoordBuffer;
}
public boolean fuzzyEquals(RenderContext other) {
@@ -211,3 +239,4 @@ public abstract class Layer {
}
}
}
+
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
index fb0823823877..250dc84c69fe 100644
--- 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
@@ -49,7 +49,6 @@ import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View.OnTouchListener;
-import android.view.ViewConfiguration;
import org.mozilla.gecko.ui.PanZoomController;
import org.mozilla.gecko.ui.SimpleScaleGestureDetector;
@@ -57,11 +56,6 @@ import org.mozilla.gecko.ui.SimpleScaleGestureDetector;
import java.util.Timer;
import java.util.TimerTask;
-//import org.mozilla.gecko.GeckoApp;
-//import org.mozilla.gecko.GeckoEvent;
-//import org.mozilla.gecko.Tabs;
-//import org.mozilla.gecko.Tab;
-
/**
* The layer controller manages a tile that represents the visible page. It does panning and
* zooming natively by delegating to a panning/zooming controller. Touch events can be dispatched
@@ -69,7 +63,7 @@ import java.util.TimerTask;
* <p/>
* Many methods require that the monitor be held, with a synchronized (controller) { ... } block.
*/
-public class LayerController /*implements Tabs.OnTabsChangedListener*/ {
+public class LayerController {
/* The extra area on the sides of the page that we want to buffer to help with
* smooth, asynchronous scrolling. Depending on a device's support for NPOT
* textures, this may be rounded up to the nearest power of two.
@@ -80,13 +74,16 @@ public class LayerController /*implements Tabs.OnTabsChangedListener*/ {
* we start aggressively redrawing to minimize checkerboarding. */
private static final int DANGER_ZONE_X = 75;
private static final int DANGER_ZONE_Y = 150;
+ /* The time limit for pages to respond with preventDefault on touchevents
+ * before we begin panning the page */
+ private static final int PREVENT_DEFAULT_TIMEOUT = 200;
private Layer mRootLayer; /* The root layer. */
private LayerView mView; /* The main rendering view. */
- private Context mContext; /* The current context. */
/*
* The panning and zooming controller, which interprets pan and zoom gestures for us and
* updates our visible rect appropriately.
*/
+ private Context mContext; /* The current context. */
private ViewportMetrics mViewportMetrics; /* The current viewport metrics. */
private boolean mWaitForTouchListeners;
private PanZoomController mPanZoomController;
@@ -96,12 +93,9 @@ public class LayerController /*implements Tabs.OnTabsChangedListener*/ {
private int mCheckerboardColor;
private boolean mCheckerboardShouldShowChecks;
private boolean mForceRedraw;
- /* The time limit for pages to respond with preventDefault on touchevents
- * before we begin panning the page */
- private int mTimeout = 200;
-
private boolean allowDefaultActions = true;
private Timer allowDefaultTimer = null;
+ private boolean inTouchSession = false;
private PointF initialTouchLocation = null;
public LayerController(Context context) {
@@ -111,15 +105,6 @@ public class LayerController /*implements Tabs.OnTabsChangedListener*/ {
mViewportMetrics = new ViewportMetrics();
mPanZoomController = new PanZoomController(this);
mView = new LayerView(context, this);
-
- //Tabs.getInstance().registerOnTabsChangedListener(this);
-
- ViewConfiguration vc = ViewConfiguration.get(mContext);
- mTimeout = vc.getLongPressTimeout();
- }
-
- public void onDestroy() {
- //Tabs.getInstance().unregisterOnTabsChangedListener(this);
}
public void setForceRedraw() {
@@ -364,12 +349,15 @@ public class LayerController /*implements Tabs.OnTabsChangedListener*/ {
* would prefer that the action didn't take place.
*/
public boolean getRedrawHint() {
+ // FIXME: Allow redraw while a finger is down, but only if we're about to checkerboard.
+ // This requires fixing aboutToCheckerboard() to know about the new buffer size.
+
if (mForceRedraw) {
mForceRedraw = false;
return true;
}
- return aboutToCheckerboard() && mPanZoomController.getRedrawHint();
+ return mPanZoomController.getRedrawHint();
}
private RectF getTileRect() {
@@ -426,29 +414,15 @@ public class LayerController /*implements Tabs.OnTabsChangedListener*/ {
int action = event.getAction();
PointF point = new PointF(event.getX(), event.getY());
- // this will only match the first touchstart in a series
if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
+ mView.clearEventQueue();
initialTouchLocation = point;
allowDefaultActions = !mWaitForTouchListeners;
-
- // if we have a timer, this may be a double tap,
- // cancel the current timer but don't clear the event queue
- if (allowDefaultTimer != null) {
- allowDefaultTimer.cancel();
- } else {
- // if we don't have a timer, make sure we remove any old events
- mView.clearEventQueue();
- }
- allowDefaultTimer = new Timer();
- allowDefaultTimer.schedule(new TimerTask() {
+ post(new Runnable() {
public void run() {
- post(new Runnable() {
- public void run() {
- preventPanning(false);
- }
- });
+ preventPanning(mWaitForTouchListeners);
}
- }, mTimeout);
+ });
}
// After the initial touch, ignore touch moves until they exceed a minimum distance.
@@ -460,16 +434,55 @@ public class LayerController /*implements Tabs.OnTabsChangedListener*/ {
}
}
- // send the event to content
if (mOnTouchListener != null)
mOnTouchListener.onTouch(mView, event);
+ if (!mWaitForTouchListeners)
+ return !allowDefaultActions;
+
+ boolean createTimer = false;
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_MOVE: {
+ if (!inTouchSession && allowDefaultTimer == null) {
+ inTouchSession = true;
+ createTimer = true;
+ }
+ break;
+ }
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP: {
+ // if we still have initialTouchLocation, we haven't fired any
+ // touchmove events. We should start the timer to wait for preventDefault
+ // from touchstart. If we don't hear from it we fire mouse events
+ if (initialTouchLocation != null)
+ createTimer = true;
+ inTouchSession = false;
+ }
+ }
+
+ if (createTimer) {
+ if (allowDefaultTimer != null) {
+ allowDefaultTimer.cancel();
+ }
+ allowDefaultTimer = new Timer();
+ allowDefaultTimer.schedule(new TimerTask() {
+ public void run() {
+ post(new Runnable() {
+ public void run() {
+ preventPanning(false);
+ }
+ });
+ }
+ }, PREVENT_DEFAULT_TIMEOUT);
+ }
+
return !allowDefaultActions;
}
public void preventPanning(boolean aValue) {
if (allowDefaultTimer != null) {
allowDefaultTimer.cancel();
+ allowDefaultTimer.purge();
allowDefaultTimer = null;
}
if (aValue == allowDefaultActions) {
@@ -484,11 +497,6 @@ public class LayerController /*implements Tabs.OnTabsChangedListener*/ {
}
}
- /*public void onTabChanged(Tab tab, Tabs.TabEvents msg) {
- if ((Tabs.getInstance().isSelectedTab(tab) && msg == Tabs.TabEvents.STOP) || msg == Tabs.TabEvents.SELECTED) {
- mWaitForTouchListeners = tab.getHasTouchListeners();
- }
- }*/
public void setWaitForTouchListeners(boolean aValue) {
mWaitForTouchListeners = aValue;
}
@@ -523,3 +531,4 @@ public class LayerController /*implements Tabs.OnTabsChangedListener*/ {
mView.requestRender();
}
}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerRenderer.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerRenderer.java
index 9081a19e4ecb..6690aad8ec16 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerRenderer.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerRenderer.java
@@ -21,6 +21,7 @@
* Contributor(s):
* Patrick Walton <pcwalton@mozilla.com>
* Chris Lord <chrislord.net@gmail.com>
+ * Arkady Blyakher <rkadyb@mit.edu>
*
* 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
@@ -38,17 +39,18 @@
package org.mozilla.gecko.gfx;
+import org.libreoffice.LOKitShell;
import org.mozilla.gecko.gfx.BufferedCairoImage;
import org.mozilla.gecko.gfx.IntSize;
import org.mozilla.gecko.gfx.Layer.RenderContext;
import org.mozilla.gecko.gfx.LayerController;
-import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.NinePatchTileLayer;
import org.mozilla.gecko.gfx.SingleTileLayer;
import org.mozilla.gecko.gfx.TextureReaper;
import org.mozilla.gecko.gfx.TextureGenerator;
import org.mozilla.gecko.gfx.TextLayer;
import org.mozilla.gecko.gfx.TileLayer;
+//import org.mozilla.gecko.GeckoAppShell;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Point;
@@ -57,6 +59,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RegionIterator;
+import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.SystemClock;
import android.util.DisplayMetrics;
@@ -64,6 +67,9 @@ import android.util.Log;
import android.view.WindowManager;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
@@ -92,6 +98,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
private final ScrollbarLayer mHorizScrollLayer;
private final ScrollbarLayer mVertScrollLayer;
private final FadeRunnable mFadeRunnable;
+ private final FloatBuffer mCoordBuffer;
private RenderContext mLastPageContext;
private int mMaxTextureSize;
@@ -111,6 +118,48 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
/* Used by robocop for testing purposes */
private IntBuffer mPixelBuffer;
+ // Used by GLES 2.0
+ private int mProgram;
+ private int mPositionHandle;
+ private int mTextureHandle;
+ private int mSampleHandle;
+ private int mTMatrixHandle;
+
+ // column-major matrix applied to each vertex to shift the viewport from
+ // one ranging from (-1, -1),(1,1) to (0,0),(1,1) and to scale all sizes by
+ // a factor of 2 to fill up the screen
+ private static final float[] TEXTURE_MATRIX = {
+ 2.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 2.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 2.0f, 0.0f,
+ -1.0f, -1.0f, 0.0f, 1.0f
+ };
+
+ private static final int COORD_BUFFER_SIZE = 20;
+
+ // The shaders run on the GPU directly, the vertex shader is only applying the
+ // matrix transform detailed above
+ private static final String VERTEX_SHADER =
+ "uniform mat4 uTMatrix;\n" +
+ "attribute vec4 vPosition;\n" +
+ "attribute vec2 aTexCoord;\n" +
+ "varying vec2 vTexCoord;\n" +
+ "void main() {\n" +
+ " gl_Position = uTMatrix * vPosition;\n" +
+ " vTexCoord = aTexCoord;\n" +
+ "}\n";
+
+ // Note we flip the y-coordinate in the fragment shader from a
+ // coordinate system with (0,0) in the top left to one with (0,0) in
+ // the bottom left.
+ private static final String FRAGMENT_SHADER =
+ "precision mediump float;\n" +
+ "varying vec2 vTexCoord;\n" +
+ "uniform sampler2D sTexture;\n" +
+ "void main() {\n" +
+ " gl_FragColor = texture2D(sTexture, vec2(vTexCoord.x, 1.0 - vTexCoord.y));\n" +
+ "}\n";
+
public LayerRenderer(LayerView view) {
mView = view;
@@ -135,20 +184,69 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
mFrameTimings = new int[60];
mCurrentFrame = mFrameTimingsSum = mDroppedFrames = 0;
mShowFrameRate = false;
+
+ // Initialize the FloatBuffer that will be used to store all vertices and texture
+ // coordinates in draw() commands.
+ ByteBuffer byteBuffer = LOKitShell.allocateDirectBuffer(COORD_BUFFER_SIZE * 4);
+ byteBuffer.order(ByteOrder.nativeOrder());
+ mCoordBuffer = byteBuffer.asFloatBuffer();
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
checkMonitoringEnabled();
+ createProgram();
+ activateProgram();
+ }
+
+ public void createProgram() {
+ int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER);
+ int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER);
- gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
- gl.glDisable(GL10.GL_DITHER);
- gl.glEnable(GL10.GL_TEXTURE_2D);
+ mProgram = GLES20.glCreateProgram();
+ GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
+ GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
+ GLES20.glLinkProgram(mProgram); // creates OpenGL program executables
+
+ // Get handles to the vertex shader's vPosition, aTexCoord, sTexture, and uTMatrix members.
+ mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
+ mTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoord");
+ mSampleHandle = GLES20.glGetUniformLocation(mProgram, "sTexture");
+ mTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uTMatrix");
int maxTextureSizeResult[] = new int[1];
- gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSizeResult, 0);
+ GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSizeResult, 0);
mMaxTextureSize = maxTextureSizeResult[0];
+ }
+
+ // Activates the shader program.
+ public void activateProgram() {
+ // Add the program to the OpenGL environment
+ GLES20.glUseProgram(mProgram);
+
+ // Set the transformation matrix
+ GLES20.glUniformMatrix4fv(mTMatrixHandle, 1, false, TEXTURE_MATRIX, 0);
+
+ Log.e(LOGTAG, "### Position handle is " + mPositionHandle + ", texture handle is " +
+ mTextureHandle + ", last error is " + GLES20.glGetError());
+
+ // Enable the arrays from which we get the vertex and texture coordinates
+ GLES20.glEnableVertexAttribArray(mPositionHandle);
+ GLES20.glEnableVertexAttribArray(mTextureHandle);
+
+ GLES20.glUniform1i(mSampleHandle, 0);
TextureGenerator.get().fill();
+
+ // TODO: Move these calls into a separate deactivate() call that is called after the
+ // underlay and overlay are rendered.
+ }
+
+ // Deactivates the shader program. This must be done to avoid crashes after returning to the
+ // Gecko C++ compositor from Java.
+ public void deactivateProgram() {
+ GLES20.glDisableVertexAttribArray(mTextureHandle);
+ GLES20.glDisableVertexAttribArray(mPositionHandle);
+ GLES20.glUseProgram(0);
}
public int getMaxTextureSize() {
@@ -179,149 +277,14 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
* Called whenever a new frame is about to be drawn.
*/
public void onDrawFrame(GL10 gl) {
- long frameStartTime = SystemClock.uptimeMillis();
-
- TextureReaper.get().reap(gl);
- TextureGenerator.get().fill();
-
- LayerController controller = mView.getController();
- RenderContext screenContext = createScreenContext();
-
- boolean updated = true;
-
- synchronized (controller) {
- Layer rootLayer = controller.getRoot();
- RenderContext pageContext = createPageContext();
-
- if (!pageContext.fuzzyEquals(mLastPageContext)) {
- // the viewport or page changed, so show the scrollbars again
- // as per UX decision
- mVertScrollLayer.unfade();
- mHorizScrollLayer.unfade();
- mFadeRunnable.scheduleStartFade(ScrollbarLayer.FADE_DELAY);
- } else if (mFadeRunnable.timeToFade()) {
- boolean stillFading = mVertScrollLayer.fade() | mHorizScrollLayer.fade();
- if (stillFading) {
- mFadeRunnable.scheduleNextFadeFrame();
- }
- }
- mLastPageContext = pageContext;
-
- /* Update layers. */
- if (rootLayer != null) updated &= rootLayer.update(gl, pageContext);
- updated &= mBackgroundLayer.update(gl, screenContext);
- updated &= mShadowLayer.update(gl, pageContext);
- updateCheckerboardLayer(gl, screenContext);
- updated &= mFrameRateLayer.update(gl, screenContext);
- updated &= mVertScrollLayer.update(gl, pageContext);
- updated &= mHorizScrollLayer.update(gl, pageContext);
-
- for (Layer layer : mExtraLayers)
- updated &= layer.update(gl, pageContext);
-
- /* Draw the background. */
- mBackgroundLayer.draw(screenContext);
-
- /* Draw the drop shadow, if we need to. */
- Rect pageRect = getPageRect();
- RectF untransformedPageRect = new RectF(0.0f, 0.0f, pageRect.width(),
- pageRect.height());
- if (!untransformedPageRect.contains(controller.getViewport()))
- mShadowLayer.draw(pageContext);
-
- /* Draw the checkerboard. */
- Rect scissorRect = transformToScissorRect(pageRect);
- gl.glEnable(GL10.GL_SCISSOR_TEST);
- gl.glScissor(scissorRect.left, scissorRect.top,
- scissorRect.width(), scissorRect.height());
-
- mCheckerboardLayer.draw(screenContext);
-
- /* Draw the layer the client added to us. */
- if (rootLayer != null)
- rootLayer.draw(pageContext);
-
- gl.glDisable(GL10.GL_SCISSOR_TEST);
-
- /* Draw any extra layers that were added (likely plugins) */
- for (Layer layer : mExtraLayers)
- layer.draw(pageContext);
-
- /* Draw the vertical scrollbar. */
- IntSize screenSize = new IntSize(controller.getViewportSize());
- if (pageRect.height() > screenSize.height)
- mVertScrollLayer.draw(pageContext);
-
- /* Draw the horizontal scrollbar. */
- if (pageRect.width() > screenSize.width)
- mHorizScrollLayer.draw(pageContext);
-
- /* Measure how much of the screen is checkerboarding */
- if ((rootLayer != null) &&
- (mProfileRender || PanningPerfAPI.isRecordingCheckerboard())) {
- // Find out how much of the viewport area is valid
- Rect viewport = RectUtils.round(pageContext.viewport);
- Region validRegion = rootLayer.getValidRegion(pageContext);
- validRegion.op(viewport, Region.Op.INTERSECT);
-
- float checkerboard = 0.0f;
- if (!(validRegion.isRect() && validRegion.getBounds().equals(viewport))) {
- int screenArea = viewport.width() * viewport.height();
- validRegion.op(viewport, Region.Op.REVERSE_DIFFERENCE);
-
- // XXX The assumption here is that a Region never has overlapping
- // rects. This is true, as evidenced by reading the SkRegion
- // source, but is not mentioned in the Android documentation,
- // and so is liable to change.
- // If it does change, this code will need to be reevaluated.
- Rect r = new Rect();
- int checkerboardArea = 0;
- for (RegionIterator i = new RegionIterator(validRegion); i.next(r);) {
- checkerboardArea += r.width() * r.height();
- }
-
- checkerboard = checkerboardArea / (float)screenArea;
- }
-
- PanningPerfAPI.recordCheckerboard(checkerboard);
-
- mCompleteFramesRendered += 1.0f - checkerboard;
- mFramesRendered ++;
-
- if (frameStartTime - mProfileOutputTime > 1000) {
- mProfileOutputTime = frameStartTime;
- printCheckerboardStats();
- }
- }
- }
-
- /* Draw the FPS. */
- if (mShowFrameRate) {
- updateDroppedFrames(frameStartTime);
-
- try {
- gl.glEnable(GL10.GL_BLEND);
- gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
- mFrameRateLayer.draw(screenContext);
- } finally {
- gl.glDisable(GL10.GL_BLEND);
- }
- }
-
- // If a layer update requires further work, schedule another redraw
- if (!updated)
- mView.requestRender();
-
- PanningPerfAPI.recordFrameTime();
-
- /* Used by robocop for testing purposes */
- IntBuffer pixelBuffer = mPixelBuffer;
- if (updated && pixelBuffer != null) {
- synchronized (pixelBuffer) {
- pixelBuffer.position(0);
- gl.glReadPixels(0, 0, (int)screenContext.viewport.width(), (int)screenContext.viewport.height(), GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixelBuffer);
- pixelBuffer.notify();
- }
+ RenderContext pageContext = createPageContext(), screenContext = createScreenContext();
+ Frame frame = createFrame(pageContext, screenContext);
+ synchronized (mView.getController()) {
+ frame.beginDrawing();
+ frame.drawBackground();
+ frame.drawRootLayer();
+ frame.drawForeground();
+ frame.endDrawing();
}
}
@@ -346,15 +309,15 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
return pixelBuffer;
}
- private RenderContext createScreenContext() {
+ public RenderContext createScreenContext() {
LayerController layerController = mView.getController();
IntSize viewportSize = new IntSize(layerController.getViewportSize());
RectF viewport = new RectF(0.0f, 0.0f, viewportSize.width, viewportSize.height);
FloatSize pageSize = new FloatSize(layerController.getPageSize());
- return new RenderContext(viewport, pageSize, 1.0f);
+ return createContext(viewport, pageSize, 1.0f);
}
- private RenderContext createPageContext() {
+ public RenderContext createPageContext() {
LayerController layerController = mView.getController();
Rect viewport = new Rect();
@@ -362,7 +325,12 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
FloatSize pageSize = new FloatSize(layerController.getPageSize());
float zoomFactor = layerController.getZoomFactor();
- return new RenderContext(new RectF(viewport), pageSize, zoomFactor);
+ return createContext(new RectF(viewport), pageSize, zoomFactor);
+ }
+
+ private RenderContext createContext(RectF viewport, FloatSize pageSize, float zoomFactor) {
+ return new RenderContext(viewport, pageSize, zoomFactor, mPositionHandle, mTextureHandle,
+ mCoordBuffer);
}
private Rect getPageRect() {
@@ -374,7 +342,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
origin.negate();
return new Rect(origin.x, origin.y,
- origin.x + pageSize.width, origin.y + pageSize.height);
+ origin.x + pageSize.width, origin.y + pageSize.height);
}
private Rect transformToScissorRect(Rect rect) {
@@ -387,11 +355,11 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
int bottom = Math.min(screenSize.height, rect.bottom);
return new Rect(left, screenSize.height - bottom, right,
- (screenSize.height - bottom) + (bottom - top));
+ (screenSize.height - bottom) + (bottom - top));
}
public void onSurfaceChanged(GL10 gl, final int width, final int height) {
- gl.glViewport(0, 0, width, height);
+ GLES20.glViewport(0, 0, width, height);
// updating the state in the view/controller/client should be
// done on the main UI thread, not the GL renderer thread
@@ -431,7 +399,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
mFrameRateLayer.beginTransaction();
try {
Point origin = new Point(width - FRAME_RATE_METER_WIDTH - 8,
- height - FRAME_RATE_METER_HEIGHT + 8);
+ height - FRAME_RATE_METER_HEIGHT + 8);
mFrameRateLayer.setOrigin(origin);
} finally {
mFrameRateLayer.endTransaction();
@@ -451,11 +419,11 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
}).start();
}
- private void updateCheckerboardLayer(GL10 gl, RenderContext renderContext) {
+ private void updateCheckerboardLayer(RenderContext renderContext) {
int checkerboardColor = mView.getController().getCheckerboardColor();
boolean showChecks = mView.getController().checkerboardShouldShowChecks();
if (checkerboardColor == mCheckerboardImage.getColor() &&
- showChecks == mCheckerboardImage.getShowChecks()) {
+ showChecks == mCheckerboardImage.getShowChecks()) {
return;
}
@@ -467,7 +435,22 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
mCheckerboardLayer.endTransaction();
}
- mCheckerboardLayer.update(gl, renderContext);
+ mCheckerboardLayer.update(renderContext);
+ }
+
+ /*
+ * create a vertex shader type (GLES20.GL_VERTEX_SHADER)
+ * or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
+ */
+ private int loadShader(int type, String shaderCode) {
+ int shader = GLES20.glCreateShader(type);
+ GLES20.glShaderSource(shader, shaderCode);
+ GLES20.glCompileShader(shader);
+ return shader;
+ }
+
+ public Frame createFrame(RenderContext pageContext, RenderContext screenContext) {
+ return new Frame(pageContext, screenContext);
}
class FadeRunnable implements Runnable {
@@ -505,4 +488,202 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
}
}
}
+
+ public class Frame {
+ // The timestamp recording the start of this frame.
+ private long mFrameStartTime;
+ // A rendering context for page-positioned layers, and one for screen-positioned layers.
+ private RenderContext mPageContext, mScreenContext;
+ // Whether a layer was updated.
+ private boolean mUpdated;
+
+ public Frame(RenderContext pageContext, RenderContext screenContext) {
+ mPageContext = pageContext;
+ mScreenContext = screenContext;
+ }
+
+ private void setScissorRect() {
+ Rect scissorRect = transformToScissorRect(getPageRect());
+ GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+ GLES20.glScissor(scissorRect.left, scissorRect.top,
+ scissorRect.width(), scissorRect.height());
+ }
+
+ public void beginDrawing() {
+ mFrameStartTime = SystemClock.uptimeMillis();
+
+ TextureReaper.get().reap();
+ TextureGenerator.get().fill();
+
+ mUpdated = true;
+
+ LayerController controller = mView.getController();
+ Layer rootLayer = controller.getRoot();
+
+ if (!mPageContext.fuzzyEquals(mLastPageContext)) {
+ // the viewport or page changed, so show the scrollbars again
+ // as per UX decision
+ mVertScrollLayer.unfade();
+ mHorizScrollLayer.unfade();
+ mFadeRunnable.scheduleStartFade(ScrollbarLayer.FADE_DELAY);
+ } else if (mFadeRunnable.timeToFade()) {
+ boolean stillFading = mVertScrollLayer.fade() | mHorizScrollLayer.fade();
+ if (stillFading) {
+ mFadeRunnable.scheduleNextFadeFrame();
+ }
+ }
+ mLastPageContext = mPageContext;
+
+ /* Update layers. */
+ if (rootLayer != null) mUpdated &= rootLayer.update(mPageContext);
+ mUpdated &= mBackgroundLayer.update(mScreenContext);
+ mUpdated &= mShadowLayer.update(mPageContext);
+ updateCheckerboardLayer(mScreenContext);
+ mUpdated &= mFrameRateLayer.update(mScreenContext);
+ mUpdated &= mVertScrollLayer.update(mPageContext);
+ mUpdated &= mHorizScrollLayer.update(mPageContext);
+
+ for (Layer layer : mExtraLayers)
+ mUpdated &= layer.update(mPageContext);
+
+ GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
+
+ // If a layer update requires further work, schedule another redraw
+ if (!mUpdated)
+ mView.requestRender();
+
+ PanningPerfAPI.recordFrameTime();
+
+ /* Used by robocop for testing purposes */
+ IntBuffer pixelBuffer = mPixelBuffer;
+ if (mUpdated && pixelBuffer != null) {
+ synchronized (pixelBuffer) {
+ pixelBuffer.position(0);
+ GLES20.glReadPixels(0, 0, (int)mScreenContext.viewport.width(),
+ (int)mScreenContext.viewport.height(), GLES20.GL_RGBA,
+ GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
+ pixelBuffer.notify();
+ }
+ }
+ }
+
+ public void drawBackground() {
+ /* Draw the background. */
+ mBackgroundLayer.draw(mScreenContext);
+
+ /* Draw the drop shadow, if we need to. */
+ Rect pageRect = getPageRect();
+ RectF untransformedPageRect = new RectF(0.0f, 0.0f, pageRect.width(),
+ pageRect.height());
+ if (!untransformedPageRect.contains(mView.getController().getViewport()))
+ mShadowLayer.draw(mPageContext);
+
+ /* Draw the checkerboard. */
+ setScissorRect();
+ mCheckerboardLayer.draw(mScreenContext);
+ GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
+ }
+
+ // Draws the layer the client added to us.
+ void drawRootLayer() {
+ Layer rootLayer = mView.getController().getRoot();
+ if (rootLayer == null) {
+ return;
+ }
+
+ setScissorRect();
+ rootLayer.draw(mPageContext);
+ GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
+ }
+
+ public void drawForeground() {
+ Rect pageRect = getPageRect();
+ LayerController controller = mView.getController();
+
+ /* Draw any extra layers that were added (likely plugins) */
+ for (Layer layer : mExtraLayers)
+ layer.draw(mPageContext);
+
+ /* Draw the vertical scrollbar. */
+ IntSize screenSize = new IntSize(controller.getViewportSize());
+ if (pageRect.height() > screenSize.height)
+ mVertScrollLayer.draw(mPageContext);
+
+ /* Draw the horizontal scrollbar. */
+ if (pageRect.width() > screenSize.width)
+ mHorizScrollLayer.draw(mPageContext);
+
+ /* Measure how much of the screen is checkerboarding */
+ Layer rootLayer = controller.getRoot();
+ if ((rootLayer != null) &&
+ (mProfileRender || PanningPerfAPI.isRecordingCheckerboard())) {
+ // Find out how much of the viewport area is valid
+ Rect viewport = RectUtils.round(mPageContext.viewport);
+ Region validRegion = rootLayer.getValidRegion(mPageContext);
+ validRegion.op(viewport, Region.Op.INTERSECT);
+
+ float checkerboard = 0.0f;
+ if (!(validRegion.isRect() && validRegion.getBounds().equals(viewport))) {
+ int screenArea = viewport.width() * viewport.height();
+ validRegion.op(viewport, Region.Op.REVERSE_DIFFERENCE);
+
+ // XXX The assumption here is that a Region never has overlapping
+ // rects. This is true, as evidenced by reading the SkRegion
+ // source, but is not mentioned in the Android documentation,
+ // and so is liable to change.
+ // If it does change, this code will need to be reevaluated.
+ Rect r = new Rect();
+ int checkerboardArea = 0;
+ for (RegionIterator i = new RegionIterator(validRegion); i.next(r);) {
+ checkerboardArea += r.width() * r.height();
+ }
+
+ checkerboard = checkerboardArea / (float)screenArea;
+ }
+
+ PanningPerfAPI.recordCheckerboard(checkerboard);
+
+ mCompleteFramesRendered += 1.0f - checkerboard;
+ mFramesRendered ++;
+
+ if (mFrameStartTime - mProfileOutputTime > 1000) {
+ mProfileOutputTime = mFrameStartTime;
+ printCheckerboardStats();
+ }
+ }
+
+ /* Draw the FPS. */
+ if (mShowFrameRate) {
+ updateDroppedFrames(mFrameStartTime);
+
+ try {
+ GLES20.glEnable(GLES20.GL_BLEND);
+ GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
+ mFrameRateLayer.draw(mScreenContext);
+ } finally {
+ GLES20.glDisable(GLES20.GL_BLEND);
+ }
+ }
+ }
+
+ public void endDrawing() {
+ // If a layer update requires further work, schedule another redraw
+ if (!mUpdated)
+ mView.requestRender();
+
+ PanningPerfAPI.recordFrameTime();
+
+ /* Used by robocop for testing purposes */
+ IntBuffer pixelBuffer = mPixelBuffer;
+ if (mUpdated && pixelBuffer != null) {
+ synchronized (pixelBuffer) {
+ pixelBuffer.position(0);
+ GLES20.glReadPixels(0, 0, (int)mScreenContext.viewport.width(),
+ (int)mScreenContext.viewport.height(), GLES20.GL_RGBA,
+ GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
+ pixelBuffer.notify();
+ }
+ }
+ }
+ }
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerView.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerView.java
index 2b63f1df15ea..a3c04fa600f2 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerView.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/LayerView.java
@@ -20,6 +20,7 @@
*
* Contributor(s):
* Patrick Walton <pcwalton@mozilla.com>
+ * Arkady Blyakher <rkadyb@mit.edu>
*
* 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
@@ -37,18 +38,23 @@
package org.mozilla.gecko.gfx;
+//import org.mozilla.gecko.GeckoInputConnection;
import org.mozilla.gecko.gfx.FloatSize;
import org.mozilla.gecko.gfx.InputConnectionHandler;
import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.ui.SimpleScaleGestureDetector;
import android.content.Context;
import android.opengl.GLSurfaceView;
+import android.view.View;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
+import android.view.ScaleGestureDetector;
+import android.widget.RelativeLayout;
import android.util.Log;
+import java.nio.IntBuffer;
import java.util.LinkedList;
/**
@@ -57,7 +63,7 @@ import java.util.LinkedList;
* This view delegates to LayerRenderer to actually do the drawing. Its role is largely that of a
* mediator between the LayerRenderer and the LayerController.
*/
-public class LayerView extends GLSurfaceView {
+public class LayerView extends FlexibleGLSurfaceView {
private Context mContext;
private LayerController mController;
private InputConnectionHandler mInputConnectionHandler;
@@ -70,6 +76,7 @@ public class LayerView extends GLSurfaceView {
/* List of events to be processed if the page does not prevent them. Should only be touched on the main thread */
private LinkedList<MotionEvent> mEventQueue = new LinkedList<MotionEvent>();
+
public LayerView(Context context, LayerController controller) {
super(context);
@@ -77,15 +84,16 @@ public class LayerView extends GLSurfaceView {
mController = controller;
mRenderer = new LayerRenderer(this);
setRenderer(mRenderer);
- setRenderMode(RENDERMODE_WHEN_DIRTY);
mGestureDetector = new GestureDetector(context, controller.getGestureListener());
mScaleGestureDetector =
- new SimpleScaleGestureDetector(controller.getScaleGestureListener());
+ new SimpleScaleGestureDetector(controller.getScaleGestureListener());
mGestureDetector.setOnDoubleTapListener(controller.getDoubleTapListener());
mInputConnectionHandler = null;
setFocusable(true);
setFocusableInTouchMode(true);
+
+ createGLThread();
}
private void addToEventQueue(MotionEvent event) {
@@ -131,9 +139,11 @@ public class LayerView extends GLSurfaceView {
mController.setViewportSize(new FloatSize(size));
}
- public void setInputConnectionHandler(InputConnectionHandler handler) {
- mInputConnectionHandler = handler;
- }
+ //public GeckoInputConnection setInputConnectionHandler() {
+ // GeckoInputConnection geckoInputConnection = GeckoInputConnection.create(this);
+ // mInputConnectionHandler = geckoInputConnection;
+ // return geckoInputConnection;
+ //}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
@@ -211,5 +221,10 @@ public class LayerView extends GLSurfaceView {
public int getMaxTextureSize() {
return mRenderer.getMaxTextureSize();
}
+
+ /** Used by robocop for testing purposes. Not for production use! This is called via reflection by robocop. */
+ public IntBuffer getPixels() {
+ return mRenderer.getPixels();
+ }
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/MultiTileLayer.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/MultiTileLayer.java
index 94a605f35572..3ade6c14d2d6 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/MultiTileLayer.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/MultiTileLayer.java
@@ -1,39 +1,40 @@
/* -*- 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) 2011-2012
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Chris Lord <chrislord.net@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 ***** */
+* ***** 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) 2011-2012
+* the Initial Developer. All Rights Reserved.
+*
+* Contributor(s):
+* Chris Lord <chrislord.net@gmail.com>
+* Arkady Blyakher <rkadyb@mit.edu>
+*
+* 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;
@@ -43,10 +44,11 @@ import org.mozilla.gecko.gfx.SingleTileLayer;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.Region;
import android.util.Log;
import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
import java.util.ArrayList;
-import javax.microedition.khronos.opengles.GL10;
/**
* Encapsulates the logic needed to draw a layer made of multiple tiles.
@@ -59,7 +61,7 @@ public class MultiTileLayer extends Layer {
private final CairoImage mImage;
private IntSize mTileSize;
private IntSize mBufferSize;
- private final ArrayList<SingleTileLayer> mTiles;
+ private final ArrayList<SubTile> mTiles;
public MultiTileLayer(CairoImage image, IntSize tileSize) {
super();
@@ -67,34 +69,29 @@ public class MultiTileLayer extends Layer {
mImage = image;
mTileSize = tileSize;
mBufferSize = new IntSize(0, 0);
- mTiles = new ArrayList<SingleTileLayer>();
+ mTiles = new ArrayList<SubTile>();
}
public void invalidate(Rect dirtyRect) {
- if (!inTransaction())
+ if (!inTransaction()) {
throw new RuntimeException("invalidate() is only valid inside a transaction");
+ }
- int x = 0, y = 0;
- IntSize size = getSize();
- for (SingleTileLayer layer : mTiles) {
- Rect tileRect = new Rect(x, y, x + mTileSize.width, y + mTileSize.height);
+ for (SubTile layer : mTiles) {
+ IntSize tileSize = layer.getSize();
+ Rect tileRect = new Rect(layer.x, layer.y, layer.x + tileSize.width, layer.y + tileSize.height);
if (tileRect.intersect(dirtyRect)) {
- tileRect.offset(-x, -y);
+ tileRect.offset(-layer.x, -layer.y);
layer.invalidate(tileRect);
}
-
- x += mTileSize.width;
- if (x >= size.width) {
- x = 0;
- y += mTileSize.height;
- }
}
}
public void invalidate() {
- for (SingleTileLayer layer : mTiles)
+ for (SubTile layer : mTiles) {
layer.invalidate();
+ }
}
@Override
@@ -105,8 +102,9 @@ public class MultiTileLayer extends Layer {
private void validateTiles() {
IntSize size = getSize();
- if (size.equals(mBufferSize))
+ if (size.equals(mBufferSize)) {
return;
+ }
// Regenerate tiles
mTiles.clear();
@@ -120,7 +118,7 @@ public class MultiTileLayer extends Layer {
// tile from the parent CairoImage. It's assumed that
// the tiles are stored in series.
final IntSize layerSize =
- new IntSize(Math.min(mTileSize.width, size.width - x),
+ new IntSize(Math.min(mTileSize.width, size.width - x),
Math.min(mTileSize.height, size.height - y));
final int tileOffset = offset;
@@ -148,7 +146,7 @@ public class MultiTileLayer extends Layer {
}
};
- mTiles.add(new SingleTileLayer(subImage));
+ mTiles.add(new SubTile(subImage, x, y));
offset += layerSize.getArea() * bpp;
}
}
@@ -160,21 +158,21 @@ public class MultiTileLayer extends Layer {
}
@Override
- protected boolean performUpdates(GL10 gl, RenderContext context) {
- super.performUpdates(gl, context);
+ protected boolean performUpdates(RenderContext context) {
+ super.performUpdates(context);
validateTiles();
// Iterate over the tiles and decide which ones we'll be drawing
int dirtyTiles = 0;
boolean screenUpdateDone = false;
- SingleTileLayer firstDirtyTile = null;
- for (SingleTileLayer layer : mTiles) {
+ SubTile firstDirtyTile = null;
+ for (SubTile layer : mTiles) {
// First do a non-texture update to make sure coordinates are
// up-to-date.
boolean invalid = layer.getSkipTextureUpdate();
layer.setSkipTextureUpdate(true);
- layer.performUpdates(gl, context);
+ layer.performUpdates(context);
RectF layerBounds = layer.getBounds(context, new FloatSize(layer.getSize()));
boolean isDirty = layer.isDirty();
@@ -190,7 +188,7 @@ public class MultiTileLayer extends Layer {
// update it immediately.
layer.setSkipTextureUpdate(false);
screenUpdateDone = true;
- layer.performUpdates(gl, context);
+ layer.performUpdates(context);
invalid = false;
}
}
@@ -208,7 +206,7 @@ public class MultiTileLayer extends Layer {
// upload-related hitches.
if (!screenUpdateDone && firstDirtyTile != null) {
firstDirtyTile.setSkipTextureUpdate(false);
- firstDirtyTile.performUpdates(gl, context);
+ firstDirtyTile.performUpdates(context);
dirtyTiles --;
}
@@ -216,24 +214,21 @@ public class MultiTileLayer extends Layer {
}
private void refreshTileMetrics(Point origin, float resolution, boolean inTransaction) {
- int x = 0, y = 0;
IntSize size = getSize();
- for (SingleTileLayer layer : mTiles) {
- if (!inTransaction)
+ for (SubTile layer : mTiles) {
+ if (!inTransaction) {
layer.beginTransaction(null);
+ }
- if (origin != null)
- layer.setOrigin(new Point(origin.x + x, origin.y + y));
- if (resolution >= 0.0f)
+ if (origin != null) {
+ layer.setOrigin(new Point(origin.x + layer.x, origin.y + layer.y));
+ }
+ if (resolution >= 0.0f) {
layer.setResolution(resolution);
+ }
- if (!inTransaction)
+ if (!inTransaction) {
layer.endTransaction();
-
- x += mTileSize.width;
- if (x >= size.width) {
- x = 0;
- y += mTileSize.height;
}
}
}
@@ -254,21 +249,23 @@ public class MultiTileLayer extends Layer {
public void beginTransaction(LayerView aView) {
super.beginTransaction(aView);
- for (SingleTileLayer layer : mTiles)
+ for (SubTile layer : mTiles) {
layer.beginTransaction(aView);
+ }
}
@Override
public void endTransaction() {
- for (SingleTileLayer layer : mTiles)
+ for (SubTile layer : mTiles) {
layer.endTransaction();
+ }
super.endTransaction();
}
@Override
public void draw(RenderContext context) {
- for (SingleTileLayer layer : mTiles) {
+ for (SubTile layer : mTiles) {
// We use the SkipTextureUpdate flag as a validity flag. If it's false,
// the contents of this tile are invalid and we shouldn't draw it.
if (layer.getSkipTextureUpdate())
@@ -280,5 +277,28 @@ public class MultiTileLayer extends Layer {
layer.draw(context);
}
}
+
+ @Override
+ public Region getValidRegion(RenderContext context) {
+ Region validRegion = new Region();
+ for (SubTile tile : mTiles) {
+ if (tile.getSkipTextureUpdate())
+ continue;
+ validRegion.op(tile.getValidRegion(context), Region.Op.UNION);
+ }
+
+ return validRegion;
+ }
+
+ class SubTile extends SingleTileLayer {
+ public int x;
+ public int y;
+
+ public SubTile(CairoImage mImage, int mX, int mY) {
+ super(mImage);
+ x = mX;
+ y = mY;
+ }
+ }
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/RectUtils.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/RectUtils.java
index ffc87b3dcc2a..9a5049781c45 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/RectUtils.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/RectUtils.java
@@ -38,6 +38,8 @@
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.util.FloatUtils;
+import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import org.json.JSONException;
@@ -60,27 +62,27 @@ public final class RectUtils {
float halfLessWidth = lessWidth / 2.0f;
float halfLessHeight = lessHeight / 2.0f;
return new Rect(Math.round(rect.left + halfLessWidth),
- Math.round(rect.top + halfLessHeight),
- Math.round(rect.right - halfLessWidth),
- Math.round(rect.bottom - halfLessHeight));
+ Math.round(rect.top + halfLessHeight),
+ Math.round(rect.right - halfLessWidth),
+ Math.round(rect.bottom - halfLessHeight));
}
public static RectF contract(RectF rect, float lessWidth, float lessHeight) {
float halfLessWidth = lessWidth / 2;
float halfLessHeight = lessHeight / 2;
return new RectF(rect.left + halfLessWidth,
- rect.top + halfLessHeight,
- rect.right - halfLessWidth,
- rect.bottom - halfLessHeight);
+ rect.top + halfLessHeight,
+ rect.right - halfLessWidth,
+ rect.bottom - halfLessHeight);
}
public static RectF expand(RectF rect, float moreWidth, float moreHeight) {
float halfMoreWidth = moreWidth / 2;
float halfMoreHeight = moreHeight / 2;
return new RectF(rect.left - halfMoreWidth,
- rect.top - halfMoreHeight,
- rect.right + halfMoreWidth,
- rect.bottom + halfMoreHeight);
+ rect.top - halfMoreHeight,
+ rect.right + halfMoreWidth,
+ rect.bottom + halfMoreHeight);
}
public static RectF intersect(RectF one, RectF two) {
@@ -95,34 +97,43 @@ public final class RectUtils {
float x = rect.left * scale;
float y = rect.top * scale;
return new RectF(x, y,
- x + (rect.width() * scale),
- y + (rect.height() * scale));
+ x + (rect.width() * scale),
+ y + (rect.height() * scale));
}
+ /** Returns the nearest integer rect of the given rect. */
public static Rect round(RectF rect) {
return new Rect(Math.round(rect.left), Math.round(rect.top),
- Math.round(rect.right), Math.round(rect.bottom));
+ Math.round(rect.right), Math.round(rect.bottom));
}
public static IntSize getSize(Rect rect) {
return new IntSize(rect.width(), rect.height());
}
+ public static Point getOrigin(Rect rect) {
+ return new Point(rect.left, rect.top);
+ }
+
+ public static PointF getOrigin(RectF rect) {
+ return new PointF(rect.left, rect.top);
+ }
+
/*
* Returns the rect that represents a linear transition between `from` and `to` at time `t`,
* which is on the scale [0, 1).
*/
public static RectF interpolate(RectF from, RectF to, float t) {
return new RectF(FloatUtils.interpolate(from.left, to.left, t),
- FloatUtils.interpolate(from.top, to.top, t),
- FloatUtils.interpolate(from.right, to.right, t),
- FloatUtils.interpolate(from.bottom, to.bottom, t));
+ FloatUtils.interpolate(from.top, to.top, t),
+ FloatUtils.interpolate(from.right, to.right, t),
+ FloatUtils.interpolate(from.bottom, to.bottom, t));
}
public static boolean fuzzyEquals(RectF a, RectF b) {
return FloatUtils.fuzzyEquals(a.top, b.top)
- && FloatUtils.fuzzyEquals(a.left, b.left)
- && FloatUtils.fuzzyEquals(a.right, b.right)
- && FloatUtils.fuzzyEquals(a.bottom, b.bottom);
+ && FloatUtils.fuzzyEquals(a.left, b.left)
+ && FloatUtils.fuzzyEquals(a.right, b.right)
+ && FloatUtils.fuzzyEquals(a.bottom, b.bottom);
}
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ScrollbarLayer.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ScrollbarLayer.java
index e01e1cf369c0..68b7265b368b 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ScrollbarLayer.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ScrollbarLayer.java
@@ -20,6 +20,7 @@
*
* Contributor(s):
* Kartikaya Gupta <kgupta@mozilla.com>
+ * Arkady Blyakher <rkadyb@mit.edu>
*
* 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
@@ -41,19 +42,16 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
-import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.opengl.GLES11;
-import android.opengl.GLES11Ext;
-import android.util.Log;
-import java.nio.ByteBuffer;
-import javax.microedition.khronos.opengles.GL10;
+import android.opengl.GLES20;
import org.libreoffice.LOKitShell;
import org.mozilla.gecko.util.FloatUtils;
-//import org.mozilla.gecko.GeckoAppShell;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
/**
* Draws a small rect. This is scaled to become a scrollbar.
@@ -63,15 +61,52 @@ public class ScrollbarLayer extends TileLayer {
private static final float FADE_AMOUNT = 0.03f; // how much (as a percent) the scrollbar should fade per frame
private static final int PADDING = 1; // gap between scrollbar and edge of viewport
- private static final int BAR_SIZE = 12;
+ private static final int BAR_SIZE = 6;
private static final int CAP_RADIUS = (BAR_SIZE / 2);
-
- private static final int[] CROPRECT_MIDPIXEL = new int[] { CAP_RADIUS, CAP_RADIUS, 1, 1 };
- private static final int[] CROPRECT_TOPCAP = new int[] { 0, CAP_RADIUS, BAR_SIZE, -CAP_RADIUS };
- private static final int[] CROPRECT_BOTTOMCAP = new int[] { 0, BAR_SIZE, BAR_SIZE, -CAP_RADIUS };
- private static final int[] CROPRECT_LEFTCAP = new int[] { 0, BAR_SIZE, CAP_RADIUS, -BAR_SIZE };
- private static final int[] CROPRECT_RIGHTCAP = new int[] { CAP_RADIUS, BAR_SIZE, CAP_RADIUS, -BAR_SIZE };
-
+ // Dimensions of the texture image
+ private static final float TEX_HEIGHT = 8.0f;
+ private static final float TEX_WIDTH = 8.0f;
+ // Texture coordinates for the scrollbar's body
+ // We take a 1x1 pixel from the center of the image and scale it to become the bar
+ private static final float[] BODY_TEX_COORDS = {
+ // x, y
+ CAP_RADIUS / TEX_WIDTH, CAP_RADIUS / TEX_HEIGHT,
+ CAP_RADIUS / TEX_WIDTH, (CAP_RADIUS + 1) / TEX_HEIGHT,
+ (CAP_RADIUS + 1) / TEX_WIDTH, CAP_RADIUS / TEX_HEIGHT,
+ (CAP_RADIUS + 1) / TEX_WIDTH, (CAP_RADIUS + 1) / TEX_HEIGHT
+ };
+ // Texture coordinates for the top cap of the scrollbar
+ private static final float[] TOP_CAP_TEX_COORDS = {
+ // x, y
+ 0, 1.0f - CAP_RADIUS / TEX_HEIGHT,
+ 0, 1.0f,
+ BAR_SIZE / TEX_WIDTH, 1.0f - CAP_RADIUS / TEX_HEIGHT,
+ BAR_SIZE / TEX_WIDTH, 1.0f
+ };
+ // Texture coordinates for the bottom cap of the scrollbar
+ private static final float[] BOT_CAP_TEX_COORDS = {
+ // x, y
+ 0, 1.0f - BAR_SIZE / TEX_HEIGHT,
+ 0, 1.0f - CAP_RADIUS / TEX_HEIGHT,
+ BAR_SIZE / TEX_WIDTH, 1.0f - BAR_SIZE / TEX_HEIGHT,
+ BAR_SIZE / TEX_WIDTH, 1.0f - CAP_RADIUS / TEX_HEIGHT
+ };
+ // Texture coordinates for the left cap of the scrollbar
+ private static final float[] LEFT_CAP_TEX_COORDS = {
+ // x, y
+ 0, 1.0f - BAR_SIZE / TEX_HEIGHT,
+ 0, 1.0f,
+ CAP_RADIUS / TEX_WIDTH, 1.0f - BAR_SIZE / TEX_HEIGHT,
+ CAP_RADIUS / TEX_WIDTH, 1.0f
+ };
+ // Texture coordinates for the right cap of the scrollbar
+ private static final float[] RIGHT_CAP_TEX_COORDS = {
+ // x, y
+ CAP_RADIUS / TEX_WIDTH, 1.0f - BAR_SIZE / TEX_HEIGHT,
+ CAP_RADIUS / TEX_WIDTH, 1.0f,
+ BAR_SIZE / TEX_WIDTH, 1.0f - BAR_SIZE / TEX_HEIGHT,
+ BAR_SIZE / TEX_WIDTH, 1.0f
+ };
private final boolean mVertical;
private final ByteBuffer mBuffer;
private final Bitmap mBitmap;
@@ -89,26 +124,26 @@ public class ScrollbarLayer extends TileLayer {
mCanvas = new Canvas(mBitmap);
}
+ public static ScrollbarLayer create(boolean vertical) {
+ // just create an empty image for now, it will get drawn
+ // on demand anyway
+ int imageSize = IntSize.nextPowerOfTwo(BAR_SIZE);
+ ByteBuffer buffer = LOKitShell.allocateDirectBuffer(imageSize * imageSize * 4);
+ CairoImage image = new BufferedCairoImage(buffer, imageSize, imageSize,
+ CairoImage.FORMAT_ARGB32);
+ return new ScrollbarLayer(image, vertical, buffer);
+ }
+
protected void finalize() throws Throwable {
try {
if (!mFinalized && mBuffer != null)
- /*GeckoAppShell*/ LOKitShell.freeDirectBuffer(mBuffer);
+ LOKitShell.freeDirectBuffer(mBuffer);
mFinalized = true;
} finally {
super.finalize();
}
}
-
- public static ScrollbarLayer create(boolean vertical) {
- // just create an empty image for now, it will get drawn
- // on demand anyway
- int imageSize = IntSize.nextPowerOfTwo(BAR_SIZE);
- ByteBuffer buffer = /*GeckoAppShell*/LOKitShell.allocateDirectBuffer(imageSize * imageSize * 4);
- CairoImage image = new BufferedCairoImage(buffer, imageSize, imageSize, CairoImage.FORMAT_ARGB32);
- return new ScrollbarLayer(image, vertical, buffer);
- }
-
/**
* Decrease the opacity of the scrollbar by one frame's worth.
* Return true if the opacity was decreased, or false if the scrollbars
@@ -168,36 +203,197 @@ public class ScrollbarLayer extends TileLayer {
return;
try {
- GLES11.glEnable(GL10.GL_BLEND);
- GLES11.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
+ GLES20.glEnable(GLES20.GL_BLEND);
+ GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
- Rect rect = RectUtils.round(mVertical ? getVerticalRect(context) : getHorizontalRect(context));
- GLES11.glBindTexture(GL10.GL_TEXTURE_2D, getTextureID());
+ Rect rect = RectUtils.round(mVertical
+ ? getVerticalRect(context)
+ : getHorizontalRect(context));
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureID());
+ float viewWidth = context.viewport.width();
float viewHeight = context.viewport.height();
- // for the body of the scrollbar, we take a 1x1 pixel from the center of the image
- // and scale it to become the bar
- GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_MIDPIXEL, 0);
- GLES11Ext.glDrawTexfOES(rect.left, viewHeight - rect.bottom, 0.0f, rect.width(), rect.height());
+ float top = viewHeight - rect.top;
+ float bot = viewHeight - rect.bottom;
+
+ // Coordinates for the scrollbar's body combined with the texture coordinates
+ float[] bodyCoords = {
+ // x, y, z, texture_x, texture_y
+ rect.left / viewWidth, bot / viewHeight, 0,
+ BODY_TEX_COORDS[0], BODY_TEX_COORDS[1],
+
+ rect.left / viewWidth, (bot + rect.height()) / viewHeight, 0,
+ BODY_TEX_COORDS[2], BODY_TEX_COORDS[3],
+
+ (rect.left + rect.width()) / viewWidth, bot / viewHeight, 0,
+ BODY_TEX_COORDS[4], BODY_TEX_COORDS[5],
+
+ (rect.left + rect.width()) / viewWidth, (bot + rect.height()) / viewHeight, 0,
+ BODY_TEX_COORDS[6], BODY_TEX_COORDS[7]
+ };
+
+ // Get the buffer and handles from the context
+ FloatBuffer coordBuffer = context.coordBuffer;
+ int positionHandle = context.positionHandle;
+ int textureHandle = context.textureHandle;
+
+ // Make sure we are at position zero in the buffer in case other draw methods did not
+ // clean up after themselves
+ coordBuffer.position(0);
+ coordBuffer.put(bodyCoords);
+
+ // Vertex coordinates are x,y,z starting at position 0 into the buffer.
+ coordBuffer.position(0);
+ GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
+ coordBuffer.position(3);
+ GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+
+ // Reset the position in the buffer for the next set of vertex and texture coordinates.
+ coordBuffer.position(0);
if (mVertical) {
// top endcap
- GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_TOPCAP, 0);
- GLES11Ext.glDrawTexfOES(rect.left, viewHeight - rect.top, 0.0f, BAR_SIZE, CAP_RADIUS);
+ float[] topCap = {
+ // x, y, z, texture_x, texture_y
+ rect.left / viewWidth, top / viewHeight, 0,
+ TOP_CAP_TEX_COORDS[0], TOP_CAP_TEX_COORDS[1],
+
+ rect.left / viewWidth, (top + CAP_RADIUS) / viewHeight, 0,
+ TOP_CAP_TEX_COORDS[2], TOP_CAP_TEX_COORDS[3],
+
+ (rect.left + BAR_SIZE) / viewWidth, top / viewHeight, 0,
+ TOP_CAP_TEX_COORDS[4], TOP_CAP_TEX_COORDS[5],
+
+ (rect.left + BAR_SIZE) / viewWidth, (top + CAP_RADIUS) / viewHeight, 0,
+ TOP_CAP_TEX_COORDS[6], TOP_CAP_TEX_COORDS[7]
+ };
+
+ coordBuffer.put(topCap);
+
+ // Vertex coordinates are x,y,z starting at position 0 into the buffer.
+ coordBuffer.position(0);
+ GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ // Texture coordinates are texture_x, texture_y starting at position 3 into the
+ // buffer.
+ coordBuffer.position(3);
+ GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+
+ // Reset the position in the buffer for the next set of vertex and texture
+ // coordinates.
+ coordBuffer.position(0);
+
// bottom endcap
- GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_BOTTOMCAP, 0);
- GLES11Ext.glDrawTexfOES(rect.left, viewHeight - (rect.bottom + CAP_RADIUS), 0.0f, BAR_SIZE, CAP_RADIUS);
+ float[] botCap = {
+ // x, y, z, texture_x, texture_y
+ rect.left / viewWidth, (bot - CAP_RADIUS) / viewHeight, 0,
+ BOT_CAP_TEX_COORDS[0], BOT_CAP_TEX_COORDS[1],
+
+ rect.left / viewWidth, (bot) / viewHeight, 0,
+ BOT_CAP_TEX_COORDS[2], BOT_CAP_TEX_COORDS[3],
+
+ (rect.left + BAR_SIZE) / viewWidth, (bot - CAP_RADIUS) / viewHeight, 0,
+ BOT_CAP_TEX_COORDS[4], BOT_CAP_TEX_COORDS[5],
+
+ (rect.left + BAR_SIZE) / viewWidth, (bot) / viewHeight, 0,
+ BOT_CAP_TEX_COORDS[6], BOT_CAP_TEX_COORDS[7]
+ };
+
+ coordBuffer.put(botCap);
+
+ // Vertex coordinates are x,y,z starting at position 0 into the buffer.
+ coordBuffer.position(0);
+ GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ // Texture coordinates are texture_x, texture_y starting at position 3 into the
+ // buffer.
+ coordBuffer.position(3);
+ GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+
+ // Reset the position in the buffer for the next set of vertex and texture
+ // coordinates.
+ coordBuffer.position(0);
} else {
// left endcap
- GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_LEFTCAP, 0);
- GLES11Ext.glDrawTexfOES(rect.left - CAP_RADIUS, viewHeight - rect.bottom, 0.0f, CAP_RADIUS, BAR_SIZE);
+ float[] leftCap = {
+ // x, y, z, texture_x, texture_y
+ (rect.left - CAP_RADIUS) / viewWidth, bot / viewHeight, 0,
+ LEFT_CAP_TEX_COORDS[0], LEFT_CAP_TEX_COORDS[1],
+ (rect.left - CAP_RADIUS) / viewWidth, (bot + BAR_SIZE) / viewHeight, 0,
+ LEFT_CAP_TEX_COORDS[2], LEFT_CAP_TEX_COORDS[3],
+ (rect.left) / viewWidth, bot / viewHeight, 0, LEFT_CAP_TEX_COORDS[4],
+ LEFT_CAP_TEX_COORDS[5],
+ (rect.left) / viewWidth, (bot + BAR_SIZE) / viewHeight, 0,
+ LEFT_CAP_TEX_COORDS[6], LEFT_CAP_TEX_COORDS[7]
+ };
+
+ coordBuffer.put(leftCap);
+
+ // Vertex coordinates are x,y,z starting at position 0 into the buffer.
+ coordBuffer.position(0);
+ GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ // Texture coordinates are texture_x, texture_y starting at position 3 into the
+ // buffer.
+ coordBuffer.position(3);
+ GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+
+ // Reset the position in the buffer for the next set of vertex and texture
+ // coordinates.
+ coordBuffer.position(0);
+
// right endcap
- GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_RIGHTCAP, 0);
- GLES11Ext.glDrawTexfOES(rect.right, viewHeight - rect.bottom, 0.0f, CAP_RADIUS, BAR_SIZE);
+ float[] rightCap = {
+ // x, y, z, texture_x, texture_y
+ rect.right / viewWidth, (bot) / viewHeight, 0,
+ RIGHT_CAP_TEX_COORDS[0], RIGHT_CAP_TEX_COORDS[1],
+
+ rect.right / viewWidth, (bot + BAR_SIZE) / viewHeight, 0,
+ RIGHT_CAP_TEX_COORDS[2], RIGHT_CAP_TEX_COORDS[3],
+
+ (rect.right + CAP_RADIUS) / viewWidth, (bot) / viewHeight, 0,
+ RIGHT_CAP_TEX_COORDS[4], RIGHT_CAP_TEX_COORDS[5],
+
+ (rect.right + CAP_RADIUS) / viewWidth, (bot + BAR_SIZE) / viewHeight, 0,
+ RIGHT_CAP_TEX_COORDS[6], RIGHT_CAP_TEX_COORDS[7]
+ };
+
+ coordBuffer.put(rightCap);
+
+ // Vertex coordinates are x,y,z starting at position 0 into the buffer.
+ coordBuffer.position(0);
+ GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ // Texture coordinates are texture_x, texture_y starting at position 3 into the
+ // buffer.
+ coordBuffer.position(3);
+ GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
+ coordBuffer);
+
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
} finally {
- GLES11.glDisable(GL10.GL_BLEND);
+ GLES20.glDisable(GLES20.GL_BLEND);
}
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/SingleTileLayer.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/SingleTileLayer.java
index 8993b94d5ee1..d18579e1a117 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/SingleTileLayer.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/SingleTileLayer.java
@@ -20,6 +20,7 @@
*
* Contributor(s):
* Patrick Walton <pcwalton@mozilla.com>
+ * Arkady Blyakher <rkadyb@mit.edu>
*
* 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
@@ -38,16 +39,14 @@
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.gfx.CairoImage;
+import org.mozilla.gecko.gfx.CairoUtils;
import org.mozilla.gecko.gfx.IntSize;
import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.gfx.TileLayer;
import android.graphics.PointF;
import android.graphics.RectF;
-import android.opengl.GLES11;
-import android.opengl.GLES11Ext;
+import android.opengl.GLES20;
import android.util.Log;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
@@ -70,7 +69,7 @@ public class SingleTileLayer extends TileLayer {
if (!initialized())
return;
- GLES11.glBindTexture(GL10.GL_TEXTURE_2D, getTextureID());
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureID());
RectF bounds;
int[] cropRect;
@@ -80,21 +79,49 @@ public class SingleTileLayer extends TileLayer {
if (repeats()) {
bounds = new RectF(0.0f, 0.0f, viewport.width(), viewport.height());
int width = Math.round(viewport.width());
- int height = Math.round(-viewport.height());
- cropRect = new int[] { 0, size.height, width, height };
+ int height = Math.round(viewport.height());
+ cropRect = new int[] { 0, 0, width, height };
} else {
bounds = getBounds(context, new FloatSize(size));
- cropRect = new int[] { 0, size.height, size.width, -size.height };
+ cropRect = new int[] { 0, 0, size.width, size.height };
}
- GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect,
- 0);
-
float height = bounds.height();
float left = bounds.left - viewport.left;
float top = viewport.height() - (bounds.top + height - viewport.top);
- GLES11Ext.glDrawTexfOES(left, top, 0.0f, bounds.width(), height);
+ float[] coords = {
+ //x, y, z, texture_x, texture_y
+ left/viewport.width(), top/viewport.height(), 0,
+ cropRect[0]/(float)size.width, cropRect[1]/(float)size.height,
+
+ left/viewport.width(), (top+height)/viewport.height(), 0,
+ cropRect[0]/(float)size.width, cropRect[3]/(float)size.height,
+
+ (left+bounds.width())/viewport.width(), top/viewport.height(), 0,
+ cropRect[2]/(float)size.width, cropRect[1]/(float)size.height,
+
+ (left+bounds.width())/viewport.width(), (top+height)/viewport.height(), 0,
+ cropRect[2]/(float)size.width, cropRect[3]/(float)size.height
+ };
+
+ FloatBuffer coordBuffer = context.coordBuffer;
+ int positionHandle = context.positionHandle;
+ int textureHandle = context.textureHandle;
+
+ // Make sure we are at position zero in the buffer in case other draw methods did not clean
+ // up after themselves
+ coordBuffer.position(0);
+ coordBuffer.put(coords);
+
+ // Vertex coordinates are x,y,z starting at position 0 into the buffer.
+ coordBuffer.position(0);
+ GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20, coordBuffer);
+
+ // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
+ coordBuffer.position(3);
+ GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20, coordBuffer);
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TextureReaper.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TextureReaper.java
index 047406234b44..e18139cb9bc9 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TextureReaper.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TextureReaper.java
@@ -20,6 +20,7 @@
*
* Contributor(s):
* Patrick Walton <pcwalton@mozilla.com>
+ * Arkady Blyakher <rkadyb@mit.edu>
*
* 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
@@ -37,7 +38,7 @@
package org.mozilla.gecko.gfx;
-import javax.microedition.khronos.opengles.GL10;
+import android.opengl.GLES20;
import java.util.ArrayList;
/** Manages a list of dead tiles, so we don't leak resources. */
@@ -62,13 +63,13 @@ public class TextureReaper {
mDeadTextureIDs.add(textureID);
}
- public void reap(GL10 gl) {
+ public void reap() {
int[] deadTextureIDs = new int[mDeadTextureIDs.size()];
for (int i = 0; i < deadTextureIDs.length; i++)
deadTextureIDs[i] = mDeadTextureIDs.get(i);
mDeadTextureIDs.clear();
- gl.glDeleteTextures(deadTextureIDs.length, deadTextureIDs, 0);
+ GLES20.glDeleteTextures(deadTextureIDs.length, deadTextureIDs, 0);
}
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TileLayer.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TileLayer.java
index ad52229cfbcf..64ec94dc694a 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TileLayer.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/TileLayer.java
@@ -20,6 +20,7 @@
*
* Contributor(s):
* Patrick Walton <pcwalton@mozilla.com>
+ * Arkady Blyakher <rkadyb@mit.edu>
*
* 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
@@ -37,12 +38,12 @@
package org.mozilla.gecko.gfx;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.Region;
import android.opengl.GLES20;
import android.util.Log;
-import javax.microedition.khronos.opengles.GL10;
-import javax.microedition.khronos.opengles.GL11Ext;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -104,7 +105,7 @@ public abstract class TileLayer extends Layer {
return mImage.getSize().isPositive() && (mTextureIDs == null || !mDirtyRect.isEmpty());
}
- private void validateTexture(GL10 gl) {
+ private void validateTexture() {
/* Calculate the ideal texture size. This must be a power of two if
* the texture is repeated or OpenGL ES 2.0 isn't supported, as
* OpenGL ES 2.0 is required for NPOT texture support (without
@@ -127,7 +128,7 @@ public abstract class TileLayer extends Layer {
// Free the texture immediately, so we don't incur a
// temporarily increased memory usage.
- TextureReaper.get().reap(gl);
+ TextureReaper.get().reap();
}
}
}
@@ -142,36 +143,38 @@ public abstract class TileLayer extends Layer {
}
@Override
- protected boolean performUpdates(GL10 gl, RenderContext context) {
- super.performUpdates(gl, context);
+ protected boolean performUpdates(RenderContext context) {
+ super.performUpdates(context);
- if (mSkipTextureUpdate)
+ if (mSkipTextureUpdate) {
return false;
+ }
// Reallocate the texture if the size has changed
- validateTexture(gl);
+ validateTexture();
// Don't do any work if the image has an invalid size.
if (!mImage.getSize().isPositive())
return true;
// If we haven't allocated a texture, assume the whole region is dirty
- if (mTextureIDs == null)
- uploadFullTexture(gl);
- else
- uploadDirtyRect(gl, mDirtyRect);
+ if (mTextureIDs == null) {
+ uploadFullTexture();
+ } else {
+ uploadDirtyRect(mDirtyRect);
+ }
mDirtyRect.setEmpty();
return true;
}
- private void uploadFullTexture(GL10 gl) {
+ private void uploadFullTexture() {
IntSize bufferSize = mImage.getSize();
- uploadDirtyRect(gl, new Rect(0, 0, bufferSize.width, bufferSize.height));
+ uploadDirtyRect(new Rect(0, 0, bufferSize.width, bufferSize.height));
}
- private void uploadDirtyRect(GL10 gl, Rect dirtyRect) {
+ private void uploadDirtyRect(Rect dirtyRect) {
// If we have nothing to upload, just return for now
if (dirtyRect.isEmpty())
return;
@@ -185,7 +188,7 @@ public abstract class TileLayer extends Layer {
if (mTextureIDs == null) {
mTextureIDs = new int[1];
- gl.glGenTextures(mTextureIDs.length, mTextureIDs, 0);
+ GLES20.glGenTextures(mTextureIDs.length, mTextureIDs, 0);
newlyCreated = true;
}
@@ -195,26 +198,27 @@ public abstract class TileLayer extends Layer {
int cairoFormat = mImage.getFormat();
CairoGLInfo glInfo = new CairoGLInfo(cairoFormat);
- bindAndSetGLParameters(gl);
+ bindAndSetGLParameters();
if (newlyCreated || dirtyRect.contains(bufferRect)) {
if (mSize.equals(bufferSize)) {
- gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width, mSize.height,
- 0, glInfo.format, glInfo.type, imageBuffer);
+ GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width,
+ mSize.height, 0, glInfo.format, glInfo.type, imageBuffer);
return;
} else {
- gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width, mSize.height,
- 0, glInfo.format, glInfo.type, null);
- gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, bufferSize.width, bufferSize.height,
- glInfo.format, glInfo.type, imageBuffer);
+ GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width,
+ mSize.height, 0, glInfo.format, glInfo.type, null);
+ GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, bufferSize.width,
+ bufferSize.height, glInfo.format, glInfo.type, imageBuffer);
return;
}
}
// Make sure that the dirty region intersects with the buffer rect,
// otherwise we'll end up with an invalid buffer pointer.
- if (!Rect.intersects(dirtyRect, bufferRect))
+ if (!Rect.intersects(dirtyRect, bufferRect)) {
return;
+ }
/*
* Upload the changed rect. We have to widen to the full width of the texture
@@ -232,19 +236,21 @@ public abstract class TileLayer extends Layer {
}
viewBuffer.position(position);
- gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, dirtyRect.top, bufferSize.width,
- Math.min(bufferSize.height - dirtyRect.top, dirtyRect.height()),
- glInfo.format, glInfo.type, viewBuffer);
+ GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, dirtyRect.top, bufferSize.width,
+ Math.min(bufferSize.height - dirtyRect.top, dirtyRect.height()),
+ glInfo.format, glInfo.type, viewBuffer);
}
- private void bindAndSetGLParameters(GL10 gl) {
- gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]);
- gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
- gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
+ private void bindAndSetGLParameters() {
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIDs[0]);
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
+ GLES20.GL_NEAREST);
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
+ GLES20.GL_LINEAR);
- int repeatMode = mRepeat ? GL10.GL_REPEAT : GL10.GL_CLAMP_TO_EDGE;
- gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, repeatMode);
- gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, repeatMode);
+ int repeatMode = mRepeat ? GLES20.GL_REPEAT : GLES20.GL_CLAMP_TO_EDGE;
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, repeatMode);
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, repeatMode);
}
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewTransform.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewTransform.java
new file mode 100644
index 000000000000..9f443ea52894
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewTransform.java
@@ -0,0 +1,51 @@
+/* -*- 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@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;
+
+public class ViewTransform {
+ public float x;
+ public float y;
+ public float scale;
+
+ public ViewTransform(float inX, float inY, float inScale) {
+ x = inX;
+ y = inY;
+ scale = inScale;
+ }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewportMetrics.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewportMetrics.java
index d03b423df9bb..d98b47421520 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewportMetrics.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/ViewportMetrics.java
@@ -38,22 +38,14 @@
package org.mozilla.gecko.gfx;
-import android.graphics.Point;
import android.graphics.PointF;
-import android.graphics.Rect;
import android.graphics.RectF;
import android.util.DisplayMetrics;
-import org.libreoffice.LibreOfficeMainActivity;
-import org.mozilla.gecko.util.FloatUtils;
-//import org.mozilla.gecko.GeckoApp;
-import org.mozilla.gecko.gfx.FloatSize;
-import org.mozilla.gecko.gfx.IntSize;
-import org.mozilla.gecko.gfx.LayerController;
-import org.mozilla.gecko.gfx.RectUtils;
import org.json.JSONException;
import org.json.JSONObject;
-import android.util.Log;
+import org.libreoffice.LibreOfficeMainActivity;
+import org.mozilla.gecko.util.FloatUtils;
/**
* ViewportMetrics manages state and contains some utility functions related to
@@ -61,28 +53,24 @@ import android.util.Log;
*/
public class ViewportMetrics {
private static final String LOGTAG = "GeckoViewportMetrics";
-
+ private static final float MAX_BIAS = 0.8f;
private FloatSize mPageSize;
private RectF mViewportRect;
private PointF mViewportOffset;
private float mZoomFactor;
- private boolean mAllowZoom;
-
// A scale from -1,-1 to 1,1 that represents what edge of the displayport
// we want the viewport to be biased towards.
private PointF mViewportBias;
- private static final float MAX_BIAS = 0.8f;
public ViewportMetrics() {
DisplayMetrics metrics = new DisplayMetrics();
- /*GeckoApp*/LibreOfficeMainActivity.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ LibreOfficeMainActivity.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
mPageSize = new FloatSize(metrics.widthPixels, metrics.heightPixels);
mViewportRect = new RectF(0, 0, metrics.widthPixels, metrics.heightPixels);
mViewportOffset = new PointF(0, 0);
mZoomFactor = 1.0f;
mViewportBias = new PointF(0.0f, 0.0f);
- mAllowZoom = true;
}
public ViewportMetrics(ViewportMetrics viewport) {
@@ -92,21 +80,18 @@ public class ViewportMetrics {
mViewportOffset = new PointF(offset.x, offset.y);
mZoomFactor = viewport.getZoomFactor();
mViewportBias = viewport.mViewportBias;
- mAllowZoom = viewport.mAllowZoom;
}
public ViewportMetrics(JSONObject json) throws JSONException {
- float x = (float)json.getDouble("x");
- float y = (float)json.getDouble("y");
- float width = (float)json.getDouble("width");
- float height = (float)json.getDouble("height");
- float pageWidth = (float)json.getDouble("pageWidth");
- float pageHeight = (float)json.getDouble("pageHeight");
- float offsetX = (float)json.getDouble("offsetX");
- float offsetY = (float)json.getDouble("offsetY");
- float zoom = (float)json.getDouble("zoom");
-
- mAllowZoom = json.getBoolean("allowZoom");
+ float x = (float) json.getDouble("x");
+ float y = (float) json.getDouble("y");
+ float width = (float) json.getDouble("width");
+ float height = (float) json.getDouble("height");
+ float pageWidth = (float) json.getDouble("pageWidth");
+ float pageHeight = (float) json.getDouble("pageHeight");
+ float offsetX = (float) json.getDouble("offsetX");
+ float offsetY = (float) json.getDouble("offsetY");
+ float zoom = (float) json.getDouble("zoom");
mPageSize = new FloatSize(pageWidth, pageHeight);
mViewportRect = new RectF(x, y, x + width, y + height);
@@ -148,6 +133,29 @@ public class ViewportMetrics {
return new PointF(mViewportRect.left, mViewportRect.top);
}
+ public void setOrigin(PointF origin) {
+ // When the origin is set, we compare it with the last value set and
+ // change the viewport bias accordingly, so that any viewport based
+ // on these metrics will have a larger buffer in the direction of
+ // movement.
+
+ // XXX Note the comment about bug #524925 in getOptimumViewportOffset.
+ // Ideally, the viewport bias would be a sliding scale, but we
+ // don't want to change it too often at the moment.
+ if (FloatUtils.fuzzyEquals(origin.x, mViewportRect.left))
+ mViewportBias.x = 0;
+ else
+ mViewportBias.x = ((mViewportRect.left - origin.x) > 0) ? MAX_BIAS : -MAX_BIAS;
+ if (FloatUtils.fuzzyEquals(origin.y, mViewportRect.top))
+ mViewportBias.y = 0;
+ else
+ mViewportBias.y = ((mViewportRect.top - origin.y) > 0) ? MAX_BIAS : -MAX_BIAS;
+
+ mViewportRect.set(origin.x, origin.y,
+ origin.x + mViewportRect.width(),
+ origin.y + mViewportRect.height());
+ }
+
public PointF getDisplayportOrigin() {
return new PointF(mViewportRect.left - mViewportOffset.x,
mViewportRect.top - mViewportOffset.y);
@@ -157,11 +165,22 @@ public class ViewportMetrics {
return new FloatSize(mViewportRect.width(), mViewportRect.height());
}
+ public void setSize(FloatSize size) {
+ mViewportRect.right = mViewportRect.left + size.width;
+ mViewportRect.bottom = mViewportRect.top + size.height;
+ }
+
public RectF getViewport() {
return mViewportRect;
}
- /** Returns the viewport rectangle, clamped within the page-size. */
+ public void setViewport(RectF viewport) {
+ mViewportRect = viewport;
+ }
+
+ /**
+ * Returns the viewport rectangle, clamped within the page-size.
+ */
public RectF getClampedViewport() {
RectF clampedViewport = new RectF(mViewportRect);
@@ -185,56 +204,20 @@ public class ViewportMetrics {
return mViewportOffset;
}
- public FloatSize getPageSize() {
- return mPageSize;
- }
-
- public float getZoomFactor() {
- return mZoomFactor;
+ public void setViewportOffset(PointF offset) {
+ mViewportOffset = offset;
}
- public boolean getAllowZoom() {
- return mAllowZoom;
+ public FloatSize getPageSize() {
+ return mPageSize;
}
public void setPageSize(FloatSize pageSize) {
mPageSize = pageSize;
}
- public void setViewport(RectF viewport) {
- mViewportRect = viewport;
- }
-
- public void setOrigin(PointF origin) {
- // When the origin is set, we compare it with the last value set and
- // change the viewport bias accordingly, so that any viewport based
- // on these metrics will have a larger buffer in the direction of
- // movement.
-
- // XXX Note the comment about bug #524925 in getOptimumViewportOffset.
- // Ideally, the viewport bias would be a sliding scale, but we
- // don't want to change it too often at the moment.
- if (FloatUtils.fuzzyEquals(origin.x, mViewportRect.left))
- mViewportBias.x = 0;
- else
- mViewportBias.x = ((mViewportRect.left - origin.x) > 0) ? MAX_BIAS : -MAX_BIAS;
- if (FloatUtils.fuzzyEquals(origin.y, mViewportRect.top))
- mViewportBias.y = 0;
- else
- mViewportBias.y = ((mViewportRect.top - origin.y) > 0) ? MAX_BIAS : -MAX_BIAS;
-
- mViewportRect.set(origin.x, origin.y,
- origin.x + mViewportRect.width(),
- origin.y + mViewportRect.height());
- }
-
- public void setSize(FloatSize size) {
- mViewportRect.right = mViewportRect.left + size.width;
- mViewportRect.bottom = mViewportRect.top + size.height;
- }
-
- public void setViewportOffset(PointF offset) {
- mViewportOffset = offset;
+ public float getZoomFactor() {
+ return mZoomFactor;
}
public void setZoomFactor(float zoomFactor) {
@@ -320,3 +303,4 @@ public class ViewportMetrics {
return buff.toString();
}
}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/VirtualLayer.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/VirtualLayer.java
new file mode 100644
index 000000000000..0f314ae71620
--- /dev/null
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/VirtualLayer.java
@@ -0,0 +1,80 @@
+/* -*- 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@mozilla.com>
+ * Chris Lord <chrislord.net@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;
+
+public class VirtualLayer extends Layer {
+ private Listener mListener;
+ private IntSize mSize;
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void draw(RenderContext context) {
+ // No-op.
+ }
+
+ @Override
+ public IntSize getSize() {
+ return mSize;
+ }
+
+ public void setSize(IntSize size) {
+ mSize = size;
+ }
+
+ @Override
+ protected boolean performUpdates(RenderContext context) {
+ boolean dimensionsChanged = dimensionChangesPending();
+ boolean result = super.performUpdates(context);
+ if (dimensionsChanged && mListener != null) {
+ mListener.dimensionsChanged(getOrigin(), getResolution());
+ }
+
+ return result;
+ }
+
+ public interface Listener {
+ void dimensionsChanged(Point newOrigin, float newResolution);
+ }
+}
+
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/WidgetTileLayer.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/WidgetTileLayer.java
index 7cbcdb3a016d..b123d55c403d 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/WidgetTileLayer.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/gfx/WidgetTileLayer.java
@@ -20,6 +20,7 @@
*
* Contributor(s):
* James Willcox <jwillcox@mozilla.com>
+ * Arkady Blyakher <rkadyb@mit.edu>
*
* 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
@@ -41,11 +42,10 @@ import org.libreoffice.LOKitShell;
import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.gfx.SingleTileLayer;
//import org.mozilla.gecko.GeckoAppShell;
-import android.opengl.GLES11;
-import android.opengl.GLES11Ext;
import android.graphics.RectF;
import android.util.Log;
-import javax.microedition.khronos.opengles.GL10;
+import android.opengl.GLES20;
+import java.nio.FloatBuffer;
/**
* Encapsulates the logic needed to draw the single-tiled Gecko texture
@@ -66,9 +66,9 @@ public class WidgetTileLayer extends Layer {
public IntSize getSize() { return mImage.getSize(); }
protected void bindAndSetGLParameters() {
- GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]);
- GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
- GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIDs[0]);
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
}
@Override
@@ -78,16 +78,16 @@ public class WidgetTileLayer extends Layer {
}
@Override
- protected boolean performUpdates(GL10 gl, RenderContext context) {
- super.performUpdates(gl, context);
+ protected boolean performUpdates(RenderContext context) {
+ super.performUpdates(context);
if (mTextureIDs == null) {
mTextureIDs = new int[1];
- GLES11.glGenTextures(1, mTextureIDs, 0);
+ GLES20.glGenTextures(1, mTextureIDs, 0);
}
bindAndSetGLParameters();
- /*GeckoAppShell*/LOKitShell.bindWidgetTexture();
+ LOKitShell.bindWidgetTexture();
return true;
}
@@ -99,7 +99,7 @@ public class WidgetTileLayer extends Layer {
if (!initialized())
return;
- GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIDs[0]);
RectF bounds;
int[] cropRect;
@@ -107,21 +107,52 @@ public class WidgetTileLayer extends Layer {
RectF viewport = context.viewport;
bounds = getBounds(context, new FloatSize(size));
- cropRect = new int[] { 0, size.height, size.width, -size.height };
+ cropRect = new int[] { 0, 0, size.width, size.height };
bounds.offset(-viewport.left, -viewport.top);
- GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect,
- 0);
-
float top = viewport.height() - (bounds.top + bounds.height());
// There may be errors from a previous GL call, so clear them first because
// we want to check for one below
- while (GLES11.glGetError() != GLES11.GL_NO_ERROR);
+ while (GLES20.glGetError() != GLES20.GL_NO_ERROR);
+
+ float[] coords = {
+ //x, y, z, texture_x, texture_y
+ bounds.left/viewport.width(), top/viewport.height(), 0,
+ cropRect[0]/size.width, cropRect[1]/size.height,
+
+ bounds.left/viewport.width(), (top+bounds.height())/viewport.height(), 0,
+ cropRect[0]/size.width, cropRect[3]/size.height,
+
+ (bounds.left+bounds.width())/viewport.width(), top/viewport.height(), 0,
+ cropRect[2]/size.width, cropRect[1]/size.height,
+
+ (bounds.left+bounds.width())/viewport.width(), (top+bounds.height())/viewport.height(),
+ 0,
+ cropRect[2]/size.width, cropRect[3]/size.height
+ };
+
+ // Get the buffer and handles from the context
+ FloatBuffer coordBuffer = context.coordBuffer;
+ int positionHandle = context.positionHandle;
+ int textureHandle = context.textureHandle;
+
+ // Make sure we are at position zero in the buffer in case other draw methods did not clean
+ // up after themselves
+ coordBuffer.position(0);
+ coordBuffer.put(coords);
+
+ // Vertex coordinates are x,y,z starting at position 0 into the buffer.
+ coordBuffer.position(0);
+ GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20, coordBuffer);
+
+ // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
+ coordBuffer.position(3);
+ GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20, coordBuffer);
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
- GLES11Ext.glDrawTexfOES(bounds.left, top, 0.0f, bounds.width(), bounds.height());
- int error = GLES11.glGetError();
- if (error != GLES11.GL_NO_ERROR) {
+ int error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
Log.i(LOGTAG, "Failed to draw texture: " + error);
}
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/Axis.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/Axis.java
index 1d8138de7d51..8c0fce4c73b3 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/Axis.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/Axis.java
@@ -61,7 +61,7 @@ abstract class Axis {
// The rate of deceleration when the surface has overscrolled.
private static final float OVERSCROLL_DECEL_RATE = 0.04f;
// The percentage of the surface which can be overscrolled before it must snap back.
- private static final float SNAP_LIMIT = 0.3f;
+ private static final float SNAP_LIMIT = 0.75f;
// The minimum amount of space that must be present for an axis to be considered scrollable,
// in pixels.
@@ -268,4 +268,4 @@ abstract class Axis {
mDisplacement = 0.0f;
return d;
}
-} \ No newline at end of file
+}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/PanZoomController.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/PanZoomController.java
index 58c52e26ff99..c3cacccf805e 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/PanZoomController.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/PanZoomController.java
@@ -47,9 +47,6 @@ import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.gfx.PointUtils;
import org.mozilla.gecko.gfx.ViewportMetrics;
import org.mozilla.gecko.util.FloatUtils;
-//import org.mozilla.gecko.GeckoApp;
-//import org.mozilla.gecko.GeckoAppShell;
-//import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoEventListener;
import android.graphics.PointF;
import android.graphics.RectF;
@@ -89,7 +86,7 @@ public class PanZoomController
private static final double AXIS_LOCK_ANGLE = Math.PI / 6.0; // 30 degrees
// The maximum amount we allow you to zoom into a page
- private static final float MAX_ZOOM = 12.0f;
+ private static final float MAX_ZOOM = 4.0f;
/* 16 precomputed frames of the _ease-out_ animation from the CSS Transitions specification. */
private static final float[] EASE_OUT_ANIMATION_FRAMES = {
@@ -148,7 +145,7 @@ public class PanZoomController
mX = new AxisX(mSubscroller);
mY = new AxisY(mSubscroller);
- mMainThread = /*GeckoApp*/LibreOfficeMainActivity.mAppContext.getMainLooper().getThread();
+ mMainThread = LibreOfficeMainActivity.mAppContext.getMainLooper().getThread();
checkMainThread();
mState = PanZoomState.NOTHING;
@@ -254,6 +251,7 @@ public class PanZoomController
/*
* Panning/scrolling
*/
+
private boolean onTouchStart(MotionEvent event) {
Log.d(LOGTAG, "onTouchStart in state " + mState);
// user is taking control of movement, so stop
@@ -298,12 +296,12 @@ public class PanZoomController
cancelTouch();
startPanning(event.getX(0), event.getY(0), event.getEventTime());
//GeckoApp.mAppContext.hidePlugins(false /* don't hide layers */);
- //GeckoApp.mFormAssistPopup.hide();
+ //GeckoApp.mAutoCompletePopup.hide();
track(event);
return true;
case PANNING_HOLD_LOCKED:
- //GeckoApp.mFormAssistPopup.hide();
+ //GeckoApp.mAutoCompletePopup.hide();
mState = PanZoomState.PANNING_LOCKED;
// fall through
case PANNING_LOCKED:
@@ -311,7 +309,7 @@ public class PanZoomController
return true;
case PANNING_HOLD:
- //GeckoApp.mFormAssistPopup.hide();
+ //GeckoApp.mAutoCompletePopup.hide();
mState = PanZoomState.PANNING;
// fall through
case PANNING:
@@ -761,7 +759,7 @@ public class PanZoomController
mState = PanZoomState.PINCHING;
mLastZoomFocus = new PointF(detector.getFocusX(), detector.getFocusY());
//GeckoApp.mAppContext.hidePlugins(false /* don't hide layers, only views */);
- //GeckoApp.mFormAssistPopup.hide();
+ //GeckoApp.mAutoCompletePopup.hide();
cancelTouch();
return true;
@@ -771,12 +769,6 @@ public class PanZoomController
public boolean onScale(SimpleScaleGestureDetector detector) {
Log.d(LOGTAG, "onScale in state " + mState);
- //if (GeckoApp.mDOMFullScreen)
- // return false;
-
- if (!mController.getViewportMetrics().getAllowZoom())
- return false;
-
if (mState == PanZoomState.ANIMATED_ZOOM)
return false;
@@ -837,7 +829,7 @@ public class PanZoomController
}
public boolean getRedrawHint() {
- return (mState == PanZoomState.NOTHING || mState == PanZoomState.FLING);
+ return (mState != PanZoomState.PINCHING && mState != PanZoomState.ANIMATED_ZOOM);
}
private void sendPointToGecko(String event, MotionEvent motionEvent) {
@@ -870,7 +862,7 @@ public class PanZoomController
@Override
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
- //GeckoApp.mFormAssistPopup.hide();
+ //GeckoApp.mAutoCompletePopup.hide();
sendPointToGecko("Gesture:SingleTap", motionEvent);
return true;
}
@@ -887,7 +879,7 @@ public class PanZoomController
}
private boolean animatedZoomTo(RectF zoomToRect) {
- //GeckoApp.mFormAssistPopup.hide();
+ //GeckoApp.mAutoCompletePopup.hide();
mState = PanZoomState.ANIMATED_ZOOM;
final float startZoom = mController.getZoomFactor();
@@ -926,4 +918,4 @@ public class PanZoomController
bounce(finalMetrics);
return true;
}
-} \ No newline at end of file
+}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java
index 5184bd18a462..4f9e39857e81 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java
@@ -81,19 +81,19 @@ public class SimpleScaleGestureDetector {
/** Forward touch events to this function. */
public void onTouchEvent(MotionEvent event) {
- switch (event.getAction() & event.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN:
- onTouchStart(event);
- break;
- case MotionEvent.ACTION_MOVE:
- onTouchMove(event);
- break;
- case MotionEvent.ACTION_POINTER_UP:
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- onTouchEnd(event);
- break;
+ switch (event.getAction() & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ onTouchStart(event);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ onTouchMove(event);
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ onTouchEnd(event);
+ break;
}
}
@@ -103,7 +103,7 @@ public class SimpleScaleGestureDetector {
private int getActionIndex(MotionEvent event) {
return (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
}
private void onTouchStart(MotionEvent event) {
@@ -156,11 +156,11 @@ public class SimpleScaleGestureDetector {
*/
public float getFocusX() {
switch (getPointersDown()) {
- case 1:
- return mPointerInfo.getFirst().getCurrent().x;
- case 2:
- PointerInfo pointerA = mPointerInfo.getFirst(), pointerB = mPointerInfo.getLast();
- return (pointerA.getCurrent().x + pointerB.getCurrent().x) / 2.0f;
+ case 1:
+ return mPointerInfo.getFirst().getCurrent().x;
+ case 2:
+ PointerInfo pointerA = mPointerInfo.getFirst(), pointerB = mPointerInfo.getLast();
+ return (pointerA.getCurrent().x + pointerB.getCurrent().x) / 2.0f;
}
Log.e(LOGTAG, "No gesture taking place in getFocusX()!");
@@ -173,11 +173,11 @@ public class SimpleScaleGestureDetector {
*/
public float getFocusY() {
switch (getPointersDown()) {
- case 1:
- return mPointerInfo.getFirst().getCurrent().y;
- case 2:
- PointerInfo pointerA = mPointerInfo.getFirst(), pointerB = mPointerInfo.getLast();
- return (pointerA.getCurrent().y + pointerB.getCurrent().y) / 2.0f;
+ case 1:
+ return mPointerInfo.getFirst().getCurrent().y;
+ case 2:
+ PointerInfo pointerA = mPointerInfo.getFirst(), pointerB = mPointerInfo.getLast();
+ return (pointerA.getCurrent().y + pointerB.getCurrent().y) / 2.0f;
}
Log.e(LOGTAG, "No gesture taking place in getFocusY()!");
@@ -225,9 +225,9 @@ public class SimpleScaleGestureDetector {
/* Sends the requested scale gesture notification to the listener. */
private void sendScaleGesture(EventType eventType) {
switch (eventType) {
- case BEGIN: mListener.onScaleBegin(this); break;
- case CONTINUE: mListener.onScale(this); break;
- case END: mListener.onScaleEnd(this); break;
+ case BEGIN: mListener.onScaleBegin(this); break;
+ case CONTINUE: mListener.onScale(this); break;
+ case END: mListener.onScaleEnd(this); break;
}
}
diff --git a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java
index c7da61acda2b..f24a5b7adaa1 100644
--- a/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java
+++ b/android/experimental/LOAndroid2/app/src/main/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java
@@ -37,15 +37,15 @@
package org.mozilla.gecko.ui;
-//import org.mozilla.gecko.GeckoAppShell;
-//import org.mozilla.gecko.GeckoEvent;
-import org.mozilla.gecko.GeckoEventListener;
-import org.json.JSONObject;
-import org.json.JSONException;
+
import android.graphics.PointF;
import android.os.Handler;
import android.util.Log;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.gecko.GeckoEventListener;
+
class SubdocumentScrollHelper implements GeckoEventListener {
private static final String LOGTAG = "GeckoSubdocumentScrollHelper";
@@ -73,11 +73,11 @@ class SubdocumentScrollHelper implements GeckoEventListener {
}
boolean scrollBy(PointF displacement) {
- if (! mOverridePanning) {
+ if (!mOverridePanning) {
return false;
}
- if (! mOverrideScrollAck) {
+ if (!mOverrideScrollAck) {
mOverrideScrollPending = true;
return true;
}
@@ -92,7 +92,7 @@ class SubdocumentScrollHelper implements GeckoEventListener {
} catch (JSONException e) {
Log.e(LOGTAG, "Error forming subwindow scroll message: ", e);
}
- //GeckoAppShell.sendEventToGecko(new GeckoEvent(MESSAGE_SCROLL, json.toString()));
+ //GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(MESSAGE_SCROLL, json.toString()));
return true;
}