www.temu.com - Scrolls the page when dragging the captcha elements
Categories
(Web Compatibility :: Site Reports, defect, P1)
Tracking
(Webcompat Priority:P1, Webcompat Score:9)
People
(Reporter: ctanase, Unassigned)
References
()
Details
(Keywords: webcompat:needs-diagnosis, webcompat:site-report, Whiteboard: [webcompat-source:web-bugs][webcompat:sightline][webcompat:japan][webcompat:core])
User Story
platform:android impact:site-broken configuration:general affects:all branch:release diagnosis-team:performance user-impact-score:1500
Attachments
(1 file, 1 obsolete file)
|
1.49 MB,
video/mp4
|
Details |
Environment:
Operating system: Android 16
Firefox version: Firefox Mobile 149.0/151
Steps to reproduce:
- Go to https://www.temu.com/pl/ul/kuiper/un3.html?_bg_fs=1
- Wait for the captcha to appear.
- Drag the elements on their corresponding places. (unless a different type of captcha gets displayed)
Expected Behavior:
The page does not get scrolled.
Actual Behavior:
The page gets scrolled in the background.
Notes:
- The experience is worse if "Pull to refresh" is enabled, it won't let you drag the elements in most cases
- Reproduces regardless of the status of ETP
- Reproduces in firefox-nightly, and firefox-release
- Does not reproduce in chrome
Created from https://github.com/webcompat/web-bugs/issues/215958
| Reporter | ||
Comment 1•2 months ago
|
||
Updated•2 months ago
|
Updated•2 months ago
|
Updated•2 months ago
|
Comment 3•2 months ago
|
||
Geez, while I was poking the site, something has been changed. I can no longer see the capcha.
What I've noticed is that the site adds an active touchmove event handler dynamically and does preventDefault() in the handler. If the event listener is registered in a passive event handler, that's bug 1839095.
Comment 4•2 months ago
|
||
Can someone try the patch on bug 1839095 to see whether this bug can be solved by the patches? The patches are not perfect, in the test case in bug 1839095 comment 0 if you move your finger quickly it will not prevent scrolling though, if you move the finger slowly, I mean, if there's enough time in between the touch-start and the first touch-move event, it will prevent scrolling. So if the temu site does something similar to bug 1839095, the patches should work.
Comment 5•2 months ago
|
||
Here is a Pernosco recording of the bug occurring in RDM, in a build with the bug 1839095 patches applied. I've added two notebook entries, the first is a place where APZ received a preventDefault=1 content response for a touch input block, and the second is a place where APZ nonetheless scrolls in response to an event in that input block.
Comment 6•2 months ago
|
||
I've added a new note where an active touchmove event listener is setup. In the JS call stack at the moment, I do see react string so I suspect the event listener is not setup directly in a passive touchstart event listener just like bug 1839095, rather it's probably deferred to somewhere else so that the patch for bug 1839095 doesn't help.
Comment 7•2 months ago
|
||
Note for references how I reached to the active touchmove event listener;
- Searched executions of "mozilla::dom::EventTarget::AddEventListener" with aType=="touchmove"
- there are a bunch of executions including the parent process
- On every execution I did
p ((nsIURI*)((mozilla::dom::NodeInfo*)((nsINode*)this)->mNodeInfo)->mDocument->mDocumentURI)->GetSpecOrDefault()in the debugger to see the URL - In the case of temu.com I did
p ((mozilla::dom::AddEventListenerOptions)aOptions.mValue.mAddEventListenerOptions.mStorage).mPassiveto see whether passive is false or not
Comment 8•2 months ago
|
||
Comment 9•2 months ago
|
||
I have further diagnosis on the first pernosco session. I found an interesting fact: Before APZ received the preventDefault-ed information there were 3 touch events, a touch-start, a touch-move and a touch-move. I checked the WR hit test results on both touch-move events, in both cases the result are eVisibleToHitTest. So APZ had not received eApzAwareListeners at the moment. I suspect this is kinda performance issue on the main-thread. If the main-thread had sent the up-to-date event listener setup within a reasonable time span, the patch for bug 1839095 should just work.
Comment 10•2 months ago
•
|
||
In the new pernosco session in comment 8, there were 4 active touchmove event listeners which were registered in one or two passive touchstart event handlers. Since the active touchmove event listeners were registered, this code
result += CompositorHitTestFlags::eApzAwareListeners;
didn't run at all. That's the reason why APZ didn't prevent scrolling even though APZ had received the preventDefault=1.
So the next question is why result += CompositorHitTestFlags::eApzAwareListeners; was not executed.
EDIT: This was wrong. The line was executed. On pernosco the break point set to the line somehow doesn't break.
Comment 11•2 months ago
•
|
||
Okay, what I've found:
- The
eApzAwareListeners;code was not executed in between when APZ received the touch-start and when APZ received the first touch-move - During the above time span, 4 active touchmove event listeners were setup
- when the first touch-move arrived at APZCTreeManager::ProcessTouchInput the hit results were:
(10, eVisibleToHitTest)
( 9, eVisibleToHitTest)
( 9, eVisibleToHitTest)
( 0, eVisibleToHitTest)
- when the second touch-move event arrived at APZCTreeManager::ProcessTouchInput, I manually did a hit-testing by:
set $pt = (wr::WorldPoint*)malloc(8)
set ((float*)$pt)[0] = 634.0
set ((float*)$pt)[1] = 341.0
call $wr->HitTest(*$pt)
- Then the results had eApzAwareListeners, so the active touchmove event listeners information had arrived:
(10, eVisibleToHitTest | eApzAwareListeners)
( 9, eVisibleToHitTest | eApzAwareListeners)
( 9, eVisibleToHitTest | eApzAwareListeners)
( 0, eVisibleToHitTest | eApzAwareListeners) <= these scrollId:0 results might be irrelevant
( 0, eVisibleToHitTest)
So from what I can tell is that this bug is a sort of performance issue on the main-thread. If the up-to-date information can be arrived in APZ within a reasonable time span, the patches for bug 1839095 should have been fixed this bug too.
With that I am setting bug 1839095 in this bug's dependency list, also changing the diagnosis team from APZ to Performance.
Comment 12•2 months ago
•
|
||
Botond, in the meantime, would you mind taking a performance profile result? It would be nice to have I think.
Updated•2 months ago
|
Comment 13•2 months ago
|
||
(In reply to Hiroyuki Ikezoe (:hiro) from comment #12)
Botond, in the meantime, would you mind taking a performance profile result? It would be nice to have I think.
Sure, here is a profile taken with the WebCompat preset.
You can see in the screenshots in the 6-9s interval that as the captcha element is being dragged, the page behind the dialog is also scrolling.
Comment 14•2 months ago
•
|
||
(I didn't mean to edit the "User Story" field; the browser just seems to remember some stale state sometimes. Reverted now.)
Comment 15•2 months ago
|
||
As far as I can tell when an active touchmove event listener is registered Chrome uses this SetEventListenerProperties to inform it to the compositor, which is an independent route from the route where the layer information (DOM structure or some such) is informed to the compositor.
On the other hand in Gecko we inform the both info altogether via triggering a schedule paint.
This difference may have resulted the behavior difference between Chrome and Firefox.
It seems to me that the Chrome's machinery definitely has a race where the compositor hit-testing fails, and Claude told me there is, but I haven't confirmed it yet.
Comment 16•2 months ago
•
|
||
(In reply to Hiroyuki Ikezoe (:hiro) from comment #15)
It seems to me that the Chrome's machinery definitely has a race where the compositor hit-testing fails, and Claude told me there is, but I haven't confirmed it yet.
Now I am sure that there's no race. From the touch event spec:
target
The EventTarget on which the touch point started when it was first placed on the surface, even if the touch point has since moved outside the interactive area of that element.
So browsers need to use the target of the initial touch-start event on subsequent touch events.
Comment 17•2 months ago
|
||
I am posting a profile analysis by Claude Code:
Bug 2031963 — profile analysis (build with bug 1839095 patches applied)
Profile: https://profiler.firefox.com/public/psrvytw7h8xgx3dpgqertk8gjvxtsma00r7vyag/calltree/?thread=b
(WebCompat preset, Firefox Nightly 152 on Android 13.)
The profile confirms the diagnosis from comments 11 and 15: APZ in the GPU
process has already received and processed several touchmoves before the
content process can communicate the newly-registered active touchmove
listeners through the paint pipeline.
Timeline of the gesture (Web Content thread t-11 vs GPU thread t-7)
| Time | Where | Event |
|---|---|---|
| 5.792s | content | touchstart dispatch begins (32.6 ms duration) |
| 5.794s | GPU/APZ | 1st PAPZInputBridge::Msg_ReceiveMultiTouchInputEvent (touchstart) |
| 5.802–5.823s | content | Perform microtasks (21.8 ms) — React commit + listener registration |
| 5.805s, 5.817s | GPU/APZ | 2nd, 3rd touch events arrive — still no eApzAwareListeners |
| ~5.823s | content | EventTarget.addEventListener for touchmove runs inside the touchstart handler (visible in bottom-up tree under static.kwcdn.com!K/y and static.kwcdn.com!K/v) → triggers SchedulePaint |
| 5.825s | content | touchstart returns; RefreshDriverTick + ViewManagerFlush Transaction 1504 sent to GPU |
| 5.827–5.883s | GPU/APZ | 4 more Msg_ReceiveMultiTouchInputEvent arrive |
| 5.829s | content | 35.5 ms dom::PostMessageRunnable/message handler runs (more main-thread JS work) |
| 5.865s | content | PCompositorBridge::Msg_DidComposite for tx 1504 |
| 6.007s | content | PanZoom:StateChange — APZ has already started panning |
| 6.008s | content | First PBrowser::Msg_RealTouchMoveEvent2 reaches main thread, priority InputLow (3) (subsequent ones are InputHighest (8)) — APZ has downgraded the channel because it's already scrolling |
Why the patches from bug 1839095 don't help here
Per comment 11, APZ's hit-test result for the touch block is captured at
touchstart and used for the rest of the block. The fix in bug 1839095 relies
on APZ knowing about active touchmove listeners by the time it would otherwise
begin panning. In this profile:
- The site registers active
touchmovelisteners synchronously inside the
touchstart handler (the bottom-up tree showsEventTarget.addEventListener
on the pathtouchstart → … → static.kwcdn.com!K/yandK/v). - The handler itself runs for 32.6 ms — JavaScript-heavy. While it runs,
APZ in the GPU process is already receiving touchmoves (4 events in the
GPU between 5.794s and 5.838s). - The
SchedulePainttriggered byaddEventListenercannot send a
transaction to WebRender until after the touchstart handler returns. The
first paint commit (tx 1504) goes out at 5.825s and is composited around
5.865s — but APZ has already taken its decision by then. - Top samples for the 5.79–6.01 s window:
R(PostMessage handler, 56% of
active CPU) andtouchstart(31%). All in obfuscated kwcdn JS.
What this points at
This matches Hiro's analysis in comment 15: Gecko's only path to inform APZ
about an eApzAwareListeners change goes through a paint commit + scene
update + WebRender hit-test data refresh. Chrome's
EventHandlerRegistry::SetEventListenerProperties sends listener-property
bitfields to the compositor on a dedicated IPC channel that bypasses the
paint/scene pipeline, so the compositor can update its cc::TouchActionRegion
without waiting for the next paint.
A Gecko fix in the same shape — a direct content→GPU IPC for "this layer now
has an active touchmove/touchstart listener", landing in APZCTreeManager
immediately rather than via WR scene rebuild — would let the patches from
bug 1839095 actually take effect on this site even when the listener is
registered inside the touchstart handler.
-- END OF ANALYSIS --
So Claude suggests a new light weight path to inform eApzAwareListeners from the content to APZ. But I am skeptical about the suggestion. As you can see the timeline table above, at 5.805s 2nd touch event arrived in APZ, ~5.823s in the content SchedulePaint was triggered. It's already late, 20ms or so.
Comment 18•1 month ago
|
||
When a touchstart JS handler dynamically registers a non-passive
touchmove (or similar APZ-aware) listener, APZ doesn't learn about
eApzAwareListeners until the next painted WebRender transaction has
been scene-swapped on the compositor -- ~70 ms after the listener
add on temu.com. The first touchmove arrives at APZ well before
that, the cached touchstart hit-test is reused, and the block stays
committed to async-scroll.
Add a direct content -> APZ IPC (NotifyApzAwareListenerAdded) carrying
the nearest scroll container's ViewID. APZCTreeManager records the
(LayersId, ScrollId) pair under mMapLock; WRHitTester ORs in
eApzAwareListeners when a hit-test result's target APZC equals that
pair or descends from it within the same layers id.
EventListenerManager::ProcessApzAwareEventListenerAdd resolves the
ScrollId via FindIDFor (not FindOrCreateIDFor): if no ViewID has
been assigned yet, or the element has no primary frame / scroll
container ancestor, fall back to the existing SchedulePaint path so
the regular display-list rebuild propagates the flag.
Fast-path entries are kept until the layer tree is removed
(NotifyLayerTreeRemoved). Clearing them in PrepareNodeForLayer would
race against a paint that was in flight when the listener was added.
Add MOZ_LOG=apz.fastpath logging on both sides to trace the flow.
Comment 19•1 month ago
|
||
Comment on attachment 9588270 [details]
WIP: Bug 2031963 - Fast-path notify APZ on non-passive APZ-aware listener registration.
Revision D301665 was moved to bug 2041154. Setting attachment 9588270 [details] to obsolete.
Comment 20•28 days ago
|
||
I can still reproduce the issue in a 20260607212012 Fenix Nightly build, so it seems like this needs more diagnosis.
Comment 21•28 days ago
|
||
Okay, my hypothesis is that the original version of the fast-path notification landed in bug 2041154 was to permissive, thus it has affected on temu.com accidentally. Then the original version was backed out due to bug 2043349 etc. Then the revised version of thefast-path notification is no longer permissive, it works only for a newly setup active touchmove event listener while APZ hasn't received any touchmove events. Thus, it has no longer affected on temu.com.
That matches my analysis in comment 11 (and comment 17).
So I would say, now we need to diagnose why the main-thread in the content process doesn't have a chance to send the notification. I think performance team would be the best team to do an initial diagnosis.
Comment 22•3 days ago
|
||
I managed to see the drag-and-drop type captcha on my Windows touch screen laptop, surprisingly the images are not able to drag with touch at all. I think the site does something different depends on UA string?
I wanted to differentiate this bug from bug 1764177, but as per the above result, we can't.
Also note that I've tried a variety of ways to register preventDefault() touchmove event listeners on Chrome with debugging, as far as I can tell Chrome's behavior is same as ours since bug 2041154. A difference I noticed is that Chrome doesn't prevent scrolling if an active with `once: true} touchmove event listener is registered in a passive touchstart event listener. But Firefox does.
Description
•