mobile/android/base/gfx/LayerView.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko.gfx;
michael@0 7
michael@0 8 import org.mozilla.gecko.GeckoAccessibility;
michael@0 9 import org.mozilla.gecko.GeckoAppShell;
michael@0 10 import org.mozilla.gecko.GeckoEvent;
michael@0 11 import org.mozilla.gecko.PrefsHelper;
michael@0 12 import org.mozilla.gecko.R;
michael@0 13 import org.mozilla.gecko.Tab;
michael@0 14 import org.mozilla.gecko.Tabs;
michael@0 15 import org.mozilla.gecko.TouchEventInterceptor;
michael@0 16 import org.mozilla.gecko.ZoomConstraints;
michael@0 17 import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
michael@0 18 import org.mozilla.gecko.mozglue.RobocopTarget;
michael@0 19 import org.mozilla.gecko.EventDispatcher;
michael@0 20
michael@0 21 import android.content.Context;
michael@0 22 import android.graphics.Bitmap;
michael@0 23 import android.graphics.BitmapFactory;
michael@0 24 import android.graphics.Canvas;
michael@0 25 import android.graphics.Color;
michael@0 26 import android.graphics.Point;
michael@0 27 import android.graphics.PointF;
michael@0 28 import android.graphics.Rect;
michael@0 29 import android.graphics.SurfaceTexture;
michael@0 30 import android.os.Build;
michael@0 31 import android.os.Handler;
michael@0 32 import android.util.AttributeSet;
michael@0 33 import android.util.DisplayMetrics;
michael@0 34 import android.util.Log;
michael@0 35 import android.view.KeyEvent;
michael@0 36 import android.view.MotionEvent;
michael@0 37 import android.view.SurfaceHolder;
michael@0 38 import android.view.SurfaceView;
michael@0 39 import android.view.TextureView;
michael@0 40 import android.view.View;
michael@0 41 import android.view.ViewGroup;
michael@0 42 import android.view.inputmethod.EditorInfo;
michael@0 43 import android.view.inputmethod.InputConnection;
michael@0 44 import android.widget.FrameLayout;
michael@0 45
michael@0 46 import java.nio.IntBuffer;
michael@0 47 import java.util.ArrayList;
michael@0 48
michael@0 49 /**
michael@0 50 * A view rendered by the layer compositor.
michael@0 51 *
michael@0 52 * Note that LayerView is accessed by Robocop via reflection.
michael@0 53 */
michael@0 54 public class LayerView extends FrameLayout implements Tabs.OnTabsChangedListener {
michael@0 55 private static String LOGTAG = "GeckoLayerView";
michael@0 56
michael@0 57 private GeckoLayerClient mLayerClient;
michael@0 58 private PanZoomController mPanZoomController;
michael@0 59 private LayerMarginsAnimator mMarginsAnimator;
michael@0 60 private GLController mGLController;
michael@0 61 private InputConnectionHandler mInputConnectionHandler;
michael@0 62 private LayerRenderer mRenderer;
michael@0 63 /* Must be a PAINT_xxx constant */
michael@0 64 private int mPaintState;
michael@0 65 private int mBackgroundColor;
michael@0 66 private boolean mFullScreen;
michael@0 67
michael@0 68 private SurfaceView mSurfaceView;
michael@0 69 private TextureView mTextureView;
michael@0 70
michael@0 71 private Listener mListener;
michael@0 72
michael@0 73 /* This should only be modified on the Java UI thread. */
michael@0 74 private final ArrayList<TouchEventInterceptor> mTouchInterceptors;
michael@0 75 private final Overscroll mOverscroll;
michael@0 76
michael@0 77 /* Flags used to determine when to show the painted surface. */
michael@0 78 public static final int PAINT_START = 0;
michael@0 79 public static final int PAINT_BEFORE_FIRST = 1;
michael@0 80 public static final int PAINT_AFTER_FIRST = 2;
michael@0 81
michael@0 82 public boolean shouldUseTextureView() {
michael@0 83 // Disable TextureView support for now as it causes panning/zooming
michael@0 84 // performance regressions (see bug 792259). Uncomment the code below
michael@0 85 // once this bug is fixed.
michael@0 86 return false;
michael@0 87
michael@0 88 /*
michael@0 89 // we can only use TextureView on ICS or higher
michael@0 90 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
michael@0 91 Log.i(LOGTAG, "Not using TextureView: not on ICS+");
michael@0 92 return false;
michael@0 93 }
michael@0 94
michael@0 95 try {
michael@0 96 // and then we can only use it if we have a hardware accelerated window
michael@0 97 Method m = View.class.getMethod("isHardwareAccelerated", (Class[]) null);
michael@0 98 return (Boolean) m.invoke(this);
michael@0 99 } catch (Exception e) {
michael@0 100 Log.i(LOGTAG, "Not using TextureView: caught exception checking for hw accel: " + e.toString());
michael@0 101 return false;
michael@0 102 } */
michael@0 103 }
michael@0 104
michael@0 105 public LayerView(Context context, AttributeSet attrs) {
michael@0 106 super(context, attrs);
michael@0 107
michael@0 108 mGLController = GLController.getInstance(this);
michael@0 109 mPaintState = PAINT_START;
michael@0 110 mBackgroundColor = Color.WHITE;
michael@0 111
michael@0 112 mTouchInterceptors = new ArrayList<TouchEventInterceptor>();
michael@0 113 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
michael@0 114 mOverscroll = new OverscrollEdgeEffect(this);
michael@0 115 } else {
michael@0 116 mOverscroll = null;
michael@0 117 }
michael@0 118 Tabs.registerOnTabsChangedListener(this);
michael@0 119 }
michael@0 120
michael@0 121 public LayerView(Context context) {
michael@0 122 this(context, null);
michael@0 123 }
michael@0 124
michael@0 125 public void initializeView(EventDispatcher eventDispatcher) {
michael@0 126 mLayerClient = new GeckoLayerClient(getContext(), this, eventDispatcher);
michael@0 127 if (mOverscroll != null) {
michael@0 128 mLayerClient.setOverscrollHandler(mOverscroll);
michael@0 129 }
michael@0 130
michael@0 131 mPanZoomController = mLayerClient.getPanZoomController();
michael@0 132 mMarginsAnimator = mLayerClient.getLayerMarginsAnimator();
michael@0 133
michael@0 134 mRenderer = new LayerRenderer(this);
michael@0 135 mInputConnectionHandler = null;
michael@0 136
michael@0 137 setFocusable(true);
michael@0 138 setFocusableInTouchMode(true);
michael@0 139
michael@0 140 GeckoAccessibility.setDelegate(this);
michael@0 141 }
michael@0 142
michael@0 143 private Point getEventRadius(MotionEvent event) {
michael@0 144 if (Build.VERSION.SDK_INT >= 9) {
michael@0 145 return new Point((int)event.getToolMajor()/2,
michael@0 146 (int)event.getToolMinor()/2);
michael@0 147 }
michael@0 148
michael@0 149 float size = event.getSize();
michael@0 150 DisplayMetrics displaymetrics = getContext().getResources().getDisplayMetrics();
michael@0 151 size = size * Math.min(displaymetrics.heightPixels, displaymetrics.widthPixels);
michael@0 152 return new Point((int)size, (int)size);
michael@0 153 }
michael@0 154
michael@0 155 public void geckoConnected() {
michael@0 156 // See if we want to force 16-bit colour before doing anything
michael@0 157 PrefsHelper.getPref("gfx.android.rgb16.force", new PrefsHelper.PrefHandlerBase() {
michael@0 158 @Override public void prefValue(String pref, boolean force16bit) {
michael@0 159 if (force16bit) {
michael@0 160 GeckoAppShell.setScreenDepthOverride(16);
michael@0 161 }
michael@0 162 }
michael@0 163 });
michael@0 164
michael@0 165 mLayerClient.notifyGeckoReady();
michael@0 166 addTouchInterceptor(new TouchEventInterceptor() {
michael@0 167 private PointF mInitialTouchPoint = null;
michael@0 168
michael@0 169 @Override
michael@0 170 public boolean onInterceptTouchEvent(View view, MotionEvent event) {
michael@0 171 return false;
michael@0 172 }
michael@0 173
michael@0 174 @Override
michael@0 175 public boolean onTouch(View view, MotionEvent event) {
michael@0 176 if (event == null) {
michael@0 177 return true;
michael@0 178 }
michael@0 179
michael@0 180 int action = event.getActionMasked();
michael@0 181 PointF point = new PointF(event.getX(), event.getY());
michael@0 182 if (action == MotionEvent.ACTION_DOWN) {
michael@0 183 mInitialTouchPoint = point;
michael@0 184 }
michael@0 185
michael@0 186 if (mInitialTouchPoint != null && action == MotionEvent.ACTION_MOVE) {
michael@0 187 Point p = getEventRadius(event);
michael@0 188
michael@0 189 if (PointUtils.subtract(point, mInitialTouchPoint).length() <
michael@0 190 Math.max(PanZoomController.CLICK_THRESHOLD, Math.min(Math.min(p.x, p.y), PanZoomController.PAN_THRESHOLD))) {
michael@0 191 // Don't send the touchmove event if if the users finger hasn't moved far.
michael@0 192 // Necessary for Google Maps to work correctly. See bug 771099.
michael@0 193 return true;
michael@0 194 } else {
michael@0 195 mInitialTouchPoint = null;
michael@0 196 }
michael@0 197 }
michael@0 198
michael@0 199 GeckoAppShell.sendEventToGecko(GeckoEvent.createMotionEvent(event, false));
michael@0 200 return true;
michael@0 201 }
michael@0 202 });
michael@0 203 }
michael@0 204
michael@0 205 public void showSurface() {
michael@0 206 // Fix this if TextureView support is turned back on above
michael@0 207 mSurfaceView.setVisibility(View.VISIBLE);
michael@0 208 }
michael@0 209
michael@0 210 public void hideSurface() {
michael@0 211 // Fix this if TextureView support is turned back on above
michael@0 212 mSurfaceView.setVisibility(View.INVISIBLE);
michael@0 213 }
michael@0 214
michael@0 215 public void destroy() {
michael@0 216 if (mLayerClient != null) {
michael@0 217 mLayerClient.destroy();
michael@0 218 }
michael@0 219 if (mRenderer != null) {
michael@0 220 mRenderer.destroy();
michael@0 221 }
michael@0 222 Tabs.unregisterOnTabsChangedListener(this);
michael@0 223 }
michael@0 224
michael@0 225 public void addTouchInterceptor(final TouchEventInterceptor aTouchInterceptor) {
michael@0 226 post(new Runnable() {
michael@0 227 @Override
michael@0 228 public void run() {
michael@0 229 mTouchInterceptors.add(aTouchInterceptor);
michael@0 230 }
michael@0 231 });
michael@0 232 }
michael@0 233
michael@0 234 public void removeTouchInterceptor(final TouchEventInterceptor aTouchInterceptor) {
michael@0 235 post(new Runnable() {
michael@0 236 @Override
michael@0 237 public void run() {
michael@0 238 mTouchInterceptors.remove(aTouchInterceptor);
michael@0 239 }
michael@0 240 });
michael@0 241 }
michael@0 242
michael@0 243 private boolean runTouchInterceptors(MotionEvent event, boolean aOnTouch) {
michael@0 244 boolean result = false;
michael@0 245 for (TouchEventInterceptor i : mTouchInterceptors) {
michael@0 246 if (aOnTouch) {
michael@0 247 result |= i.onTouch(this, event);
michael@0 248 } else {
michael@0 249 result |= i.onInterceptTouchEvent(this, event);
michael@0 250 }
michael@0 251 }
michael@0 252
michael@0 253 return result;
michael@0 254 }
michael@0 255
michael@0 256 @Override
michael@0 257 public void dispatchDraw(final Canvas canvas) {
michael@0 258 super.dispatchDraw(canvas);
michael@0 259
michael@0 260 // We must have a layer client to get valid viewport metrics
michael@0 261 if (mLayerClient != null && mOverscroll != null) {
michael@0 262 mOverscroll.draw(canvas, getViewportMetrics());
michael@0 263 }
michael@0 264 }
michael@0 265
michael@0 266 @Override
michael@0 267 public boolean onTouchEvent(MotionEvent event) {
michael@0 268 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
michael@0 269 requestFocus();
michael@0 270 }
michael@0 271
michael@0 272 if (runTouchInterceptors(event, false)) {
michael@0 273 return true;
michael@0 274 }
michael@0 275 if (mPanZoomController != null && mPanZoomController.onTouchEvent(event)) {
michael@0 276 return true;
michael@0 277 }
michael@0 278 if (runTouchInterceptors(event, true)) {
michael@0 279 return true;
michael@0 280 }
michael@0 281 return false;
michael@0 282 }
michael@0 283
michael@0 284 @Override
michael@0 285 public boolean onHoverEvent(MotionEvent event) {
michael@0 286 if (runTouchInterceptors(event, true)) {
michael@0 287 return true;
michael@0 288 }
michael@0 289 return false;
michael@0 290 }
michael@0 291
michael@0 292 @Override
michael@0 293 public boolean onGenericMotionEvent(MotionEvent event) {
michael@0 294 if (mPanZoomController != null && mPanZoomController.onMotionEvent(event)) {
michael@0 295 return true;
michael@0 296 }
michael@0 297 return false;
michael@0 298 }
michael@0 299
michael@0 300 @Override
michael@0 301 protected void onAttachedToWindow() {
michael@0 302 // This check should not be done before the view is attached to a window
michael@0 303 // as hardware acceleration will not be enabled at that point.
michael@0 304 // We must create and add the SurfaceView instance before the view tree
michael@0 305 // is fully created to avoid flickering (see bug 801477).
michael@0 306 if (shouldUseTextureView()) {
michael@0 307 mTextureView = new TextureView(getContext());
michael@0 308 mTextureView.setSurfaceTextureListener(new SurfaceTextureListener());
michael@0 309
michael@0 310 // The background is set to this color when the LayerView is
michael@0 311 // created, and it will be shown immediately at startup. Shortly
michael@0 312 // after, the tab's background color will be used before any content
michael@0 313 // is shown.
michael@0 314 mTextureView.setBackgroundColor(Color.WHITE);
michael@0 315 addView(mTextureView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
michael@0 316 } else {
michael@0 317 // This will stop PropertyAnimator from creating a drawing cache (i.e. a bitmap)
michael@0 318 // from a SurfaceView, which is just not possible (the bitmap will be transparent).
michael@0 319 setWillNotCacheDrawing(false);
michael@0 320
michael@0 321 mSurfaceView = new LayerSurfaceView(getContext(), this);
michael@0 322 mSurfaceView.setBackgroundColor(Color.WHITE);
michael@0 323 addView(mSurfaceView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
michael@0 324
michael@0 325 SurfaceHolder holder = mSurfaceView.getHolder();
michael@0 326 holder.addCallback(new SurfaceListener());
michael@0 327 }
michael@0 328 }
michael@0 329
michael@0 330 // Don't expose GeckoLayerClient to things outside this package; only expose it as an Object
michael@0 331 GeckoLayerClient getLayerClient() { return mLayerClient; }
michael@0 332 public Object getLayerClientObject() { return mLayerClient; }
michael@0 333
michael@0 334 public PanZoomController getPanZoomController() { return mPanZoomController; }
michael@0 335 public LayerMarginsAnimator getLayerMarginsAnimator() { return mMarginsAnimator; }
michael@0 336
michael@0 337 public ImmutableViewportMetrics getViewportMetrics() {
michael@0 338 return mLayerClient.getViewportMetrics();
michael@0 339 }
michael@0 340
michael@0 341 public void abortPanning() {
michael@0 342 if (mPanZoomController != null) {
michael@0 343 mPanZoomController.abortPanning();
michael@0 344 }
michael@0 345 }
michael@0 346
michael@0 347 public PointF convertViewPointToLayerPoint(PointF viewPoint) {
michael@0 348 return mLayerClient.convertViewPointToLayerPoint(viewPoint);
michael@0 349 }
michael@0 350
michael@0 351 int getBackgroundColor() {
michael@0 352 return mBackgroundColor;
michael@0 353 }
michael@0 354
michael@0 355 @Override
michael@0 356 public void setBackgroundColor(int newColor) {
michael@0 357 mBackgroundColor = newColor;
michael@0 358 requestRender();
michael@0 359 }
michael@0 360
michael@0 361 public void setZoomConstraints(ZoomConstraints constraints) {
michael@0 362 mLayerClient.setZoomConstraints(constraints);
michael@0 363 }
michael@0 364
michael@0 365 public void setIsRTL(boolean aIsRTL) {
michael@0 366 mLayerClient.setIsRTL(aIsRTL);
michael@0 367 }
michael@0 368
michael@0 369 public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler) {
michael@0 370 mInputConnectionHandler = inputConnectionHandler;
michael@0 371 mLayerClient.forceRedraw(null);
michael@0 372 }
michael@0 373
michael@0 374 @Override
michael@0 375 public Handler getHandler() {
michael@0 376 if (mInputConnectionHandler != null)
michael@0 377 return mInputConnectionHandler.getHandler(super.getHandler());
michael@0 378 return super.getHandler();
michael@0 379 }
michael@0 380
michael@0 381 @Override
michael@0 382 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
michael@0 383 if (mInputConnectionHandler != null)
michael@0 384 return mInputConnectionHandler.onCreateInputConnection(outAttrs);
michael@0 385 return null;
michael@0 386 }
michael@0 387
michael@0 388 @Override
michael@0 389 public boolean onKeyPreIme(int keyCode, KeyEvent event) {
michael@0 390 if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyPreIme(keyCode, event)) {
michael@0 391 return true;
michael@0 392 }
michael@0 393 return false;
michael@0 394 }
michael@0 395
michael@0 396 @Override
michael@0 397 public boolean onKeyDown(int keyCode, KeyEvent event) {
michael@0 398 if (mPanZoomController != null && mPanZoomController.onKeyEvent(event)) {
michael@0 399 return true;
michael@0 400 }
michael@0 401 if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyDown(keyCode, event)) {
michael@0 402 return true;
michael@0 403 }
michael@0 404 return false;
michael@0 405 }
michael@0 406
michael@0 407 @Override
michael@0 408 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
michael@0 409 if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyLongPress(keyCode, event)) {
michael@0 410 return true;
michael@0 411 }
michael@0 412 return false;
michael@0 413 }
michael@0 414
michael@0 415 @Override
michael@0 416 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
michael@0 417 if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyMultiple(keyCode, repeatCount, event)) {
michael@0 418 return true;
michael@0 419 }
michael@0 420 return false;
michael@0 421 }
michael@0 422
michael@0 423 @Override
michael@0 424 public boolean onKeyUp(int keyCode, KeyEvent event) {
michael@0 425 if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyUp(keyCode, event)) {
michael@0 426 return true;
michael@0 427 }
michael@0 428 return false;
michael@0 429 }
michael@0 430
michael@0 431 public boolean isIMEEnabled() {
michael@0 432 if (mInputConnectionHandler != null) {
michael@0 433 return mInputConnectionHandler.isIMEEnabled();
michael@0 434 }
michael@0 435 return false;
michael@0 436 }
michael@0 437
michael@0 438 public void requestRender() {
michael@0 439 if (mListener != null) {
michael@0 440 mListener.renderRequested();
michael@0 441 }
michael@0 442 }
michael@0 443
michael@0 444 public void addLayer(Layer layer) {
michael@0 445 mRenderer.addLayer(layer);
michael@0 446 }
michael@0 447
michael@0 448 public void removeLayer(Layer layer) {
michael@0 449 mRenderer.removeLayer(layer);
michael@0 450 }
michael@0 451
michael@0 452 public void postRenderTask(RenderTask task) {
michael@0 453 mRenderer.postRenderTask(task);
michael@0 454 }
michael@0 455
michael@0 456 public void removeRenderTask(RenderTask task) {
michael@0 457 mRenderer.removeRenderTask(task);
michael@0 458 }
michael@0 459
michael@0 460 public int getMaxTextureSize() {
michael@0 461 return mRenderer.getMaxTextureSize();
michael@0 462 }
michael@0 463
michael@0 464 /** Used by robocop for testing purposes. Not for production use! */
michael@0 465 @RobocopTarget
michael@0 466 public IntBuffer getPixels() {
michael@0 467 return mRenderer.getPixels();
michael@0 468 }
michael@0 469
michael@0 470 /* paintState must be a PAINT_xxx constant. */
michael@0 471 public void setPaintState(int paintState) {
michael@0 472 mPaintState = paintState;
michael@0 473 }
michael@0 474
michael@0 475 public int getPaintState() {
michael@0 476 return mPaintState;
michael@0 477 }
michael@0 478
michael@0 479 public LayerRenderer getRenderer() {
michael@0 480 return mRenderer;
michael@0 481 }
michael@0 482
michael@0 483 public void setListener(Listener listener) {
michael@0 484 mListener = listener;
michael@0 485 }
michael@0 486
michael@0 487 Listener getListener() {
michael@0 488 return mListener;
michael@0 489 }
michael@0 490
michael@0 491 public GLController getGLController() {
michael@0 492 return mGLController;
michael@0 493 }
michael@0 494
michael@0 495 private Bitmap getDrawable(String name) {
michael@0 496 BitmapFactory.Options options = new BitmapFactory.Options();
michael@0 497 options.inScaled = false;
michael@0 498 Context context = getContext();
michael@0 499 int resId = context.getResources().getIdentifier(name, "drawable", context.getPackageName());
michael@0 500 return BitmapUtils.decodeResource(context, resId, options);
michael@0 501 }
michael@0 502
michael@0 503 Bitmap getScrollbarImage() {
michael@0 504 return getDrawable("scrollbar");
michael@0 505 }
michael@0 506
michael@0 507 /* When using a SurfaceView (mSurfaceView != null), resizing happens in two
michael@0 508 * phases. First, the LayerView changes size, then, often some frames later,
michael@0 509 * the SurfaceView changes size. Because of this, we need to split the
michael@0 510 * resize into two phases to avoid jittering.
michael@0 511 *
michael@0 512 * The first phase is the LayerView size change. mListener is notified so
michael@0 513 * that a synchronous draw can be performed (otherwise a blank frame will
michael@0 514 * appear).
michael@0 515 *
michael@0 516 * The second phase is the SurfaceView size change. At this point, the
michael@0 517 * backing GL surface is resized and another synchronous draw is performed.
michael@0 518 * Gecko is also sent the new window size, and this will likely cause an
michael@0 519 * extra draw a few frames later, after it's re-rendered and caught up.
michael@0 520 *
michael@0 521 * In the case that there is no valid GL surface (for example, when
michael@0 522 * resuming, or when coming back from the awesomescreen), or we're using a
michael@0 523 * TextureView instead of a SurfaceView, the first phase is skipped.
michael@0 524 */
michael@0 525 private void onSizeChanged(int width, int height) {
michael@0 526 if (!mGLController.isCompositorCreated()) {
michael@0 527 return;
michael@0 528 }
michael@0 529
michael@0 530 surfaceChanged(width, height);
michael@0 531
michael@0 532 if (mSurfaceView == null) {
michael@0 533 return;
michael@0 534 }
michael@0 535
michael@0 536 if (mListener != null) {
michael@0 537 mListener.sizeChanged(width, height);
michael@0 538 }
michael@0 539
michael@0 540 if (mOverscroll != null) {
michael@0 541 mOverscroll.setSize(width, height);
michael@0 542 }
michael@0 543 }
michael@0 544
michael@0 545 private void surfaceChanged(int width, int height) {
michael@0 546 mGLController.serverSurfaceChanged(width, height);
michael@0 547
michael@0 548 if (mListener != null) {
michael@0 549 mListener.surfaceChanged(width, height);
michael@0 550 }
michael@0 551
michael@0 552 if (mOverscroll != null) {
michael@0 553 mOverscroll.setSize(width, height);
michael@0 554 }
michael@0 555 }
michael@0 556
michael@0 557 private void onDestroyed() {
michael@0 558 mGLController.serverSurfaceDestroyed();
michael@0 559 }
michael@0 560
michael@0 561 public Object getNativeWindow() {
michael@0 562 if (mSurfaceView != null)
michael@0 563 return mSurfaceView.getHolder();
michael@0 564
michael@0 565 return mTextureView.getSurfaceTexture();
michael@0 566 }
michael@0 567
michael@0 568 @WrapElementForJNI(allowMultithread = true, stubName = "RegisterCompositorWrapper")
michael@0 569 public static GLController registerCxxCompositor() {
michael@0 570 try {
michael@0 571 LayerView layerView = GeckoAppShell.getLayerView();
michael@0 572 GLController controller = layerView.getGLController();
michael@0 573 controller.compositorCreated();
michael@0 574 return controller;
michael@0 575 } catch (Exception e) {
michael@0 576 Log.e(LOGTAG, "Error registering compositor!", e);
michael@0 577 return null;
michael@0 578 }
michael@0 579 }
michael@0 580
michael@0 581 public interface Listener {
michael@0 582 void renderRequested();
michael@0 583 void sizeChanged(int width, int height);
michael@0 584 void surfaceChanged(int width, int height);
michael@0 585 }
michael@0 586
michael@0 587 private class SurfaceListener implements SurfaceHolder.Callback {
michael@0 588 @Override
michael@0 589 public void surfaceChanged(SurfaceHolder holder, int format, int width,
michael@0 590 int height) {
michael@0 591 onSizeChanged(width, height);
michael@0 592 }
michael@0 593
michael@0 594 @Override
michael@0 595 public void surfaceCreated(SurfaceHolder holder) {
michael@0 596 }
michael@0 597
michael@0 598 @Override
michael@0 599 public void surfaceDestroyed(SurfaceHolder holder) {
michael@0 600 onDestroyed();
michael@0 601 }
michael@0 602 }
michael@0 603
michael@0 604 /* A subclass of SurfaceView to listen to layout changes, as
michael@0 605 * View.OnLayoutChangeListener requires API level 11.
michael@0 606 */
michael@0 607 private class LayerSurfaceView extends SurfaceView {
michael@0 608 LayerView mParent;
michael@0 609
michael@0 610 public LayerSurfaceView(Context aContext, LayerView aParent) {
michael@0 611 super(aContext);
michael@0 612 mParent = aParent;
michael@0 613 }
michael@0 614
michael@0 615 @Override
michael@0 616 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
michael@0 617 if (changed) {
michael@0 618 mParent.surfaceChanged(right - left, bottom - top);
michael@0 619 }
michael@0 620 }
michael@0 621 }
michael@0 622
michael@0 623 private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
michael@0 624 @Override
michael@0 625 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
michael@0 626 // We don't do this for surfaceCreated above because it is always followed by a surfaceChanged,
michael@0 627 // but that is not the case here.
michael@0 628 onSizeChanged(width, height);
michael@0 629 }
michael@0 630
michael@0 631 @Override
michael@0 632 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
michael@0 633 onDestroyed();
michael@0 634 return true; // allow Android to call release() on the SurfaceTexture, we are done drawing to it
michael@0 635 }
michael@0 636
michael@0 637 @Override
michael@0 638 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
michael@0 639 onSizeChanged(width, height);
michael@0 640 }
michael@0 641
michael@0 642 @Override
michael@0 643 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
michael@0 644
michael@0 645 }
michael@0 646 }
michael@0 647
michael@0 648 @RobocopTarget
michael@0 649 public void addDrawListener(DrawListener listener) {
michael@0 650 mLayerClient.addDrawListener(listener);
michael@0 651 }
michael@0 652
michael@0 653 @RobocopTarget
michael@0 654 public void removeDrawListener(DrawListener listener) {
michael@0 655 mLayerClient.removeDrawListener(listener);
michael@0 656 }
michael@0 657
michael@0 658 @RobocopTarget
michael@0 659 public static interface DrawListener {
michael@0 660 public void drawFinished();
michael@0 661 }
michael@0 662
michael@0 663 @Override
michael@0 664 public void setOverScrollMode(int overscrollMode) {
michael@0 665 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
michael@0 666 super.setOverScrollMode(overscrollMode);
michael@0 667 }
michael@0 668 if (mPanZoomController != null) {
michael@0 669 mPanZoomController.setOverScrollMode(overscrollMode);
michael@0 670 }
michael@0 671 }
michael@0 672
michael@0 673 @Override
michael@0 674 public int getOverScrollMode() {
michael@0 675 if (mPanZoomController != null) {
michael@0 676 return mPanZoomController.getOverScrollMode();
michael@0 677 }
michael@0 678
michael@0 679 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
michael@0 680 return super.getOverScrollMode();
michael@0 681 }
michael@0 682 return View.OVER_SCROLL_ALWAYS;
michael@0 683 }
michael@0 684
michael@0 685 @Override
michael@0 686 public void onFocusChanged (boolean gainFocus, int direction, Rect previouslyFocusedRect) {
michael@0 687 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
michael@0 688 GeckoAccessibility.onLayerViewFocusChanged(this, gainFocus);
michael@0 689 }
michael@0 690
michael@0 691 public void setFullScreen(boolean fullScreen) {
michael@0 692 mFullScreen = fullScreen;
michael@0 693 }
michael@0 694
michael@0 695 public boolean isFullScreen() {
michael@0 696 return mFullScreen;
michael@0 697 }
michael@0 698
michael@0 699 @Override
michael@0 700 public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
michael@0 701 if (msg == Tabs.TabEvents.VIEWPORT_CHANGE && Tabs.getInstance().isSelectedTab(tab) && mLayerClient != null) {
michael@0 702 setZoomConstraints(tab.getZoomConstraints());
michael@0 703 setIsRTL(tab.getIsRTL());
michael@0 704 }
michael@0 705 }
michael@0 706
michael@0 707 // Public hooks for listening to metrics changing
michael@0 708
michael@0 709 public interface OnMetricsChangedListener {
michael@0 710 public void onMetricsChanged(ImmutableViewportMetrics viewport);
michael@0 711 public void onPanZoomStopped();
michael@0 712 }
michael@0 713
michael@0 714 public void setOnMetricsChangedListener(OnMetricsChangedListener listener) {
michael@0 715 mLayerClient.setOnMetricsChangedListener(listener);
michael@0 716 }
michael@0 717 }

mercurial