| const GEOMETRY_UTILS_EPSILON = 0.5; |
| |
| function assert_point_approx_equals(actual, expected, description) { |
| assert_approx_equals(actual.x, expected.x, GEOMETRY_UTILS_EPSILON, |
| `${description} x`); |
| assert_approx_equals(actual.y, expected.y, GEOMETRY_UTILS_EPSILON, |
| `${description} y`); |
| } |
| |
| function assert_quad_approx_equals(actual, expected, description) { |
| for (const point of ["p1", "p2", "p3", "p4"]) { |
| assert_point_approx_equals(actual[point], expected[point], |
| `${description} ${point}`); |
| } |
| } |
| |
| function assert_rect_approx_equals(actual, expected, description) { |
| for (const prop of ["left", "top", "right", "bottom", "width", "height"]) { |
| assert_approx_equals(actual[prop], expected[prop], GEOMETRY_UTILS_EPSILON, |
| `${description} ${prop}`); |
| } |
| } |
| |
| function assert_quad_bounds_match_bounding_rect(element, options, description) { |
| const quad = element.getBoxQuads(options)[0]; |
| assert_rect_approx_equals(quad.getBounds(), element.getBoundingClientRect(), |
| description); |
| } |
| |
| function px(value) { |
| const result = parseFloat(value); |
| return Number.isFinite(result) ? result : 0; |
| } |
| |
| function used_box_edges(element) { |
| const style = getComputedStyle(element); |
| return { |
| marginTop: px(style.marginTop), |
| marginRight: px(style.marginRight), |
| marginBottom: px(style.marginBottom), |
| marginLeft: px(style.marginLeft), |
| borderTop: px(style.borderTopWidth), |
| borderRight: px(style.borderRightWidth), |
| borderBottom: px(style.borderBottomWidth), |
| borderLeft: px(style.borderLeftWidth), |
| paddingTop: px(style.paddingTop), |
| paddingRight: px(style.paddingRight), |
| paddingBottom: px(style.paddingBottom), |
| paddingLeft: px(style.paddingLeft), |
| borderWidth: element.offsetWidth, |
| borderHeight: element.offsetHeight, |
| }; |
| } |
| |
| function local_box_rect(element, box) { |
| const edges = used_box_edges(element); |
| const borderWidth = edges.borderWidth; |
| const borderHeight = edges.borderHeight; |
| |
| if (box === "margin") { |
| return { |
| x: -edges.marginLeft, |
| y: -edges.marginTop, |
| width: borderWidth + edges.marginLeft + edges.marginRight, |
| height: borderHeight + edges.marginTop + edges.marginBottom, |
| }; |
| } |
| |
| if (box === "padding") { |
| return { |
| x: edges.borderLeft, |
| y: edges.borderTop, |
| width: borderWidth - edges.borderLeft - edges.borderRight, |
| height: borderHeight - edges.borderTop - edges.borderBottom, |
| }; |
| } |
| |
| if (box === "content") { |
| return { |
| x: edges.borderLeft + edges.paddingLeft, |
| y: edges.borderTop + edges.paddingTop, |
| width: borderWidth - edges.borderLeft - edges.borderRight - |
| edges.paddingLeft - edges.paddingRight, |
| height: borderHeight - edges.borderTop - edges.borderBottom - |
| edges.paddingTop - edges.paddingBottom, |
| }; |
| } |
| |
| return {x: 0, y: 0, width: borderWidth, height: borderHeight}; |
| } |
| |
| function box_size(element, box) { |
| const rect = local_box_rect(element, box); |
| return {width: rect.width, height: rect.height}; |
| } |
| |
| function box_origin(element, box) { |
| const rect = local_box_rect(element, box); |
| return new DOMPoint(rect.x, rect.y); |
| } |
| |
| function quad_from_rect(rect) { |
| return new DOMQuad( |
| new DOMPoint(rect.x, rect.y), |
| new DOMPoint(rect.x + rect.width, rect.y), |
| new DOMPoint(rect.x + rect.width, rect.y + rect.height), |
| new DOMPoint(rect.x, rect.y + rect.height) |
| ); |
| } |
| |
| function translated_quad(quad, dx, dy) { |
| return new DOMQuad( |
| new DOMPoint(quad.p1.x + dx, quad.p1.y + dy), |
| new DOMPoint(quad.p2.x + dx, quad.p2.y + dy), |
| new DOMPoint(quad.p3.x + dx, quad.p3.y + dy), |
| new DOMPoint(quad.p4.x + dx, quad.p4.y + dy) |
| ); |
| } |
| |
| function translated_point(point, dx, dy) { |
| return new DOMPoint(point.x + dx, point.y + dy); |
| } |
| |
| function expected_quad_in_target_box(source, target, fromBox, toBox) { |
| const targetOrigin = box_origin(target, toBox); |
| return translated_quad( |
| source.getBoxQuads({box: fromBox, relativeTo: target})[0], |
| -targetOrigin.x, |
| -targetOrigin.y |
| ); |
| } |
| |
| function expected_point_in_target_box(source, target, fromBox, toBox, pointName) { |
| const targetOrigin = box_origin(target, toBox); |
| const point = source.getBoxQuads({box: fromBox, relativeTo: target})[0][pointName]; |
| return translated_point(point, -targetOrigin.x, -targetOrigin.y); |
| } |
| |
| function assert_geometry_utils_exist() { |
| assert_equals(typeof Element.prototype.getBoxQuads, "function", |
| "Element.prototype.getBoxQuads"); |
| assert_equals(typeof Element.prototype.convertQuadFromNode, "function", |
| "Element.prototype.convertQuadFromNode"); |
| assert_equals(typeof Element.prototype.convertRectFromNode, "function", |
| "Element.prototype.convertRectFromNode"); |
| assert_equals(typeof Element.prototype.convertPointFromNode, "function", |
| "Element.prototype.convertPointFromNode"); |
| } |