Avoid potential negative array index access to cached text.
[LibreOffice.git] / android / source / src / java / org / mozilla / gecko / gfx / LayerView.java
blob29049f92912d3347931932d0ec6015336d966603
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org.mozilla.gecko.gfx;
9 import android.content.Context;
10 import android.content.res.Resources;
11 import android.graphics.Bitmap;
12 import android.graphics.BitmapFactory;
13 import android.graphics.PixelFormat;
14 import android.util.AttributeSet;
15 import android.util.Log;
16 import android.view.KeyEvent;
17 import android.view.MotionEvent;
18 import android.view.SurfaceHolder;
19 import android.view.SurfaceView;
20 import android.view.View;
21 import android.view.ViewGroup;
22 import android.view.inputmethod.EditorInfo;
23 import android.view.inputmethod.InputConnection;
24 import android.widget.FrameLayout;
26 import org.libreoffice.LOEvent;
27 import org.libreoffice.LOKitShell;
28 import org.libreoffice.LibreOfficeMainActivity;
29 import org.libreoffice.R;
30 import org.mozilla.gecko.OnInterceptTouchListener;
31 import org.mozilla.gecko.OnSlideSwipeListener;
33 /**
34 * A view rendered by the layer compositor.
36 * This view delegates to LayerRenderer to actually do the drawing. Its role is largely that of a
37 * mediator between the LayerRenderer and the LayerController.
39 public class LayerView extends FrameLayout {
40 private static String LOGTAG = LayerView.class.getName();
42 private GeckoLayerClient mLayerClient;
43 private PanZoomController mPanZoomController;
44 private GLController mGLController;
45 private InputConnectionHandler mInputConnectionHandler;
46 private LayerRenderer mRenderer;
48 private SurfaceView mSurfaceView;
50 private Listener mListener;
51 private OnInterceptTouchListener mTouchIntercepter;
52 private LibreOfficeMainActivity mContext;
54 public LayerView(Context context, AttributeSet attrs) {
55 super(context, attrs);
56 mContext = (LibreOfficeMainActivity) context;
58 mSurfaceView = new SurfaceView(context);
59 addView(mSurfaceView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
61 SurfaceHolder holder = mSurfaceView.getHolder();
62 holder.addCallback(new SurfaceListener());
63 holder.setFormat(PixelFormat.RGB_565);
65 mGLController = new GLController(this);
68 void connect(GeckoLayerClient layerClient) {
69 mLayerClient = layerClient;
70 mPanZoomController = mLayerClient.getPanZoomController();
71 mRenderer = new LayerRenderer(this);
72 mInputConnectionHandler = null;
74 setFocusable(true);
75 setFocusableInTouchMode(true);
77 createGLThread();
78 setOnTouchListener(new OnSlideSwipeListener(getContext(), mLayerClient));
81 public void show() {
82 // Fix this if TextureView support is turned back on above
83 mSurfaceView.setVisibility(View.VISIBLE);
86 public void hide() {
87 // Fix this if TextureView support is turned back on above
88 mSurfaceView.setVisibility(View.INVISIBLE);
91 public void destroy() {
92 if (mLayerClient != null) {
93 mLayerClient.destroy();
95 if (mRenderer != null) {
96 mRenderer.destroy();
100 public void setTouchIntercepter(final OnInterceptTouchListener touchIntercepter) {
101 // this gets run on the gecko thread, but for thread safety we want the assignment
102 // on the UI thread.
103 post(new Runnable() {
104 public void run() {
105 mTouchIntercepter = touchIntercepter;
110 public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler) {
111 mInputConnectionHandler = inputConnectionHandler;
114 @Override
115 public boolean onTouchEvent(MotionEvent event) {
116 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
117 requestFocus();
120 if (mTouchIntercepter != null && mTouchIntercepter.onInterceptTouchEvent(this, event)) {
121 return true;
123 if (mPanZoomController != null && mPanZoomController.onTouchEvent(event)) {
124 return true;
126 if (mTouchIntercepter != null && mTouchIntercepter.onTouch(this, event)) {
127 return true;
129 return false;
132 @Override
133 public boolean onHoverEvent(MotionEvent event) {
134 return mTouchIntercepter != null && mTouchIntercepter.onTouch(this, event);
137 @Override
138 public boolean onGenericMotionEvent(MotionEvent event) {
139 return mPanZoomController != null && mPanZoomController.onMotionEvent(event);
142 public GeckoLayerClient getLayerClient() { return mLayerClient; }
143 public PanZoomController getPanZoomController() { return mPanZoomController; }
145 public ImmutableViewportMetrics getViewportMetrics() {
146 return mLayerClient.getViewportMetrics();
149 @Override
150 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
151 if (mInputConnectionHandler != null)
152 return mInputConnectionHandler.onCreateInputConnection(outAttrs);
153 return null;
156 @Override
157 public boolean onKeyPreIme(int keyCode, KeyEvent event) {
158 return mInputConnectionHandler != null && mInputConnectionHandler.onKeyPreIme(keyCode, event);
161 @Override
162 public boolean onKeyDown(int keyCode, KeyEvent event) {
163 return mInputConnectionHandler != null && mInputConnectionHandler.onKeyDown(keyCode, event);
166 @Override
167 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
168 return mInputConnectionHandler != null && mInputConnectionHandler.onKeyLongPress(keyCode, event);
171 @Override
172 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
173 return mInputConnectionHandler != null && mInputConnectionHandler.onKeyMultiple(keyCode, repeatCount, event);
176 @Override
177 public boolean onKeyUp(int keyCode, KeyEvent event) {
178 return mInputConnectionHandler != null && mInputConnectionHandler.onKeyUp(keyCode, event);
181 public void requestRender() {
182 if (mListener != null) {
183 mListener.renderRequested();
187 public void addLayer(Layer layer) {
188 mRenderer.addLayer(layer);
191 public void removeLayer(Layer layer) {
192 mRenderer.removeLayer(layer);
195 public int getMaxTextureSize() {
196 return mRenderer.getMaxTextureSize();
199 public void setLayerRenderer(LayerRenderer renderer) {
200 mRenderer = renderer;
203 public LayerRenderer getLayerRenderer() {
204 return mRenderer;
207 public LayerRenderer getRenderer() {
208 return mRenderer;
211 public void setListener(Listener listener) {
212 mListener = listener;
215 Listener getListener() {
216 return mListener;
219 public GLController getGLController() {
220 return mGLController;
223 public Bitmap getDrawable(String name) {
224 Context context = getContext();
225 Resources resources = context.getResources();
226 String packageName = resources.getResourcePackageName(R.id.dummy_id_for_package_name_resolution);
227 int resourceID = resources.getIdentifier(name, "drawable", packageName);
228 BitmapFactory.Options options = new BitmapFactory.Options();
229 options.inScaled = false;
230 return BitmapFactory.decodeResource(context.getResources(), resourceID, options);
233 Bitmap getBackgroundPattern() {
234 return getDrawable("background");
237 Bitmap getShadowPattern() {
238 return getDrawable("shadow");
241 private void onSizeChanged(int width, int height) {
242 mGLController.surfaceChanged(width, height);
244 mLayerClient.setViewportSize(new FloatSize(width, height), false);
246 if (mListener != null) {
247 mListener.surfaceChanged(width, height);
250 LOKitShell.sendEvent(new LOEvent(LOEvent.UPDATE_ZOOM_CONSTRAINTS));
253 private void onDestroyed() {
254 mGLController.surfaceDestroyed();
256 if (mListener != null) {
257 mListener.compositionPauseRequested();
261 public Object getNativeWindow() {
262 return mSurfaceView.getHolder();
265 public interface Listener {
266 void compositorCreated();
267 void renderRequested();
268 void compositionPauseRequested();
269 void surfaceChanged(int width, int height);
272 private class SurfaceListener implements SurfaceHolder.Callback {
273 public void surfaceChanged(SurfaceHolder holder, int format, int width,
274 int height) {
275 onSizeChanged(width, height);
278 public void surfaceCreated(SurfaceHolder holder) {
279 if (mRenderControllerThread != null) {
280 mRenderControllerThread.surfaceCreated();
284 public void surfaceDestroyed(SurfaceHolder holder) {
285 onDestroyed();
289 @Override
290 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
291 super.onLayout(changed, left, top, right, bottom);
292 if (changed) {
293 mLayerClient.setViewportSize(new FloatSize(right - left, bottom - top), true);
297 private RenderControllerThread mRenderControllerThread;
299 public synchronized void createGLThread() {
300 if (mRenderControllerThread != null) {
301 throw new LayerViewException ("createGLThread() called with a GL thread already in place!");
304 Log.e(LOGTAG, "### Creating GL thread!");
305 mRenderControllerThread = new RenderControllerThread(mGLController);
306 mRenderControllerThread.start();
307 setListener(mRenderControllerThread);
308 notifyAll();
311 public synchronized Thread destroyGLThread() {
312 // Wait for the GL thread to be started.
313 Log.e(LOGTAG, "### Waiting for GL thread to be created...");
314 while (mRenderControllerThread == null) {
315 try {
316 wait();
317 } catch (InterruptedException e) {
318 throw new RuntimeException(e);
322 Log.e(LOGTAG, "### Destroying GL thread!");
323 Thread thread = mRenderControllerThread;
324 mRenderControllerThread.shutdown();
325 setListener(null);
326 mRenderControllerThread = null;
327 return thread;
330 public static class LayerViewException extends RuntimeException {
331 public static final long serialVersionUID = 1L;
333 LayerViewException(String e) {
334 super(e);