--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -91,17 +91,16 @@ import org.mozilla.gecko.delegates.Offli
import org.mozilla.gecko.delegates.ScreenshotDelegate;
import org.mozilla.gecko.distribution.Distribution;
import org.mozilla.gecko.distribution.DistributionStoreCallback;
import org.mozilla.gecko.dlc.DownloadContentService;
import org.mozilla.gecko.extensions.ExtensionPermissionsHelper;
import org.mozilla.gecko.firstrun.FirstrunAnimationContainer;
import org.mozilla.gecko.gfx.DynamicToolbarAnimator;
import org.mozilla.gecko.gfx.DynamicToolbarAnimator.PinReason;
-import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.home.BrowserSearch;
import org.mozilla.gecko.home.HomeBanner;
import org.mozilla.gecko.home.HomeConfig;
import org.mozilla.gecko.home.HomeConfig.PanelType;
import org.mozilla.gecko.home.HomeConfigPrefsBackend;
import org.mozilla.gecko.home.HomeFragment;
import org.mozilla.gecko.home.HomePager.OnUrlOpenInBackgroundListener;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
@@ -4353,17 +4352,17 @@ public class BrowserApp extends GeckoApp
public void startActionMode(final ActionModeCompat.Callback callback) {
// If actionMode is null, we're not currently showing one. Flip to the action mode view
if (mActionMode == null) {
mActionBarFlipper.showNext();
DynamicToolbarAnimator toolbar = mLayerView.getDynamicToolbarAnimator();
// If the toolbar is dynamic and not currently showing, just show the real toolbar
// and keep the animated snapshot hidden
- if (mDynamicToolbar.isEnabled() && toolbar.getCurrentToolbarHeight() == 0) {
+ if (mDynamicToolbar.isEnabled() && !isToolbarChromeVisible()) {
toggleToolbarChrome(true);
mShowingToolbarChromeForActionBar = true;
}
mDynamicToolbar.setPinned(true, PinReason.ACTION_MODE);
} else {
// Otherwise, we're already showing an action mode. Just finish it and show the new one
mActionMode.finish();
--- a/mobile/android/base/java/org/mozilla/gecko/FormAssistPopup.java
+++ b/mobile/android/base/java/org/mozilla/gecko/FormAssistPopup.java
@@ -1,29 +1,29 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import org.mozilla.gecko.animation.ViewHelper;
-import org.mozilla.gecko.gfx.FloatSize;
-import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.util.ActivityUtils;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.SwipeDismissListViewTouchListener;
import org.mozilla.gecko.widget.SwipeDismissListViewTouchListener.OnDismissCallback;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.PointF;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -249,20 +249,16 @@ public class FormAssistPopup extends Rel
mW = rect.getDouble("w");
mH = rect.getDouble("h");
mPopupType = (isAutoComplete ?
PopupType.AUTOCOMPLETE : PopupType.VALIDATIONMESSAGE);
return true;
}
private void positionAndShowPopup() {
- positionAndShowPopup(mGeckoView.getSession().getViewportMetrics());
- }
-
- private void positionAndShowPopup(ImmutableViewportMetrics aMetrics) {
ThreadUtils.assertOnUiThread();
// Don't show the form assist popup when using fullscreen VKB
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isFullscreenMode()) {
return;
}
@@ -277,84 +273,75 @@ public class FormAssistPopup extends Rel
if (sAutoCompleteMinWidth == 0) {
Resources res = getContext().getResources();
sAutoCompleteMinWidth = (int) (res.getDimension(R.dimen.autocomplete_min_width));
sAutoCompleteRowHeight = (int) (res.getDimension(R.dimen.autocomplete_row_height));
sValidationMessageHeight = (int) (res.getDimension(R.dimen.validation_message_height));
}
- float zoom = aMetrics.zoomFactor;
-
// These values correspond to the input box for which we want to
// display the FormAssistPopup.
- int left = (int) (mX * zoom - aMetrics.viewportRectLeft);
- int top = (int) (mY * zoom - aMetrics.viewportRectTop + mGeckoView.getTop() +
- mGeckoView.getDynamicToolbarAnimator().getCurrentToolbarHeight());
- int width = (int) (mW * zoom);
- int height = (int) (mH * zoom);
+ final Matrix matrix = new Matrix();
+ final RectF input = new RectF((float) mX, (float) mY,
+ (float) (mX + mW), (float) (mY + mH));
+ mGeckoView.getSession().getClientToSurfaceMatrix(matrix);
+ matrix.mapRect(input);
+
+ final Rect page = new Rect();
+ mGeckoView.getSession().getSurfaceBounds(page);
int popupWidth = LayoutParams.MATCH_PARENT;
- int popupLeft = left < 0 ? 0 : left;
-
- FloatSize viewport = aMetrics.getSize();
+ int popupLeft = Math.max((int) input.left, page.left);
// For autocomplete suggestions, if the input is smaller than the screen-width,
// shrink the popup's width. Otherwise, keep it as MATCH_PARENT.
- if ((mPopupType == PopupType.AUTOCOMPLETE) && (left + width) < viewport.width) {
- popupWidth = left < 0 ? left + width : width;
-
+ if ((mPopupType == PopupType.AUTOCOMPLETE) && (int) input.right < page.right) {
// Ensure the popup has a minimum width.
- if (popupWidth < sAutoCompleteMinWidth) {
- popupWidth = sAutoCompleteMinWidth;
+ final int visibleWidth = (int) input.right - popupLeft;
+ popupWidth = Math.max(visibleWidth, sAutoCompleteMinWidth);
- // Move the popup to the left if there isn't enough room for it.
- if ((popupLeft + popupWidth) > viewport.width) {
- popupLeft = (int) (viewport.width - popupWidth);
- }
+ // Move the popup to the left if there isn't enough room for it.
+ if ((popupLeft + popupWidth) > page.right) {
+ popupLeft = Math.max(page.right - popupWidth, page.left);
}
}
int popupHeight;
if (mPopupType == PopupType.AUTOCOMPLETE) {
// Limit the amount of visible rows.
int rows = mAutoCompleteList.getAdapter().getCount();
if (rows > MAX_VISIBLE_ROWS) {
rows = MAX_VISIBLE_ROWS;
}
popupHeight = sAutoCompleteRowHeight * rows;
} else {
popupHeight = sValidationMessageHeight;
}
- int popupTop = top + height;
+ int popupTop = (int) input.bottom;
if (mPopupType == PopupType.VALIDATIONMESSAGE) {
mValidationMessageText.setLayoutParams(sValidationTextLayoutNormal);
mValidationMessageArrow.setVisibility(VISIBLE);
mValidationMessageArrowInverted.setVisibility(GONE);
}
// If the popup doesn't fit below the input box, shrink its height, or
// see if we can place it above the input instead.
- if ((popupTop + popupHeight) > (mGeckoView.getTop() + viewport.height)) {
+ if ((popupTop + popupHeight) > page.bottom) {
// Find where the maximum space is, and put the popup there.
- if ((viewport.height - popupTop) > top) {
+ if ((page.bottom - (int) input.bottom) > ((int) input.top - page.top)) {
// Shrink the height to fit it below the input box.
- popupHeight = (int) (viewport.height - popupTop);
+ popupHeight = page.bottom - (int) input.bottom;
} else {
- if (popupHeight < top) {
- // No shrinking needed to fit on top.
- popupTop = (top - popupHeight);
- } else {
- // Shrink to available space on top.
- popupTop = 0;
- popupHeight = top;
- }
+ // Shrink to available space on top if needed.
+ popupTop = Math.max((int) input.top - popupHeight, page.top);
+ popupHeight = (int) input.top - popupTop;
if (mPopupType == PopupType.VALIDATIONMESSAGE) {
mValidationMessageText.setLayoutParams(sValidationTextLayoutInverted);
mValidationMessageArrow.setVisibility(GONE);
mValidationMessageArrowInverted.setVisibility(VISIBLE);
}
}
}
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoAccessibility.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoAccessibility.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
import android.annotation.TargetApi;
import android.content.Context;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -169,51 +170,47 @@ public class GeckoAccessibility {
}
sVirtualCursorNode.setContentDescription(message.getString("description", ""));
final GeckoBundle bounds = message.getBundle("bounds");
if (bounds != null) {
Rect relativeBounds = new Rect(bounds.getInt("left"), bounds.getInt("top"),
bounds.getInt("right"), bounds.getInt("bottom"));
sVirtualCursorNode.setBoundsInParent(relativeBounds);
- int[] locationOnScreen = new int[2];
- view.getLocationOnScreen(locationOnScreen);
- locationOnScreen[1] += view.getDynamicToolbarAnimator().getCurrentToolbarHeight();
- Rect screenBounds = new Rect(relativeBounds);
- screenBounds.offset(locationOnScreen[0], locationOnScreen[1]);
- sVirtualCursorNode.setBoundsInScreen(screenBounds);
+
+ final Matrix matrix = new Matrix();
+ final float[] origin = new float[2];
+ view.getSession().getClientToScreenMatrix(matrix);
+ matrix.mapPoints(origin);
+
+ relativeBounds.offset((int) origin[0], (int) origin[1]);
+ sVirtualCursorNode.setBoundsInScreen(relativeBounds);
}
final GeckoBundle braille = message.getBundle("brailleOutput");
if (braille != null) {
sendBrailleText(view, braille.getString("text", ""),
braille.getInt("selectionStart"), braille.getInt("selectionEnd"));
}
if (eventType == AccessibilityEvent.TYPE_VIEW_HOVER_ENTER) {
sHoverEnter = message;
}
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
- event.setPackageName(GeckoAppShell.getApplicationContext().getPackageName());
- event.setClassName(GeckoAccessibility.class.getName());
- if (eventType == AccessibilityEvent.TYPE_ANNOUNCEMENT ||
- eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
- event.setSource(view, View.NO_ID);
- } else {
- event.setSource(view, VIRTUAL_CURSOR_POSITION);
- }
- populateEventFromJSON(event, message);
- ((ViewParent) view).requestSendAccessibilityEvent(view, event);
- }
- });
-
+ final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+ event.setPackageName(GeckoAppShell.getApplicationContext().getPackageName());
+ event.setClassName(GeckoAccessibility.class.getName());
+ if (eventType == AccessibilityEvent.TYPE_ANNOUNCEMENT ||
+ eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+ event.setSource(view, View.NO_ID);
+ } else {
+ event.setSource(view, VIRTUAL_CURSOR_POSITION);
+ }
+ populateEventFromJSON(event, message);
+ ((ViewParent) view).requestSendAccessibilityEvent(view, event);
}
}
private static void sendBrailleText(final View view, final String text, final int selectionStart, final int selectionEnd) {
AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(view, VIRTUAL_CURSOR_POSITION);
WriteData data = WriteData.forInfo(info);
data.setText(text);
// Set either the focus blink or the current caret position/selection
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -1045,21 +1045,21 @@ public abstract class GeckoApp extends G
session.getSettings().setString(GeckoSessionSettings.CHROME_URI,
"chrome://browser/content/browser.xul");
session.setContentListener(this);
GeckoAccessibility.setDelegate(mLayerView);
getAppEventDispatcher().registerGeckoThreadListener(this,
- "Accessibility:Event",
"Locale:Set",
null);
getAppEventDispatcher().registerUiThreadListener(this,
+ "Accessibility:Event",
"Contact:Add",
"DevToolsAuth:Scan",
"DOMFullScreen:Start",
"DOMFullScreen:Stop",
"Mma:reader_available",
"Mma:web_save_image",
"Mma:web_save_media",
"Permissions:Data",
@@ -2044,21 +2044,21 @@ public abstract class GeckoApp extends G
EventDispatcher.getInstance().unregisterUiThreadListener(this,
"Update:Check",
"Update:Download",
"Update:Install",
null);
getAppEventDispatcher().unregisterGeckoThreadListener(this,
- "Accessibility:Event",
"Locale:Set",
null);
getAppEventDispatcher().unregisterUiThreadListener(this,
+ "Accessibility:Event",
"Contact:Add",
"DevToolsAuth:Scan",
"DOMFullScreen:Start",
"DOMFullScreen:Stop",
"Mma:reader_available",
"Mma:web_save_image",
"Mma:web_save_media",
"Permissions:Data",
--- a/mobile/android/base/java/org/mozilla/gecko/text/FloatingToolbarTextSelection.java
+++ b/mobile/android/base/java/org/mozilla/gecko/text/FloatingToolbarTextSelection.java
@@ -1,17 +1,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.text;
import android.annotation.TargetApi;
import android.app.Activity;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Build;
import android.util.Log;
import android.util.TypedValue;
import android.view.ActionMode;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoView;
import org.mozilla.gecko.Telemetry;
@@ -163,25 +165,28 @@ public class FloatingToolbarTextSelectio
private boolean isRectVisible() {
// There's another case of an empty rect where just left == right but not top == bottom.
// That's the rect for a collapsed selection. While technically this rect isn't visible too
// we are not interested in this case because we do not want to hide the toolbar.
return contentRect.left != contentRect.right || contentRect.top != contentRect.bottom;
}
private void updateRect(final GeckoBundle message) {
- final double x = message.getDouble("x");
- final double y = (int) message.getDouble("y");
- final double width = (int) message.getDouble("width");
- final double height = (int) message.getDouble("height");
+ final float x = (float) message.getDouble("x");
+ final float y = (float) message.getDouble("y");
+ final float width = (float) message.getDouble("width");
+ final float height = (float) message.getDouble("height");
- final float toolbarOffset = geckoView.getDynamicToolbarAnimator().getCurrentToolbarHeight();
- final float zoomFactor = geckoView.getSession().getViewportMetrics().zoomFactor;
- geckoView.getLocationInWindow(locationInWindow);
+ final Matrix matrix = new Matrix();
+ final RectF rect = new RectF(x, y, x + width, y + height);
+ geckoView.getSession().getClientToScreenMatrix(matrix);
+ matrix.mapRect(rect);
- contentRect = new Rect(
- (int) (x * zoomFactor + locationInWindow[0]),
- (int) (y * zoomFactor + locationInWindow[1] + toolbarOffset),
- (int) ((x + width) * zoomFactor + locationInWindow[0]),
- (int) ((y + height) * zoomFactor + locationInWindow[1] +
- (height > 0 ? handlesOffset : 0)));
+ if ((int) height > 0) {
+ rect.bottom += handlesOffset;
+ }
+
+ if (contentRect == null) {
+ contentRect = new Rect();
+ }
+ rect.round(contentRect);
}
}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoInputConnection.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoInputConnection.java
@@ -347,80 +347,81 @@ class GeckoInputConnection
return;
}
imm.updateSelection(v, start, end, getComposingSpanStart(editable),
getComposingSpanEnd(editable));
}
@TargetApi(21)
@Override
- public void updateCompositionRects(final RectF[] aRects) {
+ public void updateCompositionRects(final RectF[] rects) {
if (!(Build.VERSION.SDK_INT >= 21)) {
return;
}
+ final GeckoView view = getView();
+ if (view == null) {
+ return;
+ }
+
+ final Editable content = getEditable();
+ if (content == null) {
+ return;
+ }
+
+ final int composingStart = getComposingSpanStart(content);
+ final int composingEnd = getComposingSpanEnd(content);
+ if (composingStart < 0 || composingEnd < 0) {
+ if (DEBUG) {
+ Log.d(LOGTAG, "No composition for updates");
+ }
+ return;
+ }
+
+ final CharSequence composition = content.subSequence(composingStart, composingEnd);
+
+ view.post(new Runnable() {
+ @Override
+ public void run() {
+ updateCompositionRectsOnUi(view, rects, composition);
+ }
+ });
+ }
+
+ @TargetApi(21)
+ /* package */ void updateCompositionRectsOnUi(final GeckoView view,
+ final RectF[] rects,
+ final CharSequence composition) {
+ if (view.getSession() == null) {
+ return;
+ }
+
if (mCursorAnchorInfoBuilder == null) {
mCursorAnchorInfoBuilder = new CursorAnchorInfo.Builder();
}
mCursorAnchorInfoBuilder.reset();
- // Calculate Gecko logical coords to screen coords
- final GeckoView view = getView();
- if (view == null || view.getSession() == null) {
- return;
+ final Matrix matrix = new Matrix();
+ view.getSession().getClientToScreenMatrix(matrix);
+ mCursorAnchorInfoBuilder.setMatrix(matrix);
+
+ for (int i = 0; i < rects.length; i++) {
+ mCursorAnchorInfoBuilder.addCharacterBounds(
+ i, rects[i].left, rects[i].top, rects[i].right, rects[i].bottom,
+ CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION);
}
- // First aRects element is the widget bounds in device units.
- final float zoom = view.getSession().getViewportMetrics().zoomFactor;
- final Matrix matrix = new Matrix();
- matrix.postScale(zoom, zoom);
- matrix.postTranslate(aRects[0].left, aRects[0].top);
- mCursorAnchorInfoBuilder.setMatrix(matrix);
+ mCursorAnchorInfoBuilder.setComposingText(0, composition);
- final Editable content = getEditable();
- if (content == null) {
- return;
- }
- int composingStart = getComposingSpanStart(content);
- int composingEnd = getComposingSpanEnd(content);
- if (composingStart < 0 || composingEnd < 0) {
- if (DEBUG) {
- Log.d(LOGTAG, "No composition for updates");
- }
+ final InputMethodManager imm = getInputMethodManager();
+ if (imm == null) {
return;
}
- // Subsequent aRects elements are character bounds in CSS units.
- for (int i = 1; i < aRects.length; i++) {
- mCursorAnchorInfoBuilder.addCharacterBounds(i - 1,
- aRects[i].left,
- aRects[i].top,
- aRects[i].right,
- aRects[i].bottom,
- CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION);
- }
-
- mCursorAnchorInfoBuilder.setComposingText(0, content.subSequence(composingStart, composingEnd));
-
- updateCursor();
- }
-
- @TargetApi(21)
- private void updateCursor() {
- if (mCursorAnchorInfoBuilder == null) {
- return;
- }
-
- final InputMethodManager imm = getInputMethodManager();
- final View v = getView();
- if (imm == null || v == null) {
- return;
- }
-
- imm.updateCursorAnchorInfo(v, mCursorAnchorInfoBuilder.build());
+ imm.updateCursorAnchorInfo(view, mCursorAnchorInfoBuilder.build());
}
@Override
public boolean requestCursorUpdates(int cursorUpdateMode) {
if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) {
mEditableClient.requestCursorUpdates(GeckoEditableClient.ONE_SHOT);
}
--- 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
@@ -128,17 +128,17 @@ public class LayerView extends FrameLayo
}
@Override
public void dispatchDraw(final Canvas canvas) {
super.dispatchDraw(canvas);
// We must have a layer client to get valid viewport metrics
if (mOverscroll != null) {
- mOverscroll.draw(canvas, mSession.getViewportMetrics());
+ mOverscroll.draw(canvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
requestFocus();
}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/Overscroll.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/Overscroll.java
@@ -9,13 +9,13 @@ import android.graphics.Canvas;
public interface Overscroll {
// The axis to show overscroll on.
public enum Axis {
X,
Y,
};
- public void draw(final Canvas canvas, final ImmutableViewportMetrics metrics);
+ public void draw(final Canvas canvas);
public void setSize(final int width, final int height);
public void setVelocity(final float velocity, final Axis axis);
public void setDistance(final float distance, final Axis axis);
}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/OverscrollEdgeEffect.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/OverscrollEdgeEffect.java
@@ -3,19 +3,19 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.gfx;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
import android.os.Build;
import android.widget.EdgeEffect;
import java.lang.reflect.Field;
public class OverscrollEdgeEffect implements Overscroll {
// Used to index particular edges in the edges array
private static final int TOP = 0;
@@ -113,42 +113,40 @@ public class OverscrollEdgeEffect implem
}
final EdgeEffect edge = getEdgeForAxisAndSide(axis, (int)distance);
edge.onPull(distance / (axis == Axis.X ? mView.getWidth() : mView.getHeight()));
invalidate();
}
@Override
- public void draw(final Canvas canvas, final ImmutableViewportMetrics metrics) {
- if (metrics == null || mView.mSession == null) {
+ public void draw(final Canvas canvas) {
+ if (mView.mSession == null) {
return;
}
- final float width = mView.getWidth();
- final float height = mView.getHeight();
- final float toolbarEnd = mView.mSession.getDynamicToolbarAnimator()
- .getCurrentToolbarHeight();
+ final Rect pageRect = new Rect();
+ mView.mSession.getSurfaceBounds(pageRect);
// If we're pulling an edge, or fading it out, draw!
boolean invalidate = false;
if (!mEdges[TOP].isFinished()) {
- invalidate |= draw(mEdges[TOP], canvas, 0, toolbarEnd, 0);
+ invalidate |= draw(mEdges[TOP], canvas, pageRect.left, pageRect.top, 0);
}
if (!mEdges[BOTTOM].isFinished()) {
- invalidate |= draw(mEdges[BOTTOM], canvas, width, height, 180);
+ invalidate |= draw(mEdges[BOTTOM], canvas, pageRect.right, pageRect.bottom, 180);
}
if (!mEdges[LEFT].isFinished()) {
- invalidate |= draw(mEdges[LEFT], canvas, 0, height, 270);
+ invalidate |= draw(mEdges[LEFT], canvas, pageRect.left, pageRect.bottom, 270);
}
if (!mEdges[RIGHT].isFinished()) {
- invalidate |= draw(mEdges[RIGHT], canvas, width, 0, 90);
+ invalidate |= draw(mEdges[RIGHT], canvas, pageRect.right, pageRect.top, 90);
}
// If the edge effect is animating off screen, invalidate.
if (invalidate) {
invalidate();
}
}
--- a/mobile/android/modules/FormAssistant.jsm
+++ b/mobile/android/modules/FormAssistant.jsm
@@ -17,16 +17,19 @@ XPCOMUtils.defineLazyModuleGetters(this,
var FormAssistant = {
// Weak-ref used to keep track of the currently focused element.
_currentFocusedElement: null,
// Whether we're in the middle of an autocomplete.
_doingAutocomplete: false,
+ // Last state received in "PanZoom:StateChange" observer.
+ _lastPanZoomState: "NOTHING",
+
init: function() {
Services.obs.addObserver(this, "PanZoom:StateChange");
},
_onPopupResponse: function(currentElement, message) {
switch (message.action) {
case "autocomplete": {
let editableElement = currentElement.QueryInterface(Ci.nsIDOMNSEditableElement);
@@ -78,16 +81,17 @@ var FormAssistant = {
if (!hasResults) {
this._hideFormAssistPopup(focused);
}
});
} else if (focused) {
// temporarily hide the form assist popup while we're panning or zooming the page
this._hideFormAssistPopup(focused);
}
+ this._lastPanZoomState = aData;
break;
}
},
notifyInvalidSubmit: function(aFormElement, aInvalidElements) {
if (!aInvalidElements.length) {
return;
}
@@ -178,18 +182,18 @@ var FormAssistant = {
this._showAutoCompleteSuggestions(currentElement, checkResultsInput);
break;
}
case "resize": {
let focused = this.focusedElement;
if (focused && focused.ownerGlobal == aEvent.target) {
- // Reposition the popup as if we just stopped pannning.
- this.observe(null, "PanZoom:StateChange", "NOTHING");
+ // Reposition the popup as in the case of pan/zoom.
+ this.observe(null, "PanZoom:StateChange", this._lastPanZoomState);
// Continue to listen to resizes.
focused.ownerGlobal.addEventListener(
"resize", this, {capture: true, mozSystemGroup: true, once: true});
}
break;
}
}
},
@@ -359,36 +363,32 @@ var FormAssistant = {
return {x: 0, y: 0, w: 0, h: 0};
}
let document = aElement.ownerDocument;
while (document.defaultView.frameElement) {
document = document.defaultView.frameElement.ownerDocument;
}
- let cwu = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
- let scrollX = {}, scrollY = {};
- cwu.getScrollXY(false, scrollX, scrollY);
-
+ let scrollX = 0, scrollY = 0;
let r = aElement.getBoundingClientRect();
// step out of iframes and frames, offsetting scroll values
for (let frame = aElement.ownerGlobal; frame.frameElement && frame != content;
frame = frame.parent) {
// adjust client coordinates' origin to be top left of iframe viewport
let rect = frame.frameElement.getBoundingClientRect();
let left = frame.getComputedStyle(frame.frameElement).borderLeftWidth;
let top = frame.getComputedStyle(frame.frameElement).borderTopWidth;
- scrollX.value += rect.left + parseInt(left);
- scrollY.value += rect.top + parseInt(top);
+ scrollX += rect.left + parseInt(left);
+ scrollY += rect.top + parseInt(top);
}
return {
- x: r.left + scrollX.value,
- y: r.top + scrollY.value,
+ x: r.left + scrollX,
+ y: r.top + scrollY,
w: r.width,
h: r.height,
};
},
};
FormAssistant.init();
--- a/widget/android/GeckoEditableSupport.cpp
+++ b/widget/android/GeckoEditableSupport.cpp
@@ -531,36 +531,29 @@ ConvertAndroidColor(uint32_t aArgb)
return NS_RGBA((aArgb & 0x00ff0000) >> 16,
(aArgb & 0x0000ff00) >> 8,
(aArgb & 0x000000ff),
(aArgb & 0xff000000) >> 24);
}
static jni::ObjectArray::LocalRef
ConvertRectArrayToJavaRectFArray(const nsTArray<LayoutDeviceIntRect>& aRects,
- const LayoutDeviceIntRect& aWidgetBounds,
const CSSToLayoutDeviceScale aScale)
{
const size_t length = aRects.Length();
- auto rects = jni::ObjectArray::New<sdk::RectF>(length + 1);
-
- // First element is the widget bounds in device units.
- auto widgetRect = sdk::RectF::New(aWidgetBounds.x, aWidgetBounds.y,
- aWidgetBounds.x + aWidgetBounds.width,
- aWidgetBounds.y + aWidgetBounds.height);
- rects->SetElement(0, widgetRect);
+ auto rects = jni::ObjectArray::New<sdk::RectF>(length);
for (size_t i = 0; i < length; i++) {
- LayoutDeviceIntRect tmp = aRects[i];
+ const LayoutDeviceIntRect& tmp = aRects[i];
- // Subsequent elements are character bounds in CSS units.
+ // Character bounds in CSS units.
auto rect = sdk::RectF::New(tmp.x / aScale.scale, tmp.y / aScale.scale,
(tmp.x + tmp.width) / aScale.scale,
(tmp.y + tmp.height) / aScale.scale);
- rects->SetElement(i + 1, rect);
+ rects->SetElement(i, rect);
}
return rects;
}
namespace mozilla {
namespace widget {
NS_IMPL_ISUPPORTS(GeckoEditableSupport,
@@ -917,17 +910,16 @@ GeckoEditableSupport::UpdateCompositionR
nsEventStatus status = nsEventStatus_eIgnore;
uint32_t offset = composition->NativeOffsetOfStartComposition();
WidgetQueryContentEvent textRects(true, eQueryTextRectArray, widget);
textRects.InitForQueryTextRectArray(offset, composition->String().Length());
widget->DispatchEvent(&textRects, status);
auto rects = ConvertRectArrayToJavaRectFArray(
textRects.mReply.mRectArray,
- widget->GetScreenBounds(),
widget->GetDefaultScale());
mEditable->UpdateCompositionRects(rects);
}
void
GeckoEditableSupport::OnImeSynchronize()
{