RenderCoordinates.java revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.content.browser;
6
7/**
8 * Cached copy of all positions and scales (CSS-to-DIP-to-physical pixels)
9 * reported from the renderer.
10 * Provides wrappers and a utility class to help with coordinate transforms on the client side.
11 * Provides the internally-visible set of update methods (called from ContentViewCore).
12 *
13 * Unless stated otherwise, all coordinates are in CSS (document) coordinate space.
14 */
15public class RenderCoordinates {
16
17    // Used to accomodate finite precision when comparing scaled viewport and
18    // content widths in {@link #hasMobileViewport()}.  While this value may
19    // seem large, width=device-width on an N7 V1 saw errors of ~0.065 between
20    // computed window and content widths.
21    private static final float MOBILE_VIEWPORT_WIDTH_EPSILON = 0.15f;
22
23    // Scroll offset from the native in CSS.
24    private float mScrollXCss;
25    private float mScrollYCss;
26
27    // Content size from native in CSS.
28    private float mContentWidthCss;
29    private float mContentHeightCss;
30
31    // Last-frame render-reported viewport size in CSS.
32    private float mLastFrameViewportWidthCss;
33    private float mLastFrameViewportHeightCss;
34
35    // Cached page scale factor from native.
36    private float mPageScaleFactor = 1.0f;
37    private float mMinPageScaleFactor = 1.0f;
38    private float mMaxPageScaleFactor = 1.0f;
39
40    // Cached device density.
41    private float mDeviceScaleFactor;
42
43    private float mContentOffsetYPix;
44
45    // Internally-visible set of update methods (used by ContentViewCore).
46    void reset() {
47        mScrollXCss = mScrollYCss = 0;
48        mPageScaleFactor = 1.0f;
49    }
50
51    void updateContentSizeCss(float contentWidthCss, float contentHeightCss) {
52        mContentWidthCss = contentWidthCss;
53        mContentHeightCss = contentHeightCss;
54    }
55
56    void setDeviceScaleFactor(float deviceScaleFactor) {
57        mDeviceScaleFactor = deviceScaleFactor;
58    }
59
60    void updateFrameInfo(
61            float scrollXCss, float scrollYCss,
62            float contentWidthCss, float contentHeightCss,
63            float viewportWidthCss, float viewportHeightCss,
64            float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor,
65            float contentOffsetYPix) {
66        mScrollXCss = scrollXCss;
67        mScrollYCss = scrollYCss;
68        mPageScaleFactor = pageScaleFactor;
69        mMinPageScaleFactor = minPageScaleFactor;
70        mMaxPageScaleFactor = maxPageScaleFactor;
71        mContentOffsetYPix = contentOffsetYPix;
72
73        updateContentSizeCss(contentWidthCss, contentHeightCss);
74        mLastFrameViewportWidthCss = viewportWidthCss;
75        mLastFrameViewportHeightCss = viewportHeightCss;
76    }
77
78    /**
79     * Handles conversion of a point from window-relative-local-dip or screen-pix
80     * to document-absolute-CSS space and vice versa.
81     */
82    public class NormalizedPoint {
83        private float mXAbsoluteCss, mYAbsoluteCss;
84
85        private NormalizedPoint() {
86        }
87
88        /**
89         * @return Absolute CSS (document) X coordinate of the point.
90         */
91        public float getXAbsoluteCss() { return mXAbsoluteCss; }
92
93        /**
94         * @return Absolute CSS (document) Y coordinate of the point.
95         */
96        public float getYAbsoluteCss() { return mYAbsoluteCss; }
97
98        /**
99         * @return Local device-scale-unadjusted X coordinate of the point.
100         */
101        public float getXLocalDip() { return (mXAbsoluteCss - mScrollXCss) * mPageScaleFactor; }
102
103        /**
104         * @return Local device-scale-unadjusted Y coordinate of the point.
105         */
106        public float getYLocalDip() { return (mYAbsoluteCss - mScrollYCss) * mPageScaleFactor; }
107
108        /**
109         * @return Physical (screen) X coordinate of the point.
110         */
111        public float getXPix() { return getXLocalDip() * mDeviceScaleFactor; }
112
113        /**
114         * @return Physical (screen) Y coordinate of the point.
115         */
116        public float getYPix() { return getYLocalDip() * mDeviceScaleFactor + mContentOffsetYPix; }
117
118        /**
119         * Sets the point to the given absolute CSS (document) coordinates.
120         */
121        public void setAbsoluteCss(float xCss, float yCss) {
122            mXAbsoluteCss = xCss;
123            mYAbsoluteCss = yCss;
124        }
125
126        /**
127         * Sets the point to the given local device-scale-unadjusted coordinates.
128         */
129        public void setLocalDip(float xDip, float yDip) {
130            setAbsoluteCss(
131                    xDip / mPageScaleFactor + mScrollXCss,
132                    yDip / mPageScaleFactor + mScrollYCss);
133        }
134
135        /**
136         * Sets the point to the given physical (screen) coordinates.
137         */
138        public void setScreen(float xPix, float yPix) {
139            setLocalDip(xPix / mDeviceScaleFactor, yPix / mDeviceScaleFactor);
140        }
141    }
142
143    /**
144     * @return A helper to convert a point between between absolute CSS and local DIP spaces.
145     */
146    public NormalizedPoint createNormalizedPoint() {
147        return new NormalizedPoint();
148    }
149
150    /**
151     * @return Horizontal scroll offset in CSS pixels.
152     */
153    public float getScrollX() { return mScrollXCss; }
154
155    /**
156     * @return Vertical scroll offset in CSS pixels.
157     */
158    public float getScrollY() { return mScrollYCss; }
159
160    /**
161     * @return Horizontal scroll offset in physical pixels.
162     */
163    public float getScrollXPix() { return fromLocalCssToPix(mScrollXCss); }
164
165    /**
166     * @return Vertical scroll offset in physical pixels.
167     */
168    public float getScrollYPix() { return fromLocalCssToPix(mScrollYCss); }
169
170    /**
171     * @return Horizontal scroll offset in physical pixels (approx, integer).
172     */
173    public int getScrollXPixInt() { return (int) Math.floor(getScrollXPix()); }
174
175    /**
176     * @return Vertical scroll offset in physical pixels (approx, integer).
177     */
178    public int getScrollYPixInt() { return (int) Math.floor(getScrollYPix()); }
179
180    /**
181     * @return Width of the content in CSS pixels.
182     */
183    public float getContentWidthCss() { return mContentWidthCss; }
184
185    /**
186     * @return Height of the content in CSS pixels.
187     */
188    public float getContentHeightCss() { return mContentHeightCss; }
189
190    /**
191     * @return Approximate width of the content in physical pixels.
192     */
193    public float getContentWidthPix() { return fromLocalCssToPix(mContentWidthCss); }
194
195    /**
196     * @return Approximate height of the content in physical pixels.
197     */
198    public float getContentHeightPix() { return fromLocalCssToPix(mContentHeightCss); }
199
200    /**
201     * @return Approximate width of the content in physical pixels (integer).
202     */
203    public int getContentWidthPixInt() { return (int) Math.ceil(getContentWidthPix()); }
204
205    /**
206     * @return Approximate height of the content in physical pixels (integer).
207     */
208    public int getContentHeightPixInt() { return (int) Math.ceil(getContentHeightPix()); }
209
210    /**
211     * @return Render-reported width of the viewport in CSS pixels.
212     */
213    public float getLastFrameViewportWidthCss() { return mLastFrameViewportWidthCss; }
214
215    /**
216     * @return Render-reported height of the viewport in CSS pixels.
217     */
218    public float getLastFrameViewportHeightCss() { return mLastFrameViewportHeightCss; }
219
220    /**
221     * @return Render-reported width of the viewport in physical pixels (approximate).
222     */
223    public float getLastFrameViewportWidthPix() {
224        return fromLocalCssToPix(mLastFrameViewportWidthCss);
225    }
226
227    /**
228     * @return Render-reported height of the viewport in physical pixels (approximate).
229     */
230    public float getLastFrameViewportHeightPix() {
231        return fromLocalCssToPix(mLastFrameViewportHeightCss);
232    }
233
234    /**
235     * @return Render-reported width of the viewport in physical pixels (approx, integer).
236     */
237    public int getLastFrameViewportWidthPixInt() {
238        return (int) Math.ceil(getLastFrameViewportWidthPix());
239    }
240
241    /**
242     * @return Render-reported height of the viewport in physical pixels (approx, integer).
243     */
244    public int getLastFrameViewportHeightPixInt() {
245        return (int) Math.ceil(getLastFrameViewportHeightPix());
246    }
247
248    /**
249     * @return The Physical on-screen Y offset amount below the top controls.
250     */
251    public float getContentOffsetYPix() {
252        return mContentOffsetYPix;
253    }
254
255    /**
256     * @return Current page scale factor (maps CSS pixels to DIP pixels).
257     */
258    public float getPageScaleFactor() { return mPageScaleFactor; }
259
260    /**
261     * @return Minimum page scale factor to be used with the content.
262     */
263    public float getMinPageScaleFactor() { return mMinPageScaleFactor; }
264
265    /**
266     * @return Maximum page scale factor to be used with the content.
267     */
268    public float getMaxPageScaleFactor() { return mMaxPageScaleFactor; }
269
270    /**
271     * @return Current device scale factor (maps DIP pixels to physical pixels).
272     */
273    public float getDeviceScaleFactor() { return mDeviceScaleFactor; }
274
275    /**
276     * @return True if the page doesn't allow zoom-in/zoom-out.
277     */
278    public boolean hasFixedPageScale() { return mMinPageScaleFactor == mMaxPageScaleFactor; }
279
280    /**
281     * @return True if the page has a width=device-width or narrower viewport.
282     */
283    public boolean hasMobileViewport() {
284        final float windowWidthDip = mPageScaleFactor * mLastFrameViewportWidthCss;
285        return mContentWidthCss <= (windowWidthDip + MOBILE_VIEWPORT_WIDTH_EPSILON);
286    }
287
288    /**
289     * @return Maximum possible horizontal scroll in physical pixels.
290     */
291    public float getMaxHorizontalScrollPix() {
292        return getContentWidthPix() - getLastFrameViewportWidthPix();
293    }
294
295    /**
296     * @return Maximum possible vertical scroll in physical pixels.
297     */
298    public float getMaxVerticalScrollPix() {
299        return getContentHeightPix() - getLastFrameViewportHeightPix();
300    }
301
302    /**
303     * @return Maximum possible horizontal scroll in physical pixels (approx, integer).
304     */
305    public int getMaxHorizontalScrollPixInt() {
306        return (int) Math.floor(getMaxHorizontalScrollPix());
307    }
308
309    /**
310     * @return Maximum possible vertical scroll in physical pixels (approx, integer).
311     */
312    public int getMaxVerticalScrollPixInt() {
313        return (int) Math.floor(getMaxVerticalScrollPix());
314    }
315
316    /**
317     * @return Physical on-screen coordinate converted to local DIP.
318     */
319    public float fromPixToDip(float pix) {
320        return pix / mDeviceScaleFactor;
321    }
322
323    /**
324     * @return Local DIP converted to physical coordinates.
325     */
326    public float fromDipToPix(float dip) {
327        return dip * mDeviceScaleFactor;
328    }
329
330    /**
331     * @return Physical coordinate converted to local CSS.
332     */
333    public float fromPixToLocalCss(float pix) {
334        return pix / (mDeviceScaleFactor * mPageScaleFactor);
335    }
336
337    /**
338     * @return Local CSS converted to physical coordinates.
339     */
340    public float fromLocalCssToPix(float css) {
341        return css * mPageScaleFactor * mDeviceScaleFactor;
342    }
343}
344