| <!DOCTYPE html> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <style> |
| html { |
| font-family: Ahem; |
| font-size: 10px; |
| } |
| #testArea { |
| position: absolute; |
| right: 50px; |
| top: 50px; |
| } |
| #target { |
| width: 10px; |
| height: 10px; |
| } |
| #frame { |
| width: 100px; |
| height: 100px; |
| margin-top: 30px; |
| } |
| </style> |
| <body onload="runTest();"> |
| <div id=testArea> |
| <div id=target></div> |
| <iframe id=frame srcdoc='<body style="margin: 5px"><iframe width=75 |
| height=75></iframe></body>'></iframe> |
| </div> |
| <script src="../../resources/js-test.js"></script> |
| <script src="../../resources/gesture-util.js"></script> |
| <script> |
| setPrintTestResultsLazily(); |
| jsTestIsAsync = true; |
| |
| if (window.internals) |
| internals.settings.setViewportEnabled(true); |
| |
| var unique_event_id = 1; |
| description("Count how many hit tests are required for various event " + |
| "scenarios. Hit tests can be expensive and it's often tempting " + |
| "to add more. These values should only ever be changed to go " + |
| "down, not up."); |
| |
| function hitTestCountDelta(doc) |
| { |
| var lastCount = 0; |
| if ('lastHitTestCount' in doc) |
| lastCount = doc.lastHitTestCount; |
| var newCount = internals.hitTestCount(doc); |
| doc.lastHitTestCount = newCount; |
| return newCount - lastCount; |
| } |
| |
| function hitTestCacheHitsDelta(doc) |
| { |
| var lastCount = 0; |
| if ('lastHitTestCacheHits' in doc) |
| lastCount = doc.lastHitTestCacheHits; |
| var newCount = internals.hitTestCacheHits(doc); |
| doc.lastHitTestCacheHits = newCount; |
| return newCount - lastCount; |
| } |
| |
| async function logCounts(label, documents, eventSenderFunction) |
| { |
| if (eventSenderFunction) { |
| if (label == 'TouchScroll' || label == 'MouseWheelScroll') |
| await eventSenderFunction(); |
| else |
| eventSenderFunction(); |
| } |
| |
| var countStr = ''; |
| for(var i = 0; i < documents.length; i++) { |
| var hits = hitTestCountDelta(documents[i]); |
| var cacheHits = hitTestCacheHitsDelta(documents[i]); |
| countStr += ' ' + (hits - cacheHits) + "+" + cacheHits; |
| } |
| |
| debug(label + ':' + countStr); |
| } |
| |
| function clearCounts(documents) |
| { |
| for(var i = 0; i < documents.length; i++) { |
| documents[i].lastHitTestCount = internals.hitTestCount(documents[i]); |
| documents[i].lastHitTestCacheHits = |
| internals.hitTestCacheHits(documents[i]); |
| } |
| } |
| |
| async function sendEvents(targetX, targetY, documents) |
| { |
| logCounts('Initial', documents); |
| |
| logCounts('MouseMove', documents, function() { |
| eventSender.mouseMoveTo(targetX, targetY); |
| }); |
| |
| logCounts('MouseDown', documents, function() { |
| eventSender.mouseDown(); |
| }); |
| |
| logCounts('MouseUp', documents, function() { |
| eventSender.mouseUp(); |
| }); |
| |
| logCounts('Wheel', documents, function() { |
| eventSender.mouseScrollBy(0, 5, false, false, 0, false); |
| }); |
| |
| logCounts('TouchStart', documents, function() { |
| eventSender.addTouchPoint(targetX, targetY, 15, 15); |
| eventSender.touchStart(unique_event_id + 1); |
| }); |
| |
| logCounts('TouchMove', documents, function() { |
| eventSender.updateTouchPoint(0, targetX + 1, targetY, 15, 15); |
| eventSender.touchMove(unique_event_id + 2); |
| }); |
| |
| logCounts('TouchEnd', documents, function() { |
| eventSender.releaseTouchPoint(0); |
| eventSender.touchEnd(unique_event_id + 3); |
| }); |
| |
| logCounts('GestureTapDown', documents, function() { |
| eventSender.gestureTapDown(targetX, targetY, 30, 30, |
| unique_event_id + 1); |
| }); |
| |
| logCounts('GestureShowPress', documents, function() { |
| eventSender.gestureShowPress(targetX, targetY, 30, 30, |
| unique_event_id + 3); |
| }); |
| |
| logCounts('GestureTap', documents, function() { |
| // We don't want to tap on an existing selection so we clear |
| // selections. |
| window.getSelection().empty(); |
| eventSender.gestureTap(targetX, targetY, 1, 30, 30, |
| unique_event_id + 3); |
| }); |
| |
| logCounts('GestureTapCancel', documents, function() { |
| eventSender.gestureTapCancel(targetX, targetY); |
| }); |
| |
| logCounts('DoubleFingerTouch', documents, function() { |
| eventSender.addTouchPoint(targetX+1, targetY+1, 15, 15); |
| eventSender.touchStart(); |
| eventSender.addTouchPoint(targetX+4, targetY+4, 15, 15); |
| eventSender.touchStart(); |
| eventSender.releaseTouchPoint(0); |
| eventSender.releaseTouchPoint(1); |
| eventSender.touchEnd(); |
| }); |
| |
| // smoothScrollWithXY function returns a Promise object, so we use await |
| // operator to wait for a Promise. eventSender does not need await. |
| // smoothScrollWithXY with touch input simulates a real touch scroll, which |
| // consists of a sequence of events, such as touch start, tap down, tap |
| // cancel, scroll begin and these events will do a hit-test, which causes |
| // the hit test count greater than 1. |
| await logCounts('TouchScroll', documents, async function() { |
| await smoothScrollWithXY(0, 1, targetX, targetY, |
| GestureSourceType.TOUCH_INPUT, SPEED_INSTANT); |
| }); |
| |
| // smoothScrollWithXY function returns a Promise object, so we use await |
| // operator to wait for a Promise. eventSender does not need await. |
| // smoothScrollWithXY with mouse input simulates a real touch scroll, which |
| // consists of a sequence of events, such as mouse wheel, scroll begin, and |
| // these events will do a hit-test, which causes the hit test count greater |
| // than 1. |
| await logCounts('MouseWheelScroll', documents, async function() { |
| await smoothScrollWithXY(0, 1, targetX, targetY, |
| GestureSourceType.Mouse_INPUT, SPEED_INSTANT); |
| }); |
| |
| unique_event_id = unique_event_id + 3; |
| // Leap forward to reset click count, so mouse down will not generate a |
| // double click. |
| eventSender.leapForward(1000); |
| } |
| |
| async function runTestForDocuments(targetX, targetY, documents) |
| { |
| clearCounts(documents); |
| await sendEvents(targetX, targetY, documents); |
| } |
| |
| function centerOf(element) { |
| var targetRect = element.getBoundingClientRect(); |
| return { |
| x: targetRect.left + targetRect.width / 2, |
| y: targetRect.top + targetRect.height / 2 |
| }; |
| } |
| |
| async function runTest() { |
| debug('Event on a simple div'); |
| debug('---------------------'); |
| var point = centerOf(document.getElementById('target')); |
| await runTestForDocuments(point.x, point.y, [document]); |
| debug(''); |
| |
| debug('Event entirely over one iframe nested in another'); |
| debug('---------------------'); |
| var frame = document.getElementById('frame'); |
| var doc2 = frame.contentDocument; |
| var doc3 = doc2.querySelector('iframe').contentDocument; |
| var point = centerOf(frame); |
| await runTestForDocuments(point.x, point.y, [document, doc2, doc3]); |
| debug(''); |
| |
| debug('Event near boundary of two iframes'); |
| debug('---------------------'); |
| var rect = frame.getBoundingClientRect(); |
| await runTestForDocuments(rect.left + 3, rect.top + 3, |
| [document, doc2, doc3]); |
| debug(''); |
| |
| internals.settings.setViewportEnabled(false); |
| debug('Event on a simple div (desktop viewport)'); |
| debug('---------------------'); |
| var point = centerOf(document.getElementById('target')); |
| await runTestForDocuments(point.x, point.y, [document]); |
| debug(''); |
| internals.settings.setViewportEnabled(true); |
| finishJSTest(); |
| } |
| </script> |
| </body> |