/// <summary>Expected to almost never occur - this performs a full DOM scan in order to /// find the element at the given offscreen location.</summary> internal Element elementFromPointOffScreen(float x, float y) { // Get the root node: Node node = documentElement; if (node == null) { // Empty document. return(null); } // We'll always return something - we don't need to check node's box (it must match the screen anyway). // Get kids ref: NodeList kids = node.childNodes_; while (kids != null) { // Loop backwards because the 'deepest' element is the one we want. // As soon as we find something that contains our point, we essentially stop. for (int i = kids.length - 1; i >= 0; i--) { // Get the child node: Node child = kids[i]; if (!(child is Element)) { // Must be an element (unless it's a document). // Ignore text, doctype, comment etc. if (child is ReflowDocument) { // Step into this though! child = (child as ReflowDocument).documentElement; if (child == null) { // Not loaded yet continue; } } else { continue; } } // Unlike on screen we can't rely on the fast screen region // (which is only available for all on screen elements). // We'll need to always test the boxes. // Get the render data: RenderableData renderData = (child as IRenderableNode).RenderData; LayoutBox box = renderData.FirstBox; // Must be contained in one of them. bool notActuallyContained = true; while (box != null) { if (box.Contains(x, y)) { // Ok! notActuallyContained = false; break; } // Advance to next one: box = box.NextInElement; } if (notActuallyContained) { // Not actually inside the element - continue as if nothing happened: continue; } // The child contains our point! Step into it. // - If it has no kids, or none of the kids are elements, we'll end up returning child. // Note that we could trigger the event capture phase here to squeeze a tiny bit of extra performance. node = child; kids = child.childNodes_; goto SteppedNode; } // Didn't step into anything; stop here. break; SteppedNode: continue; } // 'Node' is our result: return(node as Element); }