diff --git a/src/service/viewport-impl.js b/src/service/viewport-impl.js index f21cfa20ed98..96662cf03255 100644 --- a/src/service/viewport-impl.js +++ b/src/service/viewport-impl.js @@ -244,7 +244,8 @@ export class Viewport { * @return {!LayoutRect} */ getLayoutRect(el) { - return this.binding_.getLayoutRect(el); + return this.binding_.getLayoutRect(el, + this.getScrollLeft(), this.getScrollTop()); } /** @@ -577,9 +578,13 @@ class ViewportBindingDef { /** * Returns the rect of the element within the document. * @param {!Element} unusedEl + * @param {number=} unusedScrollLeft Optional arguments that the caller may + * pass in, if they cached these values and would like to avoid + * remeasure. Requires appropriate updating the values on scroll. + * @param {number=} unusedScrollTop Same comment as above. * @return {!LayoutRect} */ - getLayoutRect(unusedEl) {} + getLayoutRect(unusedEl, unusedScrollLeft, unusedScrollTop) {} /** For testing. */ cleanup_() {} @@ -686,9 +691,13 @@ export class ViewportBindingNatural_ { } /** @override */ - getLayoutRect(el) { - const scrollTop = this.getScrollTop(); - const scrollLeft = this.getScrollLeft(); + getLayoutRect(el, opt_scrollLeft, opt_scrollTop) { + const scrollTop = opt_scrollTop != undefined + ? opt_scrollTop + : this.getScrollTop(); + const scrollLeft = opt_scrollLeft != undefined + ? opt_scrollLeft + : this.getScrollLeft(); const b = el./*OK*/getBoundingClientRect(); return layoutRectLtwh(Math.round(b.left + scrollLeft), Math.round(b.top + scrollTop), diff --git a/test/functional/test-viewport.js b/test/functional/test-viewport.js index 1e8fea11f856..6a582355c2e0 100644 --- a/test/functional/test-viewport.js +++ b/test/functional/test-viewport.js @@ -218,6 +218,16 @@ describe('Viewport', () => { viewport.scrollIntoView(element); }); + it('should send cached scroll pos to getLayoutRect', () => { + const element = document.createElement('div'); + const bindingMock = sandbox.mock(binding); + viewport.scrollTop_ = 111; + viewport.scrollLeft_ = 222; + bindingMock.expects('getLayoutRect').withArgs(element, 222, 111) + .returns('sentinel').once(); + expect(viewport.getLayoutRect(element)).to.equal('sentinel'); + }); + it('should deletegate scrollWidth', () => { const bindingMock = sandbox.mock(binding); bindingMock.expects('getScrollWidth').withArgs().returns(111).once(); @@ -601,6 +611,22 @@ describe('ViewportBindingNatural', () => { expect(rect.width).to.equal(14); // round(13.5) expect(rect.height).to.equal(15); // round(14.5) }); + + it('should offset client rect for layout and position passed in', () => { + windowApi.pageXOffset = 1000; + windowApi.pageYOffset = 2000; + windowApi.document = {scrollingElement: {}}; + const el = { + getBoundingClientRect: () => { + return {left: 11.5, top: 12.5, width: 13.5, height: 14.5}; + }, + }; + const rect = binding.getLayoutRect(el, 100, 200); + expect(rect.left).to.equal(112); // round(100 + 11.5) + expect(rect.top).to.equal(213); // round(200 + 12.5) + expect(rect.width).to.equal(14); // round(13.5) + expect(rect.height).to.equal(15); // round(14.5) + }); });