<?xml version="1.0"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="800"> <title>Touch input event flow on B2G</title> <g id="arrows"></g> <style type="text/css"><![CDATA[ text { fill: black; text-anchor: middle; white-space: pre-line; font-size: 14px; } rect { fill: none; } line { stroke: black; } .parentinput rect { stroke: black; } text.parentinput { fill: black; text-anchor: start; } .parentmain rect { stroke: orange; } text.parentmain { fill: orange; text-anchor: start; } .parentcompositor rect { stroke: green; } text.parentcompositor { fill: green; text-anchor: start; } .childmain rect { stroke: red; } text.childmain { fill: red; text-anchor: start; } .bothmain rect { stroke: blue; } text.bothmain { fill: blue; text-anchor: start; } ]]></style> <script type="text/javascript"><![CDATA[ var svg = "http://www.w3.org/2000/svg"; var maxY = 0; function breaks(text) { var count = 0; for (var i = text.length - 1; i >= 0; i--) { if (text.charAt(i) == '\n') { count++; } } return count; } function makeAction(text, x, y, thread) { maxY = Math.max(maxY, y); var g = document.createElementNS(svg, "g"); g.setAttribute("class", "action " + thread); g.setAttribute("transform", "translate(" + x + ", " + (y + 30) + ")"); var r = document.createElementNS(svg, "rect"); r.setAttribute("width", "100"); r.setAttribute("height", "40"); var t = document.createElementNS(svg, "text"); t.setAttribute("x", "50"); t.setAttribute("y", 25 - (7 * breaks(text))); t.appendChild(document.createTextNode(text)); g.appendChild(r); g.appendChild(t); return g; } function makeChoice(text, x, y, thread) { maxY = Math.max(maxY, y); var g = document.createElementNS(svg, "g"); g.setAttribute("class", "choice " + thread); g.setAttribute("transform", "translate(" + (x + 15) + ", " + (y + 15) + ")"); var g2 = document.createElementNS(svg, "g"); g2.setAttribute("transform", "rotate(-45, 35, 35)"); var r = document.createElementNS(svg, "rect"); r.setAttribute("width", "70"); r.setAttribute("height", "70"); g2.appendChild(r); var t = document.createElementNS(svg, "text"); t.setAttribute("x", "35"); t.setAttribute("y", 40 - (7 * breaks(text))); t.appendChild(document.createTextNode(text)); g.appendChild(g2); g.appendChild(t); return g; } function makeLabelChoice(label, point) { var t = document.createElementNS(svg, "text"); t.setAttribute("x", point.x); t.setAttribute("y", point.y); t.appendChild(document.createTextNode(label)); return t; } function makeLine(sx, sy, ex, ey) { maxY = Math.max(maxY, sy, ey); var l = document.createElementNS(svg, "line"); l.setAttribute("x1", sx); l.setAttribute("y1", sy); l.setAttribute("x2", ex); l.setAttribute("y2", ey); return l; } function makeArrow(start, end) { var g = document.createElementNS(svg, "g"); g.appendChild(makeLine(start.x, start.y, end.x, end.y)); if (start.x != end.x) { start.x = end.x + (4 * Math.sign(start.x - end.x)); g.appendChild(makeLine(start.x, start.y - 4, end.x, end.y)); g.appendChild(makeLine(start.x, start.y + 4, end.x, end.y)); } else if (start.y != end.y) { start.y = end.y + (4 * Math.sign(start.y - end.y)); g.appendChild(makeLine(start.x - 4, start.y, end.x, end.y)); g.appendChild(makeLine(start.x + 4, start.y, end.x, end.y)); } return g; } function makeVHArrow(start, end) { var g = document.createElementNS(svg, "g"); g.appendChild(makeLine(start.x, start.y, start.x, end.y)); start.y = end.y; g.appendChild(makeArrow(start, end)); return g; } function makeHVArrow(start, end) { var g = document.createElementNS(svg, "g"); g.appendChild(makeLine(start.x, start.y, end.x, start.y)); start.x = end.x; g.appendChild(makeArrow(start, end)); return g; } function makeVHVArrow(start, end, length) { var g = document.createElementNS(svg, "g"); g.appendChild(makeLine(start.x, start.y, start.x, start.y + length)); start.y += length; g.appendChild(makeLine(start.x, start.y, end.x, start.y)); start.x = end.x; g.appendChild(makeArrow(start, end)); return g; } function makeHVHArrow(start, end, length) { var g = document.createElementNS(svg, "g"); g.appendChild(makeLine(start.x, start.y, start.x + length, start.y)); start.x += length; g.appendChild(makeLine(start.x, start.y, start.x, end.y)); start.y = end.y; g.appendChild(makeArrow(start, end)); return g; } function translation(group) { var r = new RegExp("translate\\((\\d+), (\\d+)\\)"); var result = r.exec(group.getAttribute("transform")); return { x: parseInt(result[1]), y: parseInt(result[2]) }; } function isAction(group) { return group.classList.contains("action"); } function isChoice(group) { return group.classList.contains("choice"); } function offset(point, x, y) { point.x += x; point.y += y; return point; } function rightOf(group) { var t = translation(group); if (isAction(group)) { return offset(t, 100, 20); } if (isChoice(group)) { return offset(t, 85, 35); } return t; } function leftOf(group) { var t = translation(group); if (isAction(group)) { return offset(t, 0, 20); } if (isChoice(group)) { return offset(t, -15, 35); } return t; } function topOf(group) { var t = translation(group); if (isAction(group)) { return offset(t, 50, 0); } if (isChoice(group)) { return offset(t, 35, -15); } return t; } function bottomOf(group) { var t = translation(group); if (isAction(group)) { return offset(t, 50, 40); } if (isChoice(group)) { return offset(t, 35, 85); } return t; } function midpoint(start, end) { return { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 }; } function makeLegend(label, thread) { var t = document.createElementNS(svg, "text"); t.setAttribute("x", "10"); t.setAttribute("y", maxY); t.setAttribute("class", thread); maxY += 15; t.appendChild(document.createTextNode(label)); return t; } var android = makeAction("Android/Gonk", 20, 0, "parentinput"); var sendNative = makeAction("DOMWindowUtils\nsendNativeTouchPoint", 20, 100, "parentmain"); var apzHitTest = makeAction("APZ hit test", 150, 0, "parentcompositor"); var apzUntransform = makeAction("APZ\nuntransform", 300, 0, "parentcompositor"); var apzGesture = makeAction("APZ gesture\ndetection", 450, 0, "parentcompositor"); var apzTransform = makeAction("APZ transform\nupdate", 600, 0, "parentcompositor"); var compositor = makeAction("Compositor", 750, 0, "parentcompositor"); var nsAppShell = makeAction("nsAppShell", 150, 100, "parentmain"); var rootHitTest = makeAction("Gecko hit test\n(root process)", 300, 100, "parentmain"); var rootEsm = makeAction("Gecko ESM\n(root process)", 450, 100, "parentmain"); var isEdgeGesture = makeChoice("Edge gesture?", 300, 200, "parentmain"); var edgeConsume = makeAction("Consume\nevent block", 150, 200, "parentmain"); var bepjsm = makeAction("BEParent.jsm\nsendTouchEvent", 450, 200, "parentmain"); var iframeSend = makeAction("HTMLIFrameElement\nsendTouchEvent", 20, 275, "parentmain"); var isApzTarget = makeChoice("Target\nhas APZ?", 600, 200, "parentmain"); var sendTouchEvent = makeAction("Target\nsendTouchEventToWindow", 750, 100, "parentmain"); var injectTouch = makeAction("injectTouchEvent", 750, 200, "parentmain"); var targetESM = makeAction("Target window\nESM", 750, 450, "bothmain"); var tabParent = makeAction("TabParent", 750, 350, "parentmain"); var geckoUntransform = makeAction("Gecko\nuntransform", 600, 350, "parentmain"); var tabChild = makeAction("TabChild", 450, 350, "childmain"); var isApzcEnabled = makeChoice("APZ\nenabled?", 300, 350, "childmain"); var tabGesture = makeAction("TabChild gesture\ndetection", 150, 350, "childmain"); var childHitTest = makeAction("Gecko hit test\n(child process)", 300, 450, "childmain"); var childEsm = makeAction("Gecko ESM\n(child process)", 450, 450, "childmain"); var childContent = makeAction("Content\n(child process)", 600, 450, "childmain"); document.documentElement.appendChild(android); document.documentElement.appendChild(sendNative); document.documentElement.appendChild(apzHitTest); document.documentElement.appendChild(apzUntransform); document.documentElement.appendChild(apzGesture); document.documentElement.appendChild(apzTransform); document.documentElement.appendChild(compositor); document.documentElement.appendChild(nsAppShell); document.documentElement.appendChild(rootHitTest); document.documentElement.appendChild(rootEsm); document.documentElement.appendChild(isEdgeGesture); document.documentElement.appendChild(edgeConsume); document.documentElement.appendChild(bepjsm); document.documentElement.appendChild(iframeSend); document.documentElement.appendChild(isApzTarget); document.documentElement.appendChild(sendTouchEvent); document.documentElement.appendChild(injectTouch); document.documentElement.appendChild(targetESM); document.documentElement.appendChild(tabParent); document.documentElement.appendChild(geckoUntransform); document.documentElement.appendChild(tabChild); document.documentElement.appendChild(isApzcEnabled); document.documentElement.appendChild(tabGesture); document.documentElement.appendChild(childHitTest); document.documentElement.appendChild(childEsm); document.documentElement.appendChild(childContent); document.documentElement.appendChild(makeLabelChoice("Y", offset(leftOf(isEdgeGesture), -5, -5))); document.documentElement.appendChild(makeLabelChoice("N", offset(rightOf(isEdgeGesture), 5, -5))); document.documentElement.appendChild(makeLabelChoice("N", offset(topOf(isApzTarget), 8, -10))); document.documentElement.appendChild(makeLabelChoice("Y", offset(rightOf(isApzTarget), 10, 14))); document.documentElement.appendChild(makeLabelChoice("N", offset(leftOf(isApzcEnabled), -5, -5))); document.documentElement.appendChild(makeLabelChoice("Y", offset(bottomOf(isApzcEnabled), 10, 14))); var arrows = document.getElementById('arrows'); arrows.appendChild(makeArrow(rightOf(android), leftOf(apzHitTest))); arrows.appendChild(makeVHVArrow(topOf(sendNative), midpoint(rightOf(android), leftOf(apzHitTest)), -20)); arrows.appendChild(makeArrow(rightOf(apzHitTest), leftOf(apzUntransform))); arrows.appendChild(makeArrow(rightOf(apzUntransform), leftOf(apzGesture))); arrows.appendChild(makeArrow(rightOf(apzGesture), leftOf(apzTransform))); arrows.appendChild(makeArrow(rightOf(apzTransform), leftOf(compositor))); arrows.appendChild(makeVHVArrow(midpoint(leftOf(apzUntransform), rightOf(apzGesture)), topOf(nsAppShell), 40)); arrows.appendChild(makeArrow(rightOf(nsAppShell), leftOf(rootHitTest))); arrows.appendChild(makeArrow(rightOf(rootHitTest), leftOf(rootEsm))); arrows.appendChild(makeVHVArrow(bottomOf(rootEsm), topOf(isEdgeGesture), 15)); arrows.appendChild(makeArrow(leftOf(isEdgeGesture), rightOf(edgeConsume))); arrows.appendChild(makeArrow(rightOf(isEdgeGesture), leftOf(bepjsm), 20)); arrows.appendChild(makeHVArrow(rightOf(iframeSend), bottomOf(bepjsm))); arrows.appendChild(makeArrow(rightOf(bepjsm), leftOf(isApzTarget))); arrows.appendChild(makeArrow(rightOf(isApzTarget), leftOf(injectTouch))); arrows.appendChild(makeArrow(bottomOf(injectTouch), topOf(tabParent))); arrows.appendChild(makeVHArrow(topOf(isApzTarget), leftOf(sendTouchEvent))); arrows.appendChild(makeHVHArrow(rightOf(sendTouchEvent), rightOf(targetESM), 30)); arrows.appendChild(makeArrow(leftOf(tabParent), rightOf(geckoUntransform))); arrows.appendChild(makeArrow(leftOf(geckoUntransform), rightOf(tabChild))); arrows.appendChild(makeArrow(leftOf(tabChild), rightOf(isApzcEnabled))); arrows.appendChild(makeArrow(leftOf(isApzcEnabled), rightOf(tabGesture))); arrows.appendChild(makeArrow(bottomOf(isApzcEnabled), topOf(childHitTest))); arrows.appendChild(makeVHArrow(bottomOf(tabGesture), leftOf(childHitTest))); arrows.appendChild(makeArrow(rightOf(childHitTest), leftOf(childEsm))); arrows.appendChild(makeArrow(rightOf(childEsm), leftOf(childContent))); arrows.appendChild(makeVHVArrow(midpoint(leftOf(apzGesture), rightOf(apzTransform)), topOf(tabChild), 300)); document.documentElement.appendChild(makeLegend("Main process input thread", "parentinput")); document.documentElement.appendChild(makeLegend("Main process main thread", "parentmain")); document.documentElement.appendChild(makeLegend("Main process compositor thread", "parentcompositor")); document.documentElement.appendChild(makeLegend("Child process main thread", "childmain")); document.documentElement.appendChild(makeLegend("Undetermined process main thread", "bothmain")); ]]></script> </svg>