Bug 1586144 - Introduce an API to set the dynamic toolbar maximum height in GeckoView. r=geckoview-reviewers,tnikkel,snorp

And deliver the value to the top content pres context, but it's not used in
this commit. The value will be used in the next commit.

One caveat is that areas covered by the dynamic toolbar will be outside
of the content area, which means implementers of GeckoView needs to call
setVerticalClipping with _negative_ values.

Depends on D50416

Differential Revision: https://phabricator.services.mozilla.com/D50417

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Hiroyuki Ikezoe 2019-11-14 05:59:47 +00:00
Родитель eb3f83b865
Коммит 2a51338a5a
20 изменённых файлов: 270 добавлений и 1 удалений

Просмотреть файл

@ -368,6 +368,7 @@ BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId,
mIgnoreKeyPressEvent(false),
mHasValidInnerSize(false),
mDestroyed(false),
mDynamicToolbarMaxHeight(0),
mUniqueId(aTabId),
mIsTopLevel(aIsTopLevel),
mHasSiblings(false),
@ -1309,6 +1310,23 @@ mozilla::ipc::IPCResult BrowserChild::RecvSetIsUnderHiddenEmbedderElement(
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarMaxHeightChanged(
const ScreenIntCoord& aHeight) {
#if defined(MOZ_WIDGET_ANDROID)
mDynamicToolbarMaxHeight = aHeight;
RefPtr<Document> document = GetTopLevelDocument();
if (!document) {
return IPC_OK();
}
if (RefPtr<nsPresContext> presContext = document->GetPresContext()) {
presContext->SetDynamicToolbarMaxHeight(aHeight);
}
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvSuppressDisplayport(
const bool& aEnabled) {
if (RefPtr<PresShell> presShell = GetTopLevelPresShell()) {

Просмотреть файл

@ -286,6 +286,9 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
const mozilla::Maybe<mozilla::gfx::Matrix4x4>& aMatrix,
const mozilla::ScreenRect& aRemoteDocumentRect);
mozilla::ipc::IPCResult RecvDynamicToolbarMaxHeightChanged(
const mozilla::ScreenIntCoord& aHeight);
mozilla::ipc::IPCResult RecvActivate();
mozilla::ipc::IPCResult RecvDeactivate();
@ -538,6 +541,9 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
LayoutDeviceIntPoint GetClientOffset() const { return mClientOffset; }
LayoutDeviceIntPoint GetChromeOffset() const { return mChromeOffset; };
ScreenIntCoord GetDynamicToolbarMaxHeight() const {
return mDynamicToolbarMaxHeight;
};
bool IPCOpen() const { return mIPCOpen; }
@ -829,6 +835,7 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
LayoutDeviceIntPoint mClientOffset;
// Position of tab, relative to parent widget (typically the window)
LayoutDeviceIntPoint mChromeOffset;
ScreenIntCoord mDynamicToolbarMaxHeight;
TabId mUniqueId;
// Whether or not this browser is the child part of the top level PBrowser

Просмотреть файл

@ -908,6 +908,15 @@ void BrowserParent::InitRendering() {
Unused << SendInitRendering(textureFactoryIdentifier, layersId,
mRemoteLayerTreeOwner.GetCompositorOptions(),
mRemoteLayerTreeOwner.IsLayersConnected());
#if defined(MOZ_WIDGET_ANDROID)
if (XRE_IsParentProcess()) {
RefPtr<nsIWidget> widget = GetTopLevelWidget();
MOZ_ASSERT(widget);
Unused << SendDynamicToolbarMaxHeightChanged(
widget->GetDynamicToolbarMaxHeight());
}
#endif
}
bool BrowserParent::AttachLayerManager() {
@ -1082,6 +1091,14 @@ void BrowserParent::ThemeChanged() {
}
}
#if defined(MOZ_WIDGET_ANDROID)
void BrowserParent::DynamicToolbarMaxHeightChanged(ScreenIntCoord aHeight) {
if (!mIsDestroyed) {
Unused << SendDynamicToolbarMaxHeightChanged(aHeight);
}
}
#endif
void BrowserParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>& aCharCodes) {
if (!mIsDestroyed) {

Просмотреть файл

@ -533,6 +533,10 @@ class BrowserParent final : public PBrowserParent,
void HandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>& aCharCodes);
#if defined(MOZ_WIDGET_ANDROID)
void DynamicToolbarMaxHeightChanged(ScreenIntCoord aHeight);
#endif
void Activate();
void Deactivate(bool aWindowLowering);

Просмотреть файл

@ -37,6 +37,7 @@ using mozilla::gfx::MaybeMatrix4x4 from "mozilla/gfx/Matrix.h";
using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
using mozilla::LayoutDeviceIntPoint from "Units.h";
using mozilla::LayoutDevicePoint from "Units.h";
using mozilla::ScreenIntCoord from "Units.h";
using mozilla::ScreenIntPoint from "Units.h";
using ScreenIntSize from "Units.h";
using ScreenRect from "Units.h";
@ -748,6 +749,8 @@ child:
async SetIsUnderHiddenEmbedderElement(bool aIsUnderHiddenEmbedderElement);
async DynamicToolbarMaxHeightChanged(ScreenIntCoord height);
async ParentActivated(bool aActivated);
async SetKeyboardIndicators(UIStateChangeType showFocusRings);

Просмотреть файл

@ -167,6 +167,7 @@ nsPresContext::nsPresContext(dom::Document* aDocument, nsPresContextType aType)
mLastFontInflationScreenSize(gfxSize(-1.0, -1.0)),
mCurAppUnitsPerDevPixel(0),
mAutoQualityMinFontSizePixelsPref(0),
mDynamicToolbarMaxHeight(0),
mPageSize(-1, -1),
mPageScale(0.0),
mPPScale(1.0f),
@ -662,6 +663,15 @@ nsresult nsPresContext::Init(nsDeviceContext* aDeviceContext) {
mEventManager->SetPresContext(this);
#if defined(MOZ_WIDGET_ANDROID)
if (IsRootContentDocumentCrossProcess()) {
if (BrowserChild* browserChild =
BrowserChild::GetFrom(mDocument->GetDocShell())) {
mDynamicToolbarMaxHeight = browserChild->GetDynamicToolbarMaxHeight();
}
}
#endif
#ifdef DEBUG
mInitialized = true;
#endif
@ -2456,6 +2466,15 @@ void nsPresContext::FlushFontFeatureValues() {
}
}
void nsPresContext::SetDynamicToolbarMaxHeight(ScreenIntCoord aHeight) {
MOZ_ASSERT(IsRootContentDocumentCrossProcess());
if (mDynamicToolbarMaxHeight == aHeight) {
return;
}
mDynamicToolbarMaxHeight = aHeight;
}
#ifdef DEBUG
void nsPresContext::ValidatePresShellAndDocumentReleation() const {

Просмотреть файл

@ -380,6 +380,11 @@ class nsPresContext : public nsISupports,
}
}
/**
* Set the maximum height of the dynamic toolbar in nscoord units.
*/
void SetDynamicToolbarMaxHeight(mozilla::ScreenIntCoord aHeight);
/**
* Return true if this presentation context is a paginated
* context.
@ -1168,6 +1173,8 @@ class nsPresContext : public nsISupports,
mozilla::UniquePtr<gfxMissingFontRecorder> mMissingFonts;
nsRect mVisibleArea;
// The maximum height of the dynamic toolbar on mobile.
mozilla::ScreenIntCoord mDynamicToolbarMaxHeight;
nsSize mPageSize;
float mPageScale;
float mPPScale;

Просмотреть файл

@ -386,6 +386,7 @@ package org.mozilla.geckoview {
method @UiThread @NonNull public GeckoResult<Bitmap> capturePixels();
method @UiThread public void screenOriginChanged(int, int);
method @UiThread @NonNull public GeckoDisplay.ScreenshotBuilder screenshot();
method @UiThread public void setDynamicToolbarMaxHeight(int);
method @UiThread public void setVerticalClipping(int);
method @UiThread public boolean shouldPinOnScreen();
method @UiThread public void surfaceChanged(@NonNull Surface, int, int);
@ -1149,6 +1150,7 @@ package org.mozilla.geckoview {
method public int onTouchEventForResult(@NonNull MotionEvent);
method @UiThread @Nullable public GeckoSession releaseSession();
method public void setAutofillEnabled(boolean);
method public void setDynamicToolbarMaxHeight(int);
method @UiThread public void setSession(@NonNull GeckoSession);
method public void setVerticalClipping(int);
method public boolean shouldPinOnScreen();

Просмотреть файл

@ -0,0 +1,32 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.geckoview.test
import android.support.test.filters.MediumTest
import android.support.test.runner.AndroidJUnit4
import org.hamcrest.Matchers.*
import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
private const val SCREEN_HEIGHT = 100
private const val SCREEN_WIDTH = 200
@RunWith(AndroidJUnit4::class)
@MediumTest
class DynamicToolbarTest : BaseSessionTest() {
@WithDisplay(height = SCREEN_HEIGHT, width = SCREEN_WIDTH)
@Test
fun outOfRangeValue() {
try {
sessionRule.display?.run { setDynamicToolbarMaxHeight(SCREEN_HEIGHT + 1) }
fail("Request should have failed")
} catch (e: AssertionError) {
assertThat("Throws an exception when setting values greater than the client height",
e.toString(), containsString("maximum height of the dynamic toolbar"))
}
}
}

Просмотреть файл

@ -109,6 +109,24 @@ public class GeckoDisplay {
}
}
/**
* Set the maximum height of the dynamic toolbar(s).
*
* If the toolbar is dynamic, this function needs to be called with the maximum
* possible toolbar height so that Gecko can make the ICB static even during the dynamic
* toolbar height is being changed.
*
* @param height The maximum height of the dynamic toolbar(s).
*/
@UiThread
public void setDynamicToolbarMaxHeight(final int height) {
ThreadUtils.assertOnUiThread();
if (mSession != null) {
mSession.setDynamicToolbarMaxHeight(height);
}
}
/**
* Update the amount of vertical space that is clipped or visibly obscured in the bottom portion
* of the display. Tells gecko where to put bottom fixed elements so they are fully visible.

Просмотреть файл

@ -139,6 +139,7 @@ public class GeckoSession implements Parcelable {
private int mHeight; // Height of the surface (including toolbar);
private int mClientHeight; // Height of the client area (i.e. excluding toolbar);
private int mFixedBottomOffset; // The margin for fixed elements attached to the bottom of the viewport.
private int mDynamicToolbarMaxHeight = 0; // The maximum height of the dynamic toolbar
private float mViewportLeft;
private float mViewportTop;
private float mViewportZoom = 1.0f;
@ -204,6 +205,9 @@ public class GeckoSession implements Parcelable {
@WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
public native void onBoundsChanged(int left, int top, int width, int height);
@WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
public native void setDynamicToolbarMaxHeight(int height);
// Gecko thread pauses compositor; blocks UI thread.
@WrapForJNI(calledFrom = "ui", dispatchTo = "current")
public native void syncPauseCompositor();
@ -5268,6 +5272,26 @@ public class GeckoSession implements Parcelable {
onWindowBoundsChanged();
}
/* package */ void setDynamicToolbarMaxHeight(final int height) {
if (mDynamicToolbarMaxHeight == height) {
return;
}
if (mHeight != 0 && height != 0 && mHeight < height) {
throw new AssertionError("The maximum height of the dynamic toolbar (" +
height +
") should be smaller than GeckoView height (" +
mHeight + ")");
}
mDynamicToolbarMaxHeight = height;
if (mAttachedCompositor) {
mCompositor.setDynamicToolbarMaxHeight(mDynamicToolbarMaxHeight);
}
}
/* package */ void setFixedBottomOffset(final int offset) {
mFixedBottomOffset = offset;
@ -5292,6 +5316,7 @@ public class GeckoSession implements Parcelable {
}
mCompositor.sendToolbarAnimatorMessage(IS_COMPOSITOR_CONTROLLER_OPEN);
mCompositor.setDynamicToolbarMaxHeight(mDynamicToolbarMaxHeight);
}
/* package */ void onCompositorDetached() {
@ -5444,6 +5469,14 @@ public class GeckoSession implements Parcelable {
ThreadUtils.assertOnUiThread();
}
if (mHeight != 0 && mDynamicToolbarMaxHeight != 0 &&
mHeight < mDynamicToolbarMaxHeight) {
throw new AssertionError("The maximum height of the dynamic toolbar (" +
mDynamicToolbarMaxHeight +
") should be smaller than GeckoView height (" +
mHeight + ")");
}
final int toolbarHeight;
if (mToolbar != null) {
toolbarHeight = mToolbar.getCurrentToolbarHeight();

Просмотреть файл

@ -108,6 +108,7 @@ public class GeckoView extends FrameLayout {
private boolean mValid;
private int mClippingHeight;
private int mDynamicToolbarMaxHeight;
public void acquire(final GeckoDisplay display) {
mDisplay = display;
@ -124,6 +125,7 @@ public class GeckoView extends FrameLayout {
final SurfaceHolder holder = GeckoView.this.mSurfaceView.getHolder();
final Rect frame = holder.getSurfaceFrame();
mDisplay.surfaceChanged(holder.getSurface(), frame.right, frame.bottom);
mDisplay.setDynamicToolbarMaxHeight(mDynamicToolbarMaxHeight);
GeckoView.this.setActive(true);
}
}
@ -150,6 +152,7 @@ public class GeckoView extends FrameLayout {
final int width, final int height) {
if (mDisplay != null) {
mDisplay.surfaceChanged(holder.getSurface(), width, height);
mDisplay.setDynamicToolbarMaxHeight(mDynamicToolbarMaxHeight);
if (!mValid) {
GeckoView.this.setActive(true);
}
@ -188,6 +191,13 @@ public class GeckoView extends FrameLayout {
}
}
public void setDynamicToolbarMaxHeight(final int height) {
mDynamicToolbarMaxHeight = height;
if (mDisplay != null) {
mDisplay.setDynamicToolbarMaxHeight(height);
}
}
/**
* Request a {@link Bitmap} of the visible portion of the web page currently being
* rendered.
@ -290,6 +300,18 @@ public class GeckoView extends FrameLayout {
mDisplay.setVerticalClipping(clippingHeight);
}
/**
* Set the maximum height of the dynamic toolbar(s).
*
* If there are two or more dynamic toolbars, the height value should be the total amount of
* the height of each dynamic toolbar.
*
* @param height The the maximum height of the dynamic toolbar(s).
*/
public void setDynamicToolbarMaxHeight(final int height) {
mDisplay.setDynamicToolbarMaxHeight(height);
}
/* package */ void setActive(final boolean active) {
if (mSession != null) {
mSession.setActive(active);

Просмотреть файл

@ -80,6 +80,8 @@ exclude: true
([bug 1402369]({{bugzilla}}1402369))
- Added [`GeckoDisplay.screenshot`][71.23] allowing apps finer grain control over screenshots.
([bug 1577192]({{bugzilla}}1577192))
- Added `GeckoView.setDynamicToolbarMaxHeight` to make ICB size static, ICB doesn't include the dynamic toolbar region.
([bug 1586144]({{bugzilla}}1586144))
[71.1]: {{javadoc_uri}}/RuntimeTelemetry.Delegate.html#onBooleanScalar-org.mozilla.geckoview.RuntimeTelemetry.Metric-
[71.2]: {{javadoc_uri}}/RuntimeTelemetry.Delegate.html#onLongScalar-org.mozilla.geckoview.RuntimeTelemetry.Metric-
@ -425,4 +427,4 @@ exclude: true
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
[65.25]: {{javadoc_uri}}/GeckoResult.html
[api-version]: f4f62b0476eb283fbaf4be55e91b78dede9f0099
[api-version]: 5fce802ebb83bfd1237dd1ad541dceccb3801d9d

Просмотреть файл

@ -13,6 +13,8 @@
#include "mozilla/Poison.h"
#include "mozilla/PresShell.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/BrowserParent.h"
#include "nsIWidget.h"
#include "nsViewManager.h"
#include "nsIFrame.h"
@ -965,6 +967,40 @@ bool nsView::WindowResized(nsIWidget* aWidget, int32_t aWidth,
return false;
}
#if defined(MOZ_WIDGET_ANDROID)
static bool NotifyDynamicToolbarMaxHeightChanged(
dom::BrowserParent* aBrowserParent, void* aArg) {
ScreenIntCoord* height = static_cast<ScreenIntCoord*>(aArg);
aBrowserParent->DynamicToolbarMaxHeightChanged(*height);
return false;
}
void nsView::DynamicToolbarMaxHeightChanged(ScreenIntCoord aHeight) {
MOZ_ASSERT(XRE_IsParentProcess(),
"Should be only called for the browser parent process");
MOZ_ASSERT(this == mViewManager->GetRootView(),
"Should be called for the root view");
PresShell* presShell = mViewManager->GetPresShell();
if (!presShell) {
return;
}
dom::Document* document = presShell->GetDocument();
if (!document) {
return;
}
nsPIDOMWindowOuter* window = document->GetWindow();
if (!window) {
return;
}
nsContentUtils::CallOnAllRemoteChildren(
window, NotifyDynamicToolbarMaxHeightChanged, &aHeight);
}
#endif
bool nsView::RequestWindowClose(nsIWidget* aWidget) {
if (mFrame && IsPopupWidget(aWidget) && mFrame->IsMenuPopupFrame()) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();

Просмотреть файл

@ -449,6 +449,10 @@ class nsView final : public nsIWidgetListener {
virtual bool WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) override;
virtual bool WindowResized(nsIWidget* aWidget, int32_t aWidth,
int32_t aHeight) override;
#if defined(MOZ_WIDGET_ANDROID)
virtual void DynamicToolbarMaxHeightChanged(
mozilla::ScreenIntCoord aHeight) override;
#endif
virtual bool RequestWindowClose(nsIWidget* aWidget) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void WillPaintWindow(nsIWidget* aWidget) override;

Просмотреть файл

@ -982,6 +982,15 @@ class nsWindow::LayerViewSupport final
mWindow->Resize(aLeft, aTop, aWidth, aHeight, /* repaint */ false);
}
void SetDynamicToolbarMaxHeight(int32_t aHeight) {
MOZ_ASSERT(NS_IsMainThread());
if (!mWindow) {
return; // Already shut down.
}
mWindow->UpdateDynamicToolbarMaxHeight(ScreenIntCoord(aHeight));
}
void SyncPauseCompositor() {
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
@ -1477,6 +1486,7 @@ nsWindow::nsWindow()
: mScreenId(0), // Use 0 (primary screen) as the default value.
mIsVisible(false),
mParent(nullptr),
mDynamicToolbarMaxHeight(0),
mIsFullScreen(false),
mIsDisablingWebRender(false) {}
@ -2300,6 +2310,22 @@ void nsWindow::RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize) {
}
}
void nsWindow::UpdateDynamicToolbarMaxHeight(ScreenIntCoord aHeight) {
if (mDynamicToolbarMaxHeight == aHeight) {
return;
}
mDynamicToolbarMaxHeight = aHeight;
if (mWidgetListener) {
mWidgetListener->DynamicToolbarMaxHeightChanged(aHeight);
}
if (mAttachedWidgetListener) {
mAttachedWidgetListener->DynamicToolbarMaxHeightChanged(aHeight);
}
}
nsresult nsWindow::SetPrefersReducedMotionOverrideForTest(bool aValue) {
nsXPLookAndFeel::GetInstance()->SetPrefersReducedMotionOverrideForTest(
aValue);

Просмотреть файл

@ -322,6 +322,10 @@ class nsWindow final : public nsBaseWidget {
const CSSToScreenScale& aZoom) override;
void RecvScreenPixels(mozilla::ipc::Shmem&& aMem,
const ScreenIntSize& aSize) override;
void UpdateDynamicToolbarMaxHeight(mozilla::ScreenIntCoord aHeight) override;
mozilla::ScreenIntCoord GetDynamicToolbarMaxHeight() const override {
return mDynamicToolbarMaxHeight;
}
nsresult SetPrefersReducedMotionOverrideForTest(bool aValue) override;
nsresult ResetPrefersReducedMotionOverrideForTest() override;
@ -342,6 +346,7 @@ class nsWindow final : public nsBaseWidget {
nsWindow* mParent;
nsCOMPtr<nsIIdleServiceInternal> mIdleService;
mozilla::ScreenIntCoord mDynamicToolbarMaxHeight;
bool mIsFullScreen;
bool mIsDisablingWebRender;

Просмотреть файл

@ -2119,6 +2119,11 @@ class nsIWidget : public nsISupports {
*/
virtual void RecvScreenPixels(mozilla::ipc::Shmem&& aMem,
const ScreenIntSize& aSize) = 0;
virtual void UpdateDynamicToolbarMaxHeight(mozilla::ScreenIntCoord aHeight) {}
virtual mozilla::ScreenIntCoord GetDynamicToolbarMaxHeight() const {
return 0;
}
#endif
static already_AddRefed<nsIBidiKeyboard> CreateBidiKeyboard();

Просмотреть файл

@ -35,6 +35,11 @@ void nsIWidgetListener::SizeModeChanged(nsSizeMode aSizeMode) {}
void nsIWidgetListener::UIResolutionChanged() {}
#if defined(MOZ_WIDGET_ANDROID)
void nsIWidgetListener::DynamicToolbarMaxHeightChanged(ScreenIntCoord aHeight) {
}
#endif
void nsIWidgetListener::FullscreenWillChange(bool aInFullscreen) {}
void nsIWidgetListener::FullscreenChanged(bool aInFullscreen) {}

Просмотреть файл

@ -85,6 +85,10 @@ class nsIWidgetListener {
*/
virtual void UIResolutionChanged();
#if defined(MOZ_WIDGET_ANDROID)
virtual void DynamicToolbarMaxHeightChanged(mozilla::ScreenIntCoord aHeight);
#endif
/**
* Called when the z-order of the window is changed. Returns true if the
* notification was handled. aPlacement indicates the new z order. If