Bug 1503656 - Part 7. Notify of safe area insets changed. r=smaug

Since safe area insets uses on content, we need send it from chrome process to
content process.

SafeAreaInsetsChanged will be called per window position/size change (Next
patch is Android implementation for it), we have to calculate safe area insets
on widget/window per change.

Current implementation is that this value is top level document only like Blink
since https://github.com/w3c/csswg-drafts/issues/4670 isn't resolved yet.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Makoto Kato 2020-03-04 08:16:31 +00:00
Родитель e3d1ff0f27
Коммит 6279258383
14 изменённых файлов: 216 добавлений и 1 удалений

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

@ -10377,3 +10377,52 @@ bool nsContentUtils::IsURIInList(nsIURI* aURI, const nsCString& aBlackList) {
return false;
}
/* static */
ScreenIntMargin nsContentUtils::GetWindowSafeAreaInsets(
nsIScreen* aScreen, const ScreenIntMargin& aSafeAreaInsets,
const LayoutDeviceIntRect& aWindowRect) {
// This calculates safe area insets of window from screen rectangle, window
// rectangle and safe area insets of screen.
//
// +----------------------------------------+ <-- screen
// | +-------------------------------+ <------- window
// | | window's safe area inset top) | |
// +--+-------------------------------+--+ |
// | | | |<------ safe area rectangle of
// | | | | | screen
// +--+-------------------------------+--+ |
// | |window's safe area inset bottom| |
// | +-------------------------------+ |
// +----------------------------------------+
//
ScreenIntMargin windowSafeAreaInsets;
int32_t screenLeft, screenTop, screenWidth, screenHeight;
nsresult rv =
aScreen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
if (NS_WARN_IF(NS_FAILED(rv))) {
return windowSafeAreaInsets;
}
// Screen's rect of safe area
LayoutDeviceIntRect safeAreaRect(
screenLeft + aSafeAreaInsets.left, screenTop + aSafeAreaInsets.top,
screenWidth - aSafeAreaInsets.right - aSafeAreaInsets.left,
screenHeight - aSafeAreaInsets.bottom - aSafeAreaInsets.top);
// window's rect of safe area
safeAreaRect = safeAreaRect.Intersect(aWindowRect);
windowSafeAreaInsets.top = std::max(safeAreaRect.y - aWindowRect.y, 0);
windowSafeAreaInsets.left = std::max(safeAreaRect.x - aWindowRect.x, 0);
windowSafeAreaInsets.right =
std::max((aWindowRect.x + aWindowRect.width) -
(safeAreaRect.x + safeAreaRect.width),
0);
windowSafeAreaInsets.bottom =
std::max(aWindowRect.y + aWindowRect.height -
(safeAreaRect.y + safeAreaRect.height),
0);
return windowSafeAreaInsets;
}

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

@ -3224,6 +3224,14 @@ class nsContentUtils {
static nsGlobalWindowInner* CallerInnerWindow();
/*
* Return safe area insets of window that defines as
* https://drafts.csswg.org/css-env-1/#safe-area-insets.
*/
static mozilla::ScreenIntMargin GetWindowSafeAreaInsets(
nsIScreen* aScreen, const mozilla::ScreenIntMargin& aSafeareaInsets,
const mozilla::LayoutDeviceIntRect& aWindowRect);
private:
static bool InitializeEventTable();

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

@ -1264,6 +1264,8 @@ mozilla::ipc::IPCResult BrowserChild::RecvUpdateDimensions(
dispatcher->PostDOMEvent();
}
RecvSafeAreaInsetsChanged(mPuppetWidget->GetSafeAreaInsets());
return IPC_OK();
}
@ -3255,6 +3257,44 @@ mozilla::ipc::IPCResult BrowserChild::RecvThemeChanged(
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvSafeAreaInsetsChanged(
const mozilla::ScreenIntMargin& aSafeAreaInsets) {
mPuppetWidget->UpdateSafeAreaInsets(aSafeAreaInsets);
nsCOMPtr<nsIScreenManager> screenMgr =
do_GetService("@mozilla.org/gfx/screenmanager;1");
ScreenIntMargin currentSafeAreaInsets;
if (screenMgr) {
// aSafeAreaInsets is for current screen. But we have to calculate
// safe insets for content window.
int32_t x, y, cx, cy;
GetDimensions(0, &x, &y, &cx, &cy);
nsCOMPtr<nsIScreen> screen;
screenMgr->ScreenForRect(x, y, cx, cy, getter_AddRefs(screen));
if (screen) {
LayoutDeviceIntRect windowRect(x + mClientOffset.x + mChromeOffset.x,
y + mClientOffset.y + mChromeOffset.y, cx,
cy);
currentSafeAreaInsets = nsContentUtils::GetWindowSafeAreaInsets(
screen, aSafeAreaInsets, windowRect);
}
}
if (nsCOMPtr<Document> document = GetTopLevelDocument()) {
nsPresContext* presContext = document->GetPresContext();
if (presContext) {
presContext->SetSafeAreaInsets(currentSafeAreaInsets);
}
}
// https://github.com/w3c/csswg-drafts/issues/4670
// Actually we don't set this value on sub document. This behaviour is
// same as Blink that safe area insets isn't set on sub document.
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvAwaitLargeAlloc() {
mAwaitingLA = true;
return IPC_OK();

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

@ -406,6 +406,9 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
mozilla::ipc::IPCResult RecvSwappedWithOtherRemoteLoader(
const IPCTabContext& aContext);
mozilla::ipc::IPCResult RecvSafeAreaInsetsChanged(
const mozilla::ScreenIntMargin& aSafeAreaInsets);
#ifdef ACCESSIBILITY
PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*,
const uint64_t&,

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

@ -935,9 +935,15 @@ void BrowserParent::InitRendering() {
Unused << SendInitRendering(textureFactoryIdentifier, layersId,
mRemoteLayerTreeOwner.GetCompositorOptions(),
mRemoteLayerTreeOwner.IsLayersConnected());
RefPtr<nsIWidget> widget = GetTopLevelWidget();
if (widget) {
ScreenIntMargin safeAreaInsets = widget->GetSafeAreaInsets();
Unused << SendSafeAreaInsetsChanged(safeAreaInsets);
}
#if defined(MOZ_WIDGET_ANDROID)
if (XRE_IsParentProcess()) {
RefPtr<nsIWidget> widget = GetTopLevelWidget();
MOZ_ASSERT(widget);
Unused << SendDynamicToolbarMaxHeightChanged(

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

@ -41,6 +41,7 @@ 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::ScreenIntMargin from "Units.h";
using mozilla::ScreenIntPoint from "Units.h";
using ScreenRect from "Units.h";
using struct mozilla::layers::ScrollableLayerGuid from "mozilla/layers/ScrollableLayerGuid.h";
@ -935,6 +936,12 @@ child:
*/
async ThemeChanged(LookAndFeelInt[] lookAndFeelIntCache);
/**
* Tell the child that the safe area of widget has changed.
*
*/
async SafeAreaInsetsChanged(ScreenIntMargin aSafeAreaInsets);
/**
* Tell the browser that its frame loader has been swapped
* with another.

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

@ -609,6 +609,26 @@ struct ParamTraits<mozilla::gfx::MarginTyped<T>> {
}
};
template <class T>
struct ParamTraits<mozilla::gfx::IntMarginTyped<T>> {
typedef mozilla::gfx::IntMarginTyped<T> paramType;
static void Write(Message* msg, const paramType& param) {
WriteParam(msg, param.top);
WriteParam(msg, param.right);
WriteParam(msg, param.bottom);
WriteParam(msg, param.left);
}
static bool Read(const Message* msg, PickleIterator* iter,
paramType* result) {
return (ReadParam(msg, iter, &result->top) &&
ReadParam(msg, iter, &result->right) &&
ReadParam(msg, iter, &result->bottom) &&
ReadParam(msg, iter, &result->left));
}
};
template <>
struct ParamTraits<nsRect> {
typedef nsRect paramType;

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

@ -811,6 +811,19 @@ nsresult nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow) {
mPresContext->SetOverrideDPPX(mOverrideDPPX);
}
if (mWindow && mDocument->IsTopLevelContentDocument()) {
// Set initial safe area insets
ScreenIntMargin windowSafeAreaInsets;
LayoutDeviceIntRect windowRect = mWindow->GetScreenBounds();
nsCOMPtr<nsIScreen> screen = mWindow->GetWidgetScreen();
if (screen) {
windowSafeAreaInsets = nsContentUtils::GetWindowSafeAreaInsets(
screen, mWindow->GetSafeAreaInsets(), windowRect);
}
mPresContext->SetSafeAreaInsets(windowSafeAreaInsets);
}
if (aDoInitialReflow) {
RefPtr<PresShell> presShell = mPresShell;
// Initial reflow

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

@ -20,6 +20,7 @@
#include "nsIFrame.h"
#include "nsPresArena.h"
#include "nsXULPopupManager.h"
#include "nsIScreen.h"
#include "nsIWidgetListener.h"
#include "nsContentUtils.h" // for nsAutoScriptBlocker
#include "nsDocShell.h"
@ -1137,6 +1138,49 @@ nsEventStatus nsView::HandleEvent(WidgetGUIEvent* aEvent,
return result;
}
void nsView::SafeAreaInsetsChanged(const ScreenIntMargin& aSafeAreaInsets) {
if (!IsRoot()) {
return;
}
PresShell* presShell = mViewManager->GetPresShell();
if (!presShell) {
return;
}
ScreenIntMargin windowSafeAreaInsets;
LayoutDeviceIntRect windowRect = mWindow->GetScreenBounds();
nsCOMPtr<nsIScreen> screen = mWindow->GetWidgetScreen();
if (screen) {
windowSafeAreaInsets = nsContentUtils::GetWindowSafeAreaInsets(
screen, aSafeAreaInsets, windowRect);
}
presShell->GetPresContext()->SetSafeAreaInsets(windowSafeAreaInsets);
// https://github.com/w3c/csswg-drafts/issues/4670
// Actually we don't set this value on sub document. This behaviour is
// same as Blink.
dom::Document* document = presShell->GetDocument();
if (!document) {
return;
}
nsPIDOMWindowOuter* window = document->GetWindow();
if (!window) {
return;
}
nsContentUtils::CallOnAllRemoteChildren(
window,
[windowSafeAreaInsets](dom::BrowserParent* aBrowserParent) -> CallState {
Unused << aBrowserParent->SendSafeAreaInsetsChanged(
windowSafeAreaInsets);
return CallState::Continue;
});
}
bool nsView::IsPrimaryFramePaintSuppressed() {
return StaticPrefs::layout_show_previous_page() && mFrame &&
mFrame->PresShell()->IsPaintingSuppressed();

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

@ -472,6 +472,7 @@ class nsView final : public nsIWidgetListener {
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual nsEventStatus HandleEvent(mozilla::WidgetGUIEvent* aEvent,
bool aUseAttachedEvents) override;
virtual void SafeAreaInsetsChanged(const mozilla::ScreenIntMargin&) override;
virtual ~nsView();

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

@ -1259,6 +1259,15 @@ PuppetScreenManager::ScreenForRect(int32_t inLeft, int32_t inTop,
return GetPrimaryScreen(outScreen);
}
ScreenIntMargin PuppetWidget::GetSafeAreaInsets() const {
return mSafeAreaInsets;
}
void PuppetWidget::UpdateSafeAreaInsets(
const ScreenIntMargin& aSafeAreaInsets) {
mSafeAreaInsets = aSafeAreaInsets;
}
nsIWidgetListener* PuppetWidget::GetCurrentWidgetListener() {
if (!mPreviouslyAttachedWidgetListener || !mAttachedWidgetListener) {
return mAttachedWidgetListener;

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

@ -232,6 +232,10 @@ class PuppetWidget : public nsBaseWidget,
nsIntSize GetScreenDimensions();
// safe area insets support
virtual ScreenIntMargin GetSafeAreaInsets() const override;
void UpdateSafeAreaInsets(const ScreenIntMargin& aSafeAreaInsets);
// Get the offset to the chrome of the window that this tab belongs to.
//
// NOTE: In OOP iframes this value is zero. You should use
@ -399,6 +403,8 @@ class PuppetWidget : public nsBaseWidget,
nsCOMPtr<imgIContainer> mCustomCursor;
uint32_t mCursorHotspotX, mCursorHotspotY;
ScreenIntMargin mSafeAreaInsets;
nsCOMArray<nsIKeyEventInPluginCallback> mKeyEventInPluginCallbacks;
RefPtr<TextEventDispatcherListener> mNativeTextEventDispatcherListener;

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

@ -33,6 +33,9 @@ bool nsIWidgetListener::WindowResized(nsIWidget* aWidget, int32_t aWidth,
void nsIWidgetListener::SizeModeChanged(nsSizeMode aSizeMode) {}
void nsIWidgetListener::SafeAreaInsetsChanged(const mozilla::ScreenIntMargin&) {
}
void nsIWidgetListener::UIResolutionChanged() {}
#if defined(MOZ_WIDGET_ANDROID)

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

@ -185,6 +185,12 @@ class nsIWidgetListener {
*/
virtual nsEventStatus HandleEvent(mozilla::WidgetGUIEvent* aEvent,
bool aUseAttachedEvents);
/**
* Called when safe area insets are changed.
*/
virtual void SafeAreaInsetsChanged(
const mozilla::ScreenIntMargin& aSafeAreaInsets);
};
#endif