Allow controlling zoom-to-focused-input behaviour using `user-scalable` and `touch-action`
Categories
(Core :: Panning and Zooming, defect, P3)
Tracking
()
People
(Reporter: botond, Assigned: rzvncj, Mentored)
References
Details
(Whiteboard: [lang=c++])
Attachments
(2 files)
As discussed in bug 1738696, we would like to allow website authors to disable zoom-to-focused-input behaviour on mobile using either of the following:
user-scalable=no
in the meta viewport tagtouch-action: manipulation
(and any other less permissive value oftouch-action
includingnone
)
For now I'm marking this as a mentored bug, it's a good task for someone looking to learn the APZ code to pick up.
Assignee | ||
Comment 1•1 year ago
|
||
Doesn't this code suggest that the user-scalable=no
case should already be handled correctly? Since the bug is still open I'm guessing it's not, which means I'm probably looking at the wrong piece of code. :)
Reporter | ||
Comment 2•1 year ago
|
||
(In reply to Razvan Cojocaru from comment #1)
Doesn't this code suggest that the
user-scalable=no
case should already be handled correctly? Since the bug is still open I'm guessing it's not, which means I'm probably looking at the wrong piece of code. :)
I think that code is at least potentially relevant!
I think a good place to start here is to check what is in mZoomConstraints
when AsyncPanZoomController::ZoomToRect()
is called when triggering zoom-to-focused-input behaviour on a page with user-scalable=no
.
Do we have mMinZoom == mMaxZoom
? If so, ZoomToRect
should be a no-op (and if it's not in fact a no-op, we need to check the logic inside ZoomToRect
).
If we don't have mMinZoom == mMaxZoom
, then we should look more closely at the code you linked and see why not (the values should come from scaleMinFloat
/scaleMaxFloat
there).
If it turns out that there is a good reason why we can't have mMinZoom == mMaxZoom
, then we could alternatively consider having ZoomToRect
also respect mAllowZoom
(and mAllowZoom
should definitely be false
with user-scalable=no
).
Assignee | ||
Comment 3•1 year ago
|
||
I've had a few moments to look at this again today. Just to recap, you've suggested that we use a copy of this mochitest to debug this. I'm guessing that, in order to reproduce this, the test can be used as-is, except for setting maximum-scale
to something else (2
, for example)? However, doing so keeps allowing the test to pass, so it's likely that I'm missing something.
I'm running ./mach mochitest --setpref apz.subtest=helper_zoomToFocusedInput_nozoom2.html ./gfx/layers/apz/test/mochitest/test_group_zoomToFocusedInput.html
(where helper_zoomToFocusedInput_nozoom2.html
is the new test, with maximum-scale=2
), and test_group_zoomToFocusedInput.html
list of tests has been updated to include it.
Also, I'm guessing that the test (once correctly implemented) is supposed to only fail with an Android build, and not on desktop builds?
Reporter | ||
Comment 4•1 year ago
•
|
||
(In reply to Razvan Cojocaru from comment #3)
Just to recap, you've suggested that we use a copy of this mochitest to debug this. I'm guessing that, in order to reproduce this, the test can be used as-is, except for setting
maximum-scale
to something else (2
, for example)? However, doing so keeps allowing the test to pass, so it's likely that I'm missing something.
It's possible some minor modifications to the test will be required, though I'm not sure exactly what without playing around with it.
Some things to check are:
- Does
AsyncPanZoomController::ZoomToRect()
get called when running the test? - If so, what are the values of the starting zoom (
Metrics().GetZoom()
) and the computed target zoom (endZoomToMetrics.GetZoom()
near the end of the function)?
Also, I'm guessing that the test (once correctly implemented) is supposed to only fail with an Android build, and not on desktop builds?
Good question!
The main thing the test relies on that is disabled by default on desktop, is processing of the <meta name="viewport">
tag (sometimes referred to as "mobile viewport sizing" in the code). This can be enabled on desktop by setting the pref dom.meta-viewport.enabled=true
. This is technically an unsupported configuration, especially if non-overlay scrollbars are used (because mobile viewport sizing can have weird interactions with scrollbars that take up layout-space on the page; details can be found here if you're curious), and we probably wouldn't want to check this in, but it's probably fine for running the test locally in a desktop build for convenience.
Assignee | ||
Comment 5•1 year ago
|
||
(In reply to Botond Ballo [:botond] from comment #4)
- Does
AsyncPanZoomController::ZoomToRect()
get called when running the test?- If so, what are the values of the starting zoom (
Metrics().GetZoom()
) and the computed target zoom (endZoomToMetrics.GetZoom()
near the end of the function)?
(This is with the desktop build, with dom.meta-viewport.enabled=true
.)
0:13.11 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: got apz-flush-done in child proc
0:13.11 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: done promiseFocus
0:13.14 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: done promiseAllPaintsDone
0:13.14 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:13.15 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:13.15 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: all done
0:13.16 PASS helper_zoomToFocusedInput_nozoom2.html | The initial_resolution is 1, which is some sane value
0:13.34 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:13.35 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:13.39 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:13.40 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:13.42 PASS helper_zoomToFocusedInput_nozoom2.html | focusing input did not change resolution 1
0:13.42 GECKO(19478) void mozilla::layers::AsyncPanZoomController::ZoomToRect(const mozilla::layers::ZoomTarget &, const uint32_t)
0:13.43 GECKO(19478) Metrics().GetZoom(): 1, endZoomToMetrics.GetZoom(): 1
0:13.43 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:13.45 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:13.77 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:13.78 GECKO(19478) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:13.80 PASS helper_zoomToFocusedInput_nozoom2.html | zoomToFocusedInput input did not change resolution 1
diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -12,6 +12,8 @@
#include <algorithm> // for max, min
#include <utility> // for std::make_pair
+#include <iostream>
+
#include "APZCTreeManager.h" // for APZCTreeManager
#include "AsyncPanZoomAnimation.h" // for AsyncPanZoomAnimation
#include "AutoDirWheelDeltaAdjuster.h" // for APZAutoDirWheelDeltaAdjuster
@@ -5822,6 +5824,7 @@ APZCTreeManager* AsyncPanZoomController:
void AsyncPanZoomController::ZoomToRect(const ZoomTarget& aZoomTarget,
const uint32_t aFlags) {
+ std::cout << __PRETTY_FUNCTION__ << std::endl;
CSSRect rect = aZoomTarget.targetRect;
if (!rect.IsFinite()) {
NS_WARNING("ZoomToRect got called with a non-finite rect; ignoring...");
@@ -6047,6 +6050,10 @@ void AsyncPanZoomController::ZoomToRect(
endZoomToMetrics.SetVisualScrollOffset(rect.TopLeft());
endZoomToMetrics.RecalculateLayoutViewportOffset();
+ std::cout << "Metrics().GetZoom(): " << Metrics().GetZoom()
+ << ", endZoomToMetrics.GetZoom(): " << endZoomToMetrics.GetZoom()
+ << std::endl;
+
StartAnimation(new ZoomAnimation(
*this, Metrics().GetVisualScrollOffset(), Metrics().GetZoom(),
endZoomToMetrics.GetVisualScrollOffset(), endZoomToMetrics.GetZoom()));
Reporter | ||
Comment 6•1 year ago
•
|
||
Ok, so endZoomToMetrics.GetZoom()
being 1 explains why no zooming occurs. Next, let's see how that comes about:
- Is
aZoomTarget.targetRect
reasonable? If the focused element is an input field, I would expect it to be the bounding box of the input field. - If so, what prevents the target zoom from being something larger that would zoom in on that rect and centre it on the screen?
- Perhaps
mZoomConstraints.mMaxZoom
fails to reflect themaximum-scale=2
for some reason?
- Perhaps
Assignee | ||
Comment 7•1 year ago
•
|
||
(In reply to Botond Ballo [:botond] from comment #6)
Ok, so
endZoomToMetrics.GetZoom()
being 1 explains why no zooming occurs. Next, let's see how that comes about:
- Is
aZoomTarget.targetRect
reasonable? If the focused element is an input field, I would expect it to be the bounding box of the input field.- If so, what prevents the target zoom from being something larger that would zoom in on that rect and centre it on the screen?
- Perhaps
mZoomConstraints.mMaxZoom
fails to reflect themaximum-scale=2
for some reason?
0:13.94 GECKO(48853) void mozilla::layers::AsyncPanZoomController::ZoomToRect(const mozilla::layers::ZoomTarget &, const uint32_t)
0:13.94 GECKO(48853) mZoomConstraints.mMaxZoom: 10
0:13.94 GECKO(48853) aZoomTarget.targetRect: (x=-7, y=8, w=1294, h=200)
0:13.94 GECKO(48853) Metrics().GetZoom(): 1, endZoomToMetrics.GetZoom(): 1
Is mZoomConstraints.mMaxZoom
supposed to be 10
going into ZoomToRect()
? Is the 2
multiplied by a factor somewhere after it's read? My viewport tag is <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1, maximum-scale=2, user-scalable=no" />
.
Assignee | ||
Comment 8•1 year ago
|
||
This is interesting, I had previously just set dom.meta-viewport.enabled
to true
manually in the browser and just ran the test (and mZoomConstraints.mMaxZoom
was 10
). I've now put this in test_group_zoomToFocusedInput.html: {"file": "helper_zoomToFocusedInput_nozoom2.html", "prefs": [["dom.meta-viewport.enabled", true]]},
, and I get:
1:29.16 GECKO(3447) mZoomConstraints.mMaxZoom: 1
Neither case reflects the value in my test (maximum-scale=2
). Quite confusing.
Reporter | ||
Comment 9•1 year ago
|
||
(In reply to Razvan Cojocaru from comment #8)
This is interesting, I had previously just set
dom.meta-viewport.enabled
totrue
manually in the browser and just ran the test (andmZoomConstraints.mMaxZoom
was10
).
This doesn't work because prefs are stored in the profile directory, and ./mach mochitest
creates a temporary profile directory in /tmp
, while ./mach run
uses a profile directory in the objdir which persists across runs; so prefs set during ./mach run
will not be visible to ./mach mochitest
.
So the test actually ran with dom.meta-viewport.enaled=false
(the default), the meta viewport tag wasn't processed, and the default zoom constraints was used which has a max zoom of 10.
I've now put this in test_group_zoomToFocusedInput.html:
{"file": "helper_zoomToFocusedInput_nozoom2.html", "prefs": [["dom.meta-viewport.enabled", true]]},
,
Yep, this is the way to do it.
and I get:
1:29.16 GECKO(3447) mZoomConstraints.mMaxZoom: 1
Neither case reflects the value in my test (
maximum-scale=2
). Quite confusing.
I wonder if the user-scalable=no
forces the max zoom to be clamped to 1. Does the max zoom change to 2 if you remove the user-scalable=no
?
Reporter | ||
Comment 10•1 year ago
|
||
(In reply to Botond Ballo [:botond] from comment #9)
I've now put this in test_group_zoomToFocusedInput.html:
{"file": "helper_zoomToFocusedInput_nozoom2.html", "prefs": [["dom.meta-viewport.enabled", true]]},
,Yep, this is the way to do it.
(An alternative way to do it as a one-off is ./mach mochitest --setpref pref=value
.)
Assignee | ||
Comment 11•1 year ago
•
|
||
(In reply to Botond Ballo [:botond] from comment #9)
I wonder if the
user-scalable=no
forces the max zoom to be clamped to 1. Does the max zoom change to 2 if you remove theuser-scalable=no
?
It does apparently, yes. But the test still passes. And furthermore, isn't the test supposed to fail with user-scalable=no
(isn't the issue about how user-scalable=no
is not taken into account), or am I misunderstanding it?
1:38.84 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: got apz-flush-done in child proc
1:38.85 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: done promiseFocus
1:38.86 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: done promiseAllPaintsDone
1:38.86 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
1:38.89 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
1:38.89 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: all done
1:39.09 PASS helper_zoomToFocusedInput_nozoom2.html | The initial_resolution is 1, which is some sane value
1:39.72 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
1:39.72 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
1:39.76 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
1:39.77 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
1:39.79 PASS helper_zoomToFocusedInput_nozoom2.html | focusing input did not change resolution 1
1:39.80 GECKO(5832) void mozilla::layers::AsyncPanZoomController::ZoomToRect(const mozilla::layers::ZoomTarget &, const uint32_t)
1:39.80 GECKO(5832) mZoomConstraints.mMaxZoom: 2
1:39.80 GECKO(5832) aZoomTarget.targetRect: (x=-7, y=8, w=1294, h=200)
1:39.80 GECKO(5832) Metrics().GetZoom(): 1, endZoomToMetrics.GetZoom(): 1
1:39.81 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
1:39.82 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
1:40.15 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
1:40.15 GECKO(5832) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
1:40.18 PASS helper_zoomToFocusedInput_nozoom2.html | zoomToFocusedInput input did not change resolution 1
Reporter | ||
Comment 12•1 year ago
|
||
(In reply to Razvan Cojocaru from comment #11)
(In reply to Botond Ballo [:botond] from comment #9)
I wonder if the
user-scalable=no
forces the max zoom to be clamped to 1. Does the max zoom change to 2 if you remove theuser-scalable=no
?It does apparently, yes.
Interesting!
This is good news -- I believe it means that user-scalable=no
is already working as intended (i.e. it successfully prevents zoom-to-focused-input).
I guess this part of the bug was filed based on a misunderstanding. (In bug 1738696, the reporter initially tried user-scalable=no
alone. I suggested using maximum-scale=1
as a workaround, which also didn't work due to a regression. After we fixed the regression, I thought there was a remaining issue affecting user-scalable=no
, but I guess it has been the same regression affecting that too.)
So, for this part of the bug, maybe we can just land a test that uses user-scalable=no
and asserts that we don't zoom in?
(In addition, I believe the second part of the bug related to touch-action
remains valid.)
But the test still passes.
This part we should investigate further -- the test that we land should cause zooming if the user-scalable=no
is removed (otherwise, it's not actually testing that it's the presence of user-scalable=no
that's preventing the zooming, not something else).
Reporter | ||
Comment 13•1 year ago
|
||
aZoomTarget.targetRect: (x=-7, y=8, w=1294, h=200)
This is pretty wide. The zoom-to-rect logic is mostly based on zooming in such that the target rect fills the width of the viewport, so if it's already very wide we may not zoom.
Looking at the test, the reason for the large width is the width:100%;
on this line, in the input element's style. I guess this was necessary to test the scenario that helper_zoomToFocusedInput_nozoom.html
was intended to exercise (which was more specific and related to the dynamic toolbar), but it's not necessary here -- we can probably just remove both the width
and height
and use an input element with the default size.
Assignee | ||
Comment 14•1 year ago
|
||
(In reply to Botond Ballo [:botond] from comment #13)
aZoomTarget.targetRect: (x=-7, y=8, w=1294, h=200)
This is pretty wide. The zoom-to-rect logic is mostly based on zooming in such that the target rect fills the width of the viewport, so if it's already very wide we may not zoom.
Looking at the test, the reason for the large width is the
width:100%;
on this line, in the input element's style. I guess this was necessary to test the scenario thathelper_zoomToFocusedInput_nozoom.html
was intended to exercise (which was more specific and related to the dynamic toolbar), but it's not necessary here -- we can probably just remove both thewidth
andheight
and use an input element with the default size.
Still passing:
0:12.70 PASS Starting subtest helper_zoomToFocusedInput_nozoom2.html
0:13.38 GECKO(9003) WaitUntilApzStable: flushed APZ repaints in parent proc, waiting for callback...
0:13.39 GECKO(9003) WaitUntilApzStable: APZ flush done in parent proc
0:13.39 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: got apz-flush-done in child proc
0:13.39 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: done promiseFocus
0:13.41 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: done promiseAllPaintsDone
0:13.41 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:13.43 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:13.43 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | WaitUntilApzStable: all done
0:13.45 PASS helper_zoomToFocusedInput_nozoom2.html | The initial_resolution is 1, which is some sane value
0:13.51 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:13.62 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:13.65 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:13.67 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:13.69 PASS helper_zoomToFocusedInput_nozoom2.html | focusing input did not change resolution 1
0:13.69 GECKO(9003) void mozilla::layers::AsyncPanZoomController::ZoomToRect(const mozilla::layers::ZoomTarget &, const uint32_t)
0:13.69 GECKO(9003) mZoomConstraints.mMaxZoom: 2
0:13.70 GECKO(9003) aZoomTarget.targetRect: (x=-7, y=8, w=222, h=29)
0:13.70 GECKO(9003) Metrics().GetZoom(): 1, endZoomToMetrics.GetZoom(): 1
0:13.70 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:13.72 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:14.04 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: Flushed APZ repaints, waiting for callback...
0:14.05 GECKO(9003) helper_zoomToFocusedInput_nozoom2.html | PromiseApzRepaintsFlushed: APZ flush done
0:14.06 PASS helper_zoomToFocusedInput_nozoom2.html | zoomToFocusedInput input did not change resolution 1
0:14.08 GECKO(9003) MEMORY STAT vsizeMaxContiguous not supported in this build configuration.
0:14.09 GECKO(9003) MEMORY STAT | vsize 2409MB | residentFast 164MB | heapAllocated 13MB
0:14.21 TEST_END: Test OK. Subtests passed 9/9. Unexpected 0
Reporter | ||
Comment 15•1 year ago
|
||
The next step to investigate would be to step through the logic in ZoomToRect()
to see why endZoomToMetrics.GetZoom()
still ends up as 1. It's set based on the targetZoom
variable here.
Assignee | ||
Comment 16•1 year ago
|
||
(In reply to Botond Ballo [:botond] from comment #15)
The next step to investigate would be to step through the logic in
ZoomToRect()
to see whyendZoomToMetrics.GetZoom()
still ends up as 1. It's set based on thetargetZoom
variable here.
It becomes 1
in the if (aFlags & PAN_INTO_VIEW_ONLY)
branch here. Up until that point it's 5.95349
. It's initially set here (the if (aFlags & DISABLE_ZOOM_OUT)
branch is taken as well).
Reporter | ||
Comment 17•1 year ago
•
|
||
(In reply to Razvan Cojocaru from comment #16)
It becomes
1
in theif (aFlags & PAN_INTO_VIEW_ONLY)
branch here.
Ah, interesting!
It turns out this is another artifact of running the test on desktop, which I didn't realize before. This flag is set here if the pref formhelper.autozoom
is set to false, and this pref only defaults to true on mobile. So this is something else that needs to be flipped when running the test on desktop.
Assignee | ||
Comment 18•1 year ago
|
||
(In reply to Botond Ballo [:botond] from comment #17)
(In reply to Razvan Cojocaru from comment #16)
It becomes
1
in theif (aFlags & PAN_INTO_VIEW_ONLY)
branch here.Ah, interesting!
It turns out this is another artifact of running the test on desktop, which I didn't realize before. This flag is set here if the pref
formhelper.autozoom
is set to false, and this pref only defaults to true on mobile. So this is something else that needs to be flipped when running the test on desktop.
Right. Now it's getting set to 1
here.
Assignee | ||
Comment 19•1 year ago
|
||
zoomAtDefaultScale.scale
appears to be 1
, which is the same as currentZoom.scale
, FWIW.
Reporter | ||
Comment 20•1 year ago
|
||
(In reply to Razvan Cojocaru from comment #18)
Now it's getting set to
1
here.
Looking at some code history to understand the purpose of those branches, it seems that in bug 1250614 we limited zoom-to-focused-input to observe a maximum zoom level of 1x.
So basically, zoom-to-focused-input cannot be used to zoom from e.g. 1x to 2x, only from e.g. 0.5x to 1x. (This is geared towards sites that are not optimized for mobile but loaded on mobile. Such sites are often laid out into a default viewport width of 980px, which is then scaled down into a narrower screen width e.g. 320px, resulting in an initial zoom level < 1.)
So, to successfully trigger zooming, we should change our meta-viewport parameters from initial-scale=1, minimum-scale=1, maximum-scale=2
to something like initial-scale=0.5, minimum-scale=0.5, maximum-scale=1
.
I took a look at our other helper_zoomToFocusedInput_*
tests to see if they are affected by this issue, and it turns out none of them are actually testing successful zooming in -- they're either testing that we don't zoom in, or just testing the scroll-into-view part of the behaviour.
If you're amenable, I think there would be value in adding two tests:
- One without
user-scalable=no
, where we assert that we do zoom in - One with
user-scalable=no
, where we assert that we don't zoom in
Assignee | ||
Comment 21•1 year ago
|
||
Thanks! The test is now behaving as expected (with minimum-scale=0.5, maximum-scale=1
). user-scalable=no
continues to work properly, so I'm confirming that that particular problem has indeed already been solved and is no longer current.
Sure, no problem with adding two tests. I can probably just add that a separate first patch and already submit it later today (and push to try).
Assignee | ||
Comment 22•1 year ago
|
||
On second thought, shouldn't we just add a single test, the one that tests that we do zoom in with user-scalable=yes
, and modify the helper_zoomToFocusedInput_nozoom.html test with minimum-scale=0.5, maximum-scale=1
etc. (since it doesn't appear to test anything now, if I understand this correctly), and also call it with "prefs": [["dom.meta-viewport.enabled", true], ["formhelper.autozoom", true]]
?
Reporter | ||
Comment 23•1 year ago
•
|
||
(In reply to Razvan Cojocaru from comment #22)
and modify the helper_zoomToFocusedInput_nozoom.html [...] (since it doesn't appear to test anything now, if I understand this correctly)
helper_zoomToFocusedInput_nozoom.html is a regression test for bug 1738696, whose diagnosis is related to the "dynamic toolbar" (Android address bar that can be hidden by scrolling) creating a small discrepancy between two quantities that allowed zoom-to-focused-input to trigger a small amount of zooming in violation of maximum-scale
.
That, in combination with this comment, leads me to believe that this test is testing something (fairly specific), even if we can't trigger the affected scenario very easily, and so we should leave it as is. We can rename it to helper_zoomToFocusedInput_nozoom_bug1738696.html to better reflect that it's testing a specific scenario, as opposed to a more generic "no zooming" scenario.
Assignee | ||
Comment 24•1 year ago
|
||
Also rename helper_zoomToFocusedInput_nozoom.html to
helper_zoomToFocusedInput_nozoom_bug1738696.html, since it
appears to test behaviour specific to bug 1738696.
Updated•1 year ago
|
Reporter | ||
Comment 25•1 year ago
|
||
Adding leave-open keyword so the merging of the test patch doesn't close the bug.
Comment 26•1 year ago
|
||
Pushed by bballo@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/1d4f355a9db6 Add zoom-to-focused-input mochitests for user-scalable={yes,no}. r=botond
Comment 27•1 year ago
|
||
bugherder |
Assignee | ||
Comment 28•1 year ago
•
|
||
So now that the first part of the bug (user-scalable=no
) appears to have been covered, any specific pointers on how to approach the touch-action
part (I'm inclined to modify the helper_zoomToFocusedInput_(no)zoom.html mochitests but remove the user-scalable
part and see how touch-action
works with them)? And specific parts of the code I should be looking at (so far I found this)?
Reporter | ||
Comment 29•1 year ago
|
||
(In reply to Razvan Cojocaru from comment #28)
any specific pointers on how to approach the
touch-action
part (I'm inclined to modify the helper_zoomToFocusedInput_(no)zoom.html mochitests but remove theuser-scalable
part and see howtouch-action
works with them)?
Yeah, writing a mochitest that fails is a good starting point.
The test can have a <div>
with touch-action: none
, and an <input>
element inside it, and assert that zoom-to-focused-input on that input element does not zoom in.
For good measure, we can give the test another <div>
with default touch-action
(auto
), and another <input>
element inside that, and assert that there we do zoom in (to make sure that the presence of a touch-action: none
element on the page does not interfere with the ability to zoom elsewhere).
And specific parts of the code I should be looking at (so far I found this)?
I think it's easiest to put this logic in the content side, in nsDOMWindowUtils::ZoomToFocusedInput()
. Once we determine the focused element, we can check if the touch-action that applies to that element allows double-tap zoom. To do this, we can call the function GetAllowedTouchBehaviorForPoint() (we can expose this in TouchActionHelper.h) on the midpoint of the element's bounding rect, and check if the returned touch behaviour flags contain AllowedTouchBehavior::DOUBLE_TAP_ZOOM
.
Reporter | ||
Comment 30•1 year ago
|
||
(In reply to Botond Ballo [:botond] from comment #29)
and check if the returned touch behaviour flags contain
AllowedTouchBehavior::DOUBLE_TAP_ZOOM
.
Adding a bit of context here since the relation to double-tap zoom may not be obvious:
When touch-action
was standardized, the manipulation
value was added to give page authors a way to allow touch gestures that directly manipulate the page content (i.e. cause it to move along with / in the direction of the fingers -- namely, panning and pinching) but not less direct behaviours like double-tap zoom (which are only allowed with auto
).
Since double-tap zoom was the only behaviour in this second category at the time, we used DOUBLE_TAP_ZOOM
as the name of the flag used to indicate that behaviours in this category should be allowed.
With this change, we will be adding zoom-to-focused-input as another behaviour in this category alongside double-tap zoom. Perhaps it would be appropriate to rename the flag from DOUBLE_TAP_ZOOM
to something more general as well (though I don't have a great idea for a name at the moment).
Assignee | ||
Comment 31•1 year ago
|
||
Comment 32•1 year ago
|
||
Pushed by bballo@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/c6bc2ad84f28 Allow controlling zoom-to-focused-input behaviour using `touch-action`. r=botond
Comment 33•1 year ago
|
||
bugherder |
Assignee | ||
Comment 34•1 year ago
|
||
Should we remove leave-open
?
Reporter | ||
Comment 35•1 year ago
|
||
(In reply to Razvan Cojocaru from comment #34)
Should we remove
leave-open
?
Indeed, thanks for the reminder.
Assignee | ||
Comment 37•1 year ago
|
||
(In reply to Botond Ballo [:botond] from comment #36)
And thank you for fixing!
Happy to do it, thanks for the prompt and very helpful review!
Description
•