diff options
Diffstat (limited to 'dom/tests/mochitest/general/test_offsets.js')
-rw-r--r-- | dom/tests/mochitest/general/test_offsets.js | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/dom/tests/mochitest/general/test_offsets.js b/dom/tests/mochitest/general/test_offsets.js new file mode 100644 index 000000000..509daff8c --- /dev/null +++ b/dom/tests/mochitest/general/test_offsets.js @@ -0,0 +1,222 @@ +var scrollbarWidth = 17, scrollbarHeight = 17; + +function testElements(baseid, callback) +{ + scrollbarWidth = scrollbarHeight = gcs($("scrollbox-test"), "width"); + + var elements = $(baseid).getElementsByTagName("*"); + for (var t = 0; t < elements.length; t++) { + var element = elements[t]; + testElement(element); + } + + var nonappended = document.createElement("div"); + nonappended.id = "nonappended"; + nonappended.setAttribute("_offsetParent", "null"); + testElement(nonappended); + + checkScrolledElement($("scrollbox"), $("scrollchild")); + + var div = $("noscroll"); + div.scrollLeft = 10; + div.scrollTop = 10; + is(element.scrollLeft, 0, element.id + " scrollLeft after nonscroll"); + is(element.scrollTop, 0, element.id + " scrollTop after nonscroll"); + + callback(); +} + +function toNearestAppunit(v) +{ + // 60 appunits per CSS pixel; round result to the nearest appunit + return Math.round(v*60)/60; +} + +function isEqualAppunits(a, b, msg) +{ + is(toNearestAppunit(a), toNearestAppunit(b), msg); +} + +function testElement(element) +{ + var offsetParent = element.getAttribute("_offsetParent"); + offsetParent = $(offsetParent == "null" ? null: (offsetParent ? offsetParent : "body")); + + var borderLeft = gcs(element, "borderLeftWidth"); + var borderTop = gcs(element, "borderTopWidth"); + var borderRight = gcs(element, "borderRightWidth"); + var borderBottom = gcs(element, "borderBottomWidth"); + var paddingLeft = gcs(element, "paddingLeft"); + var paddingTop = gcs(element, "paddingTop"); + var paddingRight = gcs(element, "paddingRight"); + var paddingBottom = gcs(element, "paddingBottom"); + var width = gcs(element, "width"); + var height = gcs(element, "height"); + + if (element instanceof HTMLElement) + checkOffsetState(element, -10000, -10000, + borderLeft + paddingLeft + width + paddingRight + borderRight, + borderTop + paddingTop + height + paddingBottom + borderBottom, + offsetParent, element.id); + + var scrollWidth, scrollHeight, clientWidth, clientHeight; + var doScrollCheck = true; + if (element.id == "scrollbox") { + var lastchild = $("lastline"); + scrollWidth = lastchild.getBoundingClientRect().width + paddingLeft + paddingRight; + var top = element.firstChild.getBoundingClientRect().top; + var bottom = element.lastChild.getBoundingClientRect().bottom; + var contentsHeight = bottom - top; + scrollHeight = contentsHeight + paddingTop + paddingBottom; + clientWidth = paddingLeft + width + paddingRight - scrollbarWidth; + clientHeight = paddingTop + height + paddingBottom - scrollbarHeight; + } else { + clientWidth = paddingLeft + width + paddingRight; + clientHeight = paddingTop + height + paddingBottom; + if (element.id == "overflow-visible") { + scrollWidth = 200; + scrollHeight = 201; + } else if (element.scrollWidth > clientWidth || + element.scrollHeight > clientHeight) { + // The element overflows. Don't check scrollWidth/scrollHeight since the + // above calculation is not correct. + doScrollCheck = false; + } else { + scrollWidth = clientWidth; + scrollHeight = clientHeight; + } + } + + if (doScrollCheck) { + if (element instanceof SVGElement) + checkScrollState(element, 0, 0, 0, 0, element.id); + else + checkScrollState(element, 0, 0, scrollWidth, scrollHeight, element.id); + } + + if (element instanceof SVGElement) + checkClientState(element, 0, 0, 0, 0, element.id); + else + checkClientState(element, borderLeft, borderTop, clientWidth, clientHeight, element.id); + + var boundingrect = element.getBoundingClientRect(); + isEqualAppunits(boundingrect.width, borderLeft + paddingLeft + width + paddingRight + borderRight, + element.id + " bounding rect width"); + isEqualAppunits(boundingrect.height, borderTop + paddingTop + height + paddingBottom + borderBottom, + element.id + " bounding rect height"); + isEqualAppunits(boundingrect.right - boundingrect.left, boundingrect.width, + element.id + " bounding rect right"); + isEqualAppunits(boundingrect.bottom - boundingrect.top, boundingrect.height, + element.id + " bounding rect bottom"); + + var rects = element.getClientRects(); + if (element.id == "div-displaynone" || element.id == "nonappended") { + is(rects.length, 0, element.id + " getClientRects empty"); + } + else { + is(rects[0].left, boundingrect.left, element.id + " getClientRects left"); + is(rects[0].top, boundingrect.top, element.id + " getClientRects top"); + is(rects[0].right, boundingrect.right, element.id + " getClientRects right"); + is(rects[0].bottom, boundingrect.bottom, element.id + " getClientRects bottom"); + } +} + +function checkScrolledElement(element, child) +{ + var elemrect = element.getBoundingClientRect(); + var childrect = child.getBoundingClientRect(); + + var topdiff = childrect.top - elemrect.top; + + element.scrollTop = 20; + is(element.scrollLeft, 0, element.id + " scrollLeft after vertical scroll"); + is(element.scrollTop, 20, element.id + " scrollTop after vertical scroll"); + // If the viewport has been transformed, then we might have scrolled to a subpixel value + // that's slightly different from what we requested. After rounding, however, it should + // be the same. + is(Math.round(childrect.top - child.getBoundingClientRect().top), 20, "child position after vertical scroll"); + + element.scrollTop = 0; + is(element.scrollLeft, 0, element.id + " scrollLeft after vertical scroll reset"); + is(element.scrollTop, 0, element.id + " scrollTop after vertical scroll reset"); + // Scrolling back to the top should work precisely. + is(child.getBoundingClientRect().top, childrect.top, "child position after vertical scroll reset"); + + element.scrollTop = 10; + element.scrollTop = -30; + is(element.scrollLeft, 0, element.id + " scrollLeft after vertical scroll negative"); + is(element.scrollTop, 0, element.id + " scrollTop after vertical scroll negative"); + is(child.getBoundingClientRect().top, childrect.top, "child position after vertical scroll negative"); + + element.scrollLeft = 18; + is(element.scrollLeft, 18, element.id + " scrollLeft after horizontal scroll"); + is(element.scrollTop, 0, element.id + " scrollTop after horizontal scroll"); + is(Math.round(childrect.left - child.getBoundingClientRect().left), 18, "child position after horizontal scroll"); + + element.scrollLeft = -30; + is(element.scrollLeft, 0, element.id + " scrollLeft after horizontal scroll reset"); + is(element.scrollTop, 0, element.id + " scrollTop after horizontal scroll reset"); + is(child.getBoundingClientRect().left, childrect.left, "child position after horizontal scroll reset"); +} + +function checkOffsetState(element, left, top, width, height, parent, testname) +{ + checkCoords(element, "offset", left, top, width, height, testname); + is(element.offsetParent, parent, testname + " offsetParent"); +} + +function checkScrollState(element, left, top, width, height, testname) +{ + checkCoords(element, "scroll", left, top, width, height, testname); +} + +function checkClientState(element, left, top, width, height, testname) +{ + checkCoords(element, "client", left, top, width, height, testname); +} + +function checkCoord(element, type, val, testname) +{ + if (val != -10000) + is(element[type], Math.round(val), testname + " " + type); +} + +function checkCoordFuzzy(element, type, val, fuzz, testname) +{ + if (val != -10000) + ok(Math.abs(element[type] - Math.round(val)) <= fuzz, testname + " " + type); +} + +function checkCoords(element, type, left, top, width, height, testname) +{ + checkCoord(element, type + "Left", left, testname); + checkCoord(element, type + "Top", top, testname); + + if (type == "scroll") { + // scrollWidth and scrollHeight can deviate by 1 pixel due to snapping. + checkCoordFuzzy(element, type + "Width", width, 1, testname); + checkCoordFuzzy(element, type + "Height", height, 1, testname); + } else { + checkCoord(element, type + "Width", width, testname); + checkCoord(element, type + "Height", height, testname); + } + + if (element instanceof SVGElement) + return; + + if (element.id == "outerpopup" && !element.parentNode.open) // closed popup + return; + + if (element.id == "div-displaynone" || element.id == "nonappended") // hidden elements + ok(element[type + "Width"] == 0 && element[type + "Height"] == 0, + element.id + " has zero " + type + " width and height"); +} + +function gcs(element, prop) +{ + var propVal = (element instanceof SVGElement && (prop == "width" || prop == "height")) ? + element.getAttribute(prop) : getComputedStyle(element, "")[prop]; + if (propVal == "auto") + return 0; + return parseFloat(propVal); +} |