--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
@@ -39,18 +39,16 @@ class GeckoLayerClient implements LayerV
* 1) reading mViewportMetrics from any thread is fine without synchronization
* 2) writing to mViewportMetrics requires synchronizing on the layer controller object
* 3) whenever reading multiple fields from mViewportMetrics without synchronization (i.e. in
* case 1 above) you should always first grab a local copy of the reference, and then use
* that because mViewportMetrics might get reassigned in between reading the different
* fields. */
private volatile ImmutableViewportMetrics mViewportMetrics;
- private volatile boolean mGeckoIsReady;
-
private final PanZoomController mPanZoomController;
private final DynamicToolbarAnimator mToolbarAnimator;
private final LayerView mView;
/* This flag is true from the time that browser.js detects a first-paint is about to start,
* to the time that we receive the first-paint composite notification from the compositor.
* Note that there is a small race condition with this; if there are two paints that both
* have the first-paint flag set, and the second paint happens concurrently with the
@@ -76,47 +74,18 @@ class GeckoLayerClient implements LayerV
mView.setListener(this);
mContentDocumentIsDisplayed = true;
}
public void setOverscrollHandler(final Overscroll listener) {
mPanZoomController.setOverscrollHandler(listener);
}
- public void setGeckoReady(boolean ready) {
- mGeckoIsReady = ready;
- }
-
- public boolean isGeckoReady() {
- return mGeckoIsReady;
- }
-
- /** Attaches to root layer so that Gecko appears. */
- @WrapForJNI(calledFrom = "gecko")
- private void onGeckoReady() {
- mGeckoIsReady = true;
-
- sendResizeEventIfNecessary(true);
-
- // Gecko being ready is one of the two conditions (along with having an available
- // surface) that cause us to create the compositor. So here, now that we know gecko
- // is ready, call updateCompositor() to see if we can actually do the creation.
- // This needs to run on the UI thread so that the surface validity can't change on
- // us while we're in the middle of creating the compositor.
- mView.post(new Runnable() {
- @Override
- public void run() {
- getView().updateCompositor();
- }
- });
- }
-
public void destroy() {
mPanZoomController.destroy();
- mGeckoIsReady = false;
}
public LayerView getView() {
return mView;
}
public FloatSize getViewportSize() {
return mViewportMetrics.getSize();
@@ -132,22 +101,17 @@ class GeckoLayerClient implements LayerV
*/
boolean setViewportSize(int width, int height) {
if (mViewportMetrics.viewportRectWidth == width &&
mViewportMetrics.viewportRectHeight == height) {
return false;
}
mViewportMetrics = mViewportMetrics.setViewportSize(width, height);
- if (mGeckoIsReady) {
- // here we send gecko a resize message. The code in browser.js is responsible for
- // picking up on that resize event, modifying the viewport as necessary, and informing
- // us of the new viewport.
- sendResizeEventIfNecessary(true);
-
+ if (mView.isCompositorReady()) {
// the following call also sends gecko a message, which will be processed after the resize
// message above has updated the viewport. this message ensures that if we have just put
// focus in a text field, we scroll the content so that the text field is in view.
final boolean imeIsEnabled = mView.isIMEEnabled();
if (imeIsEnabled && !mImeWasEnabledOnLastResize) {
// The IME just came up after not being up, so let's scroll
// to the focused input.
EventDispatcher.getInstance().dispatch("ScrollTo:FocusedInput", null);
@@ -160,38 +124,16 @@ class GeckoLayerClient implements LayerV
PanZoomController getPanZoomController() {
return mPanZoomController;
}
DynamicToolbarAnimator getDynamicToolbarAnimator() {
return mToolbarAnimator;
}
- /* Informs Gecko that the screen size has changed. */
- private void sendResizeEventIfNecessary(boolean force) {
- IntSize newWindowSize = new IntSize(mViewportMetrics.viewportRectWidth,
- mViewportMetrics.viewportRectHeight);
-
- boolean windowSizeChanged = !mWindowSize.equals(newWindowSize);
-
- if (!force && !windowSizeChanged) {
- return;
- }
-
- mWindowSize = newWindowSize;
-
- if (windowSizeChanged) {
- Log.d(LOGTAG, "Window-size changed to " + mWindowSize);
- }
-
- if (mView != null) {
- mView.notifySizeChanged(mWindowSize.width, mWindowSize.height);
- }
- }
-
@WrapForJNI(calledFrom = "gecko")
void contentDocumentChanged() {
mContentDocumentIsDisplayed = false;
}
@WrapForJNI(calledFrom = "gecko")
boolean isContentDocumentDisplayed() {
return mContentDocumentIsDisplayed;
@@ -206,17 +148,17 @@ class GeckoLayerClient implements LayerV
public void updateRootFrameMetrics(float scrollX, float scrollY, float zoom) {
mViewportMetrics = mViewportMetrics.setViewportOrigin(scrollX, scrollY)
.setZoomFactor(zoom);
mToolbarAnimator.onMetricsChanged(mViewportMetrics);
mContentDocumentIsDisplayed = true;
}
- class PointerInfo {
+ private static class PointerInfo {
// We reserve one pointer ID for the mouse, so that tests don't have
// to worry about tracking pointer IDs if they just want to test mouse
// event synthesization. If somebody tries to use this ID for a
// synthesized touch event we'll throw an exception.
public static final int RESERVED_MOUSE_POINTER_ID = 100000;
public int pointerId;
public int source;
@@ -230,17 +172,17 @@ class GeckoLayerClient implements LayerV
coords.orientation = orientation;
coords.pressure = (float)pressure;
coords.x = screenX;
coords.y = screenY;
return coords;
}
}
- class SynthesizedEventState {
+ private static class SynthesizedEventState {
public final ArrayList<PointerInfo> pointers;
public long downTime;
SynthesizedEventState() {
pointers = new ArrayList<PointerInfo>();
}
int getPointerIndex(int pointerId) {
@@ -304,16 +246,21 @@ class GeckoLayerClient implements LayerV
}
private void synthesizeNativePointer(int source, int pointerId,
int eventType, int screenX, int screenY, double pressure,
int orientation)
{
Log.d(LOGTAG, "Synthesizing pointer from " + source + " id " + pointerId + " at " + screenX + ", " + screenY);
+ final int[] origin = new int[2];
+ mView.getLocationOnScreen(origin);
+ screenX -= origin[0];
+ screenY -= origin[1];
+
if (mPointerState == null) {
mPointerState = new SynthesizedEventState();
}
// Find the pointer if it already exists
int pointerIndex = mPointerState.getPointerIndex(pointerId);
// Event-specific handling
@@ -361,19 +308,16 @@ class GeckoLayerClient implements LayerV
}
break;
}
// Update the pointer with the new info
PointerInfo info = mPointerState.pointers.get(pointerIndex);
info.screenX = screenX;
info.screenY = screenY;
- if (mView != null) {
- info.screenY += mView.getCurrentToolbarHeight();
- }
info.pressure = pressure;
info.orientation = orientation;
// Dispatch the event
int action = 0;
if (eventType == MotionEvent.ACTION_POINTER_DOWN ||
eventType == MotionEvent.ACTION_POINTER_UP) {
// for pointer-down and pointer-up events we need to add the
@@ -440,17 +384,17 @@ class GeckoLayerClient implements LayerV
setViewportSize(viewportSize.width, viewportSize.height);
}
ImmutableViewportMetrics getViewportMetrics() {
return mViewportMetrics;
}
Matrix getMatrixForLayerRectToViewRect() {
- if (!mGeckoIsReady) {
+ if (!mView.isCompositorReady()) {
return null;
}
ImmutableViewportMetrics viewportMetrics = mViewportMetrics;
PointF origin = viewportMetrics.getOrigin();
float zoom = viewportMetrics.zoomFactor;
ImmutableViewportMetrics geckoViewport = mViewportMetrics;
PointF geckoOrigin = geckoViewport.getOrigin();
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java
@@ -49,35 +49,25 @@ public class LayerView extends FrameLayo
private static AccessibilityManager sAccessibilityManager;
private GeckoLayerClient mLayerClient;
private PanZoomController mPanZoomController;
private DynamicToolbarAnimator mToolbarAnimator;
private FullScreenState mFullScreenState;
- private SurfaceView mSurfaceView;
- private TextureView mTextureView;
-
private Listener mListener;
/* This should only be modified on the Java UI thread. */
private final Overscroll mOverscroll;
- private boolean mServerSurfaceValid;
- private int mWidth, mHeight;
-
private int mDefaultClearColor = Color.WHITE;
/* package */ GetPixelsResult mGetPixelsResult;
private final List<DrawListener> mDrawListeners;
- /* This is written by the Gecko thread and the UI thread, and read by the UI thread. */
- /* package */ volatile boolean mCompositorCreated;
- /* package */ volatile boolean mCompositorControllerOpen;
-
//
// NOTE: These values are also defined in gfx/layers/ipc/UiCompositorControllerMessageTypes.h
// and must be kept in sync. Any new AnimatorMessageType added here must also be added there.
//
/* package */ final static int STATIC_TOOLBAR_NEEDS_UPDATE = 0; // Sent from compositor when the static toolbar wants to hide.
/* package */ final static int STATIC_TOOLBAR_READY = 1; // Sent from compositor when the static toolbar image has been updated and is ready to animate.
/* package */ final static int TOOLBAR_HIDDEN = 2; // Sent to compositor when the real toolbar has been hidden.
/* package */ final static int TOOLBAR_VISIBLE = 3; // Sent to compositor when the real toolbar is visible.
@@ -85,127 +75,29 @@ public class LayerView extends FrameLayo
/* package */ final static int FIRST_PAINT = 5; // Sent from compositor after first paint
/* package */ final static int REQUEST_SHOW_TOOLBAR_IMMEDIATELY = 6; // Sent to compositor requesting toolbar be shown immediately
/* package */ final static int REQUEST_SHOW_TOOLBAR_ANIMATED = 7; // Sent to compositor requesting toolbar be shown animated
/* package */ final static int REQUEST_HIDE_TOOLBAR_IMMEDIATELY = 8; // Sent to compositor requesting toolbar be hidden immediately
/* package */ final static int REQUEST_HIDE_TOOLBAR_ANIMATED = 9; // Sent to compositor requesting toolbar be hidden animated
/* package */ final static int LAYERS_UPDATED = 10; // Sent from compositor when a layer has been updated
/* package */ final static int TOOLBAR_SNAPSHOT_FAILED = 11; // Sent to compositor when the toolbar snapshot fails.
/* package */ final static int COMPOSITOR_CONTROLLER_OPEN = 20; // Special message sent from UiCompositorControllerChild once it is open
- /* package */ final static int IS_COMPOSITOR_CONTROLLER_OPEN = 21; // Special message sent from controller to query if the compositor controller is open
private void postCompositorMessage(final int message) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
mCompositor.sendToolbarAnimatorMessage(message);
}
});
}
- @WrapForJNI(calledFrom = "ui")
/* package */ boolean isCompositorReady() {
ThreadUtils.assertOnUiThread();
- return mCompositorCreated && mCompositorControllerOpen;
- }
-
- /* package */ class Compositor extends JNIObject {
- public Compositor() {
- }
-
- /* package */ boolean isReady() {
- return isCompositorReady();
- }
- @WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
- @Override protected native void disposeNative();
-
- // Gecko thread sets its Java instances; does not block UI thread.
- @WrapForJNI(calledFrom = "any", dispatchTo = "gecko")
- /* package */ native void attachToJava(GeckoLayerClient layerClient,
- NativePanZoomController npzc);
-
- @WrapForJNI(calledFrom = "any", dispatchTo = "gecko")
- /* package */ native void onSizeChanged(int windowWidth, int windowHeight);
-
- // Gecko thread creates compositor; blocks UI thread.
- @WrapForJNI(calledFrom = "ui", dispatchTo = "proxy")
- /* package */ native void createCompositor(int width, int height, Object surface);
-
- // Gecko thread pauses compositor; blocks UI thread.
- @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
- /* package */ native void syncPauseCompositor();
-
- // UI thread resumes compositor and notifies Gecko thread; does not block UI thread.
- @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
- /* package */ native void syncResumeResizeCompositor(int width, int height, Object surface);
-
- @WrapForJNI(calledFrom = "any", dispatchTo = "current")
- /* package */ native void syncInvalidateAndScheduleComposite();
-
- @WrapForJNI(calledFrom = "any", dispatchTo = "current")
- /* package */ native void setMaxToolbarHeight(int height);
-
- @WrapForJNI(calledFrom = "any", dispatchTo = "current")
- /* package */ native void setPinned(boolean pinned, int reason);
-
- @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
- /* package */ native void sendToolbarAnimatorMessage(int message);
-
- @WrapForJNI(calledFrom = "ui")
- /* package */ void recvToolbarAnimatorMessage(int message) {
- handleToolbarAnimatorMessage(message);
- }
-
- @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
- /* package */ native void setDefaultClearColor(int color);
-
- @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
- /* package */ native void requestScreenPixels();
-
- @WrapForJNI(calledFrom = "ui")
- /* package */ void recvScreenPixels(int width, int height, int[] pixels) {
- if (mGetPixelsResult != null) {
- mGetPixelsResult.onPixelsResult(width, height, IntBuffer.wrap(pixels));
- mGetPixelsResult = null;
- }
- }
-
- @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
- /* package */ native void enableLayerUpdateNotifications(boolean enable);
-
- @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
- /* package */ native void sendToolbarPixelsToCompositor(final int width, final int height, final int[] pixels);
-
- @WrapForJNI(calledFrom = "gecko")
- private void reattach() {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- updateCompositor();
- }
- });
- }
-
- @WrapForJNI(calledFrom = "gecko")
- private void destroy() {
- // The nsWindow has been closed. First mark our compositor as destroyed.
- LayerView.this.mCompositorCreated = false;
- LayerView.this.mCompositorControllerOpen = false;
-
- LayerView.this.mLayerClient.setGeckoReady(false);
-
- // Then clear out any pending calls on the UI thread by disposing on the UI thread.
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- LayerView.this.mDrawListeners.clear();
- disposeNative();
- }
- });
- }
+ return mCompositor != null && mCompositor.isReady();
}
/* package */ void handleToolbarAnimatorMessage(int message) {
switch (message) {
case STATIC_TOOLBAR_NEEDS_UPDATE:
// Send updated toolbar image to compositor.
Bitmap bm = mToolbarAnimator.getBitmapOfToolbarChrome();
if (bm == null) {
@@ -238,62 +130,32 @@ public class LayerView extends FrameLayo
setSurfaceBackgroundColor(Color.TRANSPARENT);
break;
case LAYERS_UPDATED:
for (DrawListener listener : mDrawListeners) {
listener.drawFinished();
}
break;
case COMPOSITOR_CONTROLLER_OPEN:
- // It is possible to get this message multiple times. Only act on it if we didn't know the compositor controller was open
- if (mCompositorControllerOpen) {
- break;
- }
- mCompositorControllerOpen = true;
- // updateCompositor makes a synchronous call to the compositor which will dead lock if called directly from here
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
mCompositor.setDefaultClearColor(mDefaultClearColor);
mCompositor.enableLayerUpdateNotifications(!mDrawListeners.isEmpty());
mToolbarAnimator.updateCompositor();
- updateCompositor();
}
});
break;
default:
Log.e(LOGTAG, "Unhandled Toolbar Animator Message: " + message);
break;
}
}
- private final Compositor mCompositor = new Compositor();
-
- public boolean shouldUseTextureView() {
- // Disable TextureView support for now as it causes panning/zooming
- // performance regressions (see bug 792259). Uncomment the code below
- // once this bug is fixed.
- return false;
-
- /*
- // we can only use TextureView on ICS or higher
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- Log.i(LOGTAG, "Not using TextureView: not on ICS+");
- return false;
- }
-
- try {
- // and then we can only use it if we have a hardware accelerated window
- Method m = View.class.getMethod("isHardwareAccelerated", (Class[]) null);
- return (Boolean) m.invoke(this);
- } catch (Exception e) {
- Log.i(LOGTAG, "Not using TextureView: caught exception checking for hw accel: " + e.toString());
- return false;
- } */
- }
+ private LayerSession.Compositor mCompositor;
public LayerView(Context context, AttributeSet attrs) {
super(context, attrs);
mFullScreenState = FullScreenState.NONE;
mOverscroll = new OverscrollEdgeEffect(this);
mDrawListeners = new ArrayList<DrawListener>();
@@ -306,20 +168,16 @@ public class LayerView extends FrameLayo
public void initializeView() {
mLayerClient = new GeckoLayerClient(this);
if (mOverscroll != null) {
mLayerClient.setOverscrollHandler(mOverscroll);
}
mPanZoomController = mLayerClient.getPanZoomController();
mToolbarAnimator = mLayerClient.getDynamicToolbarAnimator();
- mToolbarAnimator.notifyCompositorCreated(mCompositor);
-
- setFocusable(true);
- setFocusableInTouchMode(true);
}
/**
* MotionEventHelper dragAsync() robocop tests can instruct
* PanZoomController not to generate longpress events.
* This call comes in from a thread other than the UI thread.
* So dispatch to UI thread first to prevent assert in nsWindow.
*/
@@ -332,26 +190,16 @@ public class LayerView extends FrameLayo
});
}
private static Point getEventRadius(MotionEvent event) {
return new Point((int)event.getToolMajor() / 2,
(int)event.getToolMinor() / 2);
}
- public void showSurface() {
- // Fix this if TextureView support is turned back on above
- mSurfaceView.setVisibility(View.VISIBLE);
- }
-
- public void hideSurface() {
- // Fix this if TextureView support is turned back on above
- mSurfaceView.setVisibility(View.INVISIBLE);
- }
-
public void destroy() {
if (mLayerClient != null) {
mLayerClient.destroy();
}
}
@Override
public void dispatchDraw(final Canvas canvas) {
@@ -364,17 +212,17 @@ public class LayerView extends FrameLayo
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
requestFocus();
}
- if (!mLayerClient.isGeckoReady()) {
+ if (!isCompositorReady()) {
// If gecko isn't loaded yet, don't try sending events to the
// native code because it's just going to crash
return true;
}
if (mPanZoomController != null && mPanZoomController.onTouchEvent(event)) {
return true;
}
return false;
@@ -393,109 +241,58 @@ public class LayerView extends FrameLayo
public boolean onHoverEvent(MotionEvent event) {
// If we get a touchscreen hover event, and accessibility is not enabled,
// don't send it to gecko.
if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN &&
!isAccessibilityEnabled()) {
return false;
}
- if (!mLayerClient.isGeckoReady()) {
+ if (!isCompositorReady()) {
// If gecko isn't loaded yet, don't try sending events to the
// native code because it's just going to crash
return true;
} else if (mPanZoomController != null && mPanZoomController.onMotionEvent(event)) {
return true;
}
return false;
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (AndroidGamepadManager.handleMotionEvent(event)) {
return true;
}
- if (!mLayerClient.isGeckoReady()) {
+ if (!isCompositorReady()) {
// If gecko isn't loaded yet, don't try sending events to the
// native code because it's just going to crash
return true;
}
if (mPanZoomController != null && mPanZoomController.onMotionEvent(event)) {
return true;
}
return false;
}
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- // We are adding descendants to this LayerView, but we don't want the
- // descendants to affect the way LayerView retains its focus.
- setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);
-
- // This check should not be done before the view is attached to a window
- // as hardware acceleration will not be enabled at that point.
- // We must create and add the SurfaceView instance before the view tree
- // is fully created to avoid flickering (see bug 801477).
- if (shouldUseTextureView()) {
- mTextureView = new TextureView(getContext());
- mTextureView.setSurfaceTextureListener(new SurfaceTextureListener());
-
- // The background is set to this color when the LayerView is
- // created, and it will be shown immediately at startup. Shortly
- // after, the tab's background color will be used before any content
- // is shown.
- mTextureView.setBackgroundColor(Color.WHITE);
- addView(mTextureView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
- } else {
- // This will stop PropertyAnimator from creating a drawing cache (i.e. a bitmap)
- // from a SurfaceView, which is just not possible (the bitmap will be transparent).
- setWillNotCacheDrawing(false);
-
- mSurfaceView = new LayerSurfaceView(getContext(), this);
- mSurfaceView.setBackgroundColor(Color.WHITE);
- addView(mSurfaceView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
-
- SurfaceHolder holder = mSurfaceView.getHolder();
- holder.addCallback(new SurfaceListener());
- }
-
- attachCompositor();
- }
-
// Don't expose GeckoLayerClient to things outside this package; only expose it as an Object
GeckoLayerClient getLayerClient() { return mLayerClient; }
- /* package */ boolean isGeckoReady() {
- return mLayerClient.isGeckoReady();
- }
-
public PanZoomController getPanZoomController() { return mPanZoomController; }
public DynamicToolbarAnimator getDynamicToolbarAnimator() { return mToolbarAnimator; }
public ImmutableViewportMetrics getViewportMetrics() {
return mLayerClient.getViewportMetrics();
}
public Matrix getMatrixForLayerRectToViewRect() {
return mLayerClient.getMatrixForLayerRectToViewRect();
}
public void setSurfaceBackgroundColor(int newColor) {
- if (mSurfaceView != null) {
- mSurfaceView.setBackgroundColor(newColor);
- }
- }
-
- public void requestRender() {
- if (isCompositorReady()) {
- mCompositor.syncInvalidateAndScheduleComposite();
- }
}
public interface GetPixelsResult {
public void onPixelsResult(int width, int height, IntBuffer pixels);
}
@RobocopTarget
public void getPixels(final GetPixelsResult getPixelsResult) {
@@ -512,236 +309,68 @@ public class LayerView extends FrameLayo
if (isCompositorReady()) {
mGetPixelsResult = getPixelsResult;
mCompositor.requestScreenPixels();
} else {
getPixelsResult.onPixelsResult(0, 0, null);
}
}
+ /* package */ void recvScreenPixels(int width, int height, int[] pixels) {
+ if (mGetPixelsResult != null) {
+ mGetPixelsResult.onPixelsResult(width, height, IntBuffer.wrap(pixels));
+ mGetPixelsResult = null;
+ }
+ }
+
public void setListener(Listener listener) {
mListener = listener;
}
Listener getListener() {
return mListener;
}
- private void attachCompositor() {
+ protected void attachCompositor(final LayerSession session) {
+ mCompositor = session.mCompositor;
+ mCompositor.layerView = this;
+
+ mToolbarAnimator.notifyCompositorCreated(mCompositor);
+
final NativePanZoomController npzc = (NativePanZoomController) mPanZoomController;
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
mCompositor.attachToJava(mLayerClient, npzc);
} else {
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
mCompositor, "attachToJava",
GeckoLayerClient.class, mLayerClient,
NativePanZoomController.class, npzc);
}
}
@WrapForJNI(calledFrom = "ui")
- protected Object getCompositor() {
- return mCompositor;
- }
-
- void serverSurfaceChanged(int newWidth, int newHeight) {
- ThreadUtils.assertOnUiThread();
-
- mWidth = newWidth;
- mHeight = newHeight;
- mServerSurfaceValid = true;
-
- updateCompositor();
+ private Object getCompositor() {
+ return isCompositorReady() ? mCompositor : null;
}
- void updateCompositor() {
- ThreadUtils.assertOnUiThread();
-
- if (isCompositorReady()) {
- // If the compositor has already been created, just resume it instead. We don't need
- // to block here because if the surface is destroyed before the compositor grabs it,
- // we can handle that gracefully (i.e. the compositor will remain paused).
- if (!mServerSurfaceValid) {
- return;
- }
- // Asking Gecko to resume the compositor takes too long (see
- // https://bugzilla.mozilla.org/show_bug.cgi?id=735230#c23), so we
- // resume the compositor directly. We still need to inform Gecko about
- // the compositor resuming, so that Gecko knows that it can now draw.
- // It is important to not notify Gecko until after the compositor has
- // been resumed, otherwise Gecko may send updates that get dropped.
- mCompositor.syncResumeResizeCompositor(mWidth, mHeight, getSurface());
- return;
- }
-
- // Only try to create the compositor if we have a valid surface and gecko is up. When these
- // two conditions are satisfied, we can be relatively sure that the compositor creation will
- // happen without needing to block anywhere.
- if (!mCompositorCreated && mServerSurfaceValid && getLayerClient().isGeckoReady()) {
- mCompositorCreated = true;
- mCompositor.createCompositor(mWidth, mHeight, getSurface());
- }
-
- if (mCompositorCreated && !mCompositorControllerOpen) {
- mCompositor.sendToolbarAnimatorMessage(IS_COMPOSITOR_CONTROLLER_OPEN);
- }
- }
-
- /* When using a SurfaceView (mSurfaceView != null), resizing happens in two
- * phases. First, the LayerView changes size, then, often some frames later,
- * the SurfaceView changes size. Because of this, we need to split the
- * resize into two phases to avoid jittering.
- *
- * The first phase is the LayerView size change. mListener is notified so
- * that a synchronous draw can be performed (otherwise a blank frame will
- * appear).
- *
- * The second phase is the SurfaceView size change. At this point, the
- * backing GL surface is resized and another synchronous draw is performed.
- * Gecko is also sent the new window size, and this will likely cause an
- * extra draw a few frames later, after it's re-rendered and caught up.
- *
- * In the case that there is no valid GL surface (for example, when
- * resuming, or when coming back from the awesomescreen), or we're using a
- * TextureView instead of a SurfaceView, the first phase is skipped.
- */
- private void onSizeChanged(int width, int height) {
- if (!mServerSurfaceValid || mSurfaceView == null) {
- surfaceChanged(width, height);
- return;
- }
-
- if (isCompositorReady()) {
- mCompositor.syncResumeResizeCompositor(width, height, getSurface());
- }
-
- if (mOverscroll != null) {
- mOverscroll.setSize(width, height);
- }
- }
-
- private void surfaceChanged(int width, int height) {
- serverSurfaceChanged(width, height);
-
+ /* package */ void onSizeChanged(int width, int height) {
if (mListener != null) {
mListener.surfaceChanged();
}
if (mOverscroll != null) {
mOverscroll.setSize(width, height);
}
}
- void notifySizeChanged(int windowWidth, int windowHeight) {
- mCompositor.onSizeChanged(windowWidth, windowHeight);
- }
-
- void serverSurfaceDestroyed() {
- ThreadUtils.assertOnUiThread();
-
- // We need to coordinate with Gecko when pausing composition, to ensure
- // that Gecko never executes a draw event while the compositor is paused.
- // This is sent synchronously to make sure that we don't attempt to use
- // any outstanding Surfaces after we call this (such as from a
- // serverSurfaceDestroyed notification), and to make sure that any in-flight
- // Gecko draw events have been processed. When this returns, composition is
- // definitely paused -- it'll synchronize with the Gecko event loop, which
- // in turn will synchronize with the compositor thread.
- if (isCompositorReady()) {
- mCompositor.syncPauseCompositor();
- }
-
- mServerSurfaceValid = false;
- }
-
- private void onDestroyed() {
- serverSurfaceDestroyed();
- }
-
- public Object getNativeWindow() {
- if (mSurfaceView != null)
- return mSurfaceView.getHolder();
-
- return mTextureView.getSurfaceTexture();
- }
-
- public Object getSurface() {
- if (mSurfaceView != null) {
- return mSurfaceView.getHolder().getSurface();
- }
- return null;
- }
-
public interface Listener {
void surfaceChanged();
}
- private class SurfaceListener implements SurfaceHolder.Callback {
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- onSizeChanged(width, height);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- onDestroyed();
- }
- }
-
- /* A subclass of SurfaceView to listen to layout changes, as
- * View.OnLayoutChangeListener requires API level 11.
- */
- private class LayerSurfaceView extends SurfaceView {
- private LayerView mParent;
-
- public LayerSurfaceView(Context context, LayerView parent) {
- super(context);
- mParent = parent;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (changed && mParent.mServerSurfaceValid) {
- mParent.surfaceChanged(right - left, bottom - top);
- }
- }
- }
-
- private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
- // We don't do this for surfaceCreated above because it is always followed by a surfaceChanged,
- // but that is not the case here.
- onSizeChanged(width, height);
- }
-
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- onDestroyed();
- return true; // allow Android to call release() on the SurfaceTexture, we are done drawing to it
- }
-
- @Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
- onSizeChanged(width, height);
- }
-
- @Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {
-
- }
- }
-
@RobocopTarget
public void addDrawListener(final DrawListener listener) {
if (!ThreadUtils.isOnUiThread()) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
addDrawListener(listener);
}
@@ -770,16 +399,20 @@ public class LayerView extends FrameLayo
boolean notEmpty = mDrawListeners.isEmpty();
mDrawListeners.remove(listener);
if (isCompositorReady() && notEmpty && mDrawListeners.isEmpty()) {
mCompositor.enableLayerUpdateNotifications(false);
}
}
+ /* package */ void clearDrawListeners() {
+ mDrawListeners.clear();
+ }
+
@RobocopTarget
public static interface DrawListener {
public void drawFinished();
}
public float getZoomFactor() {
return getLayerClient().getViewportMetrics().zoomFactor;
}