mobile/android/base/gfx/ImmutableViewportMetrics.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 package org.mozilla.gecko.gfx;
     8 import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
     9 import org.mozilla.gecko.util.FloatUtils;
    11 import android.graphics.PointF;
    12 import android.graphics.RectF;
    13 import android.util.DisplayMetrics;
    15 /**
    16  * ImmutableViewportMetrics are used to store the viewport metrics
    17  * in way that we can access a version of them from multiple threads
    18  * without having to take a lock
    19  */
    20 public class ImmutableViewportMetrics {
    22     // We need to flatten the RectF and FloatSize structures
    23     // because Java doesn't have the concept of const classes
    24     public final float pageRectLeft;
    25     public final float pageRectTop;
    26     public final float pageRectRight;
    27     public final float pageRectBottom;
    28     public final float cssPageRectLeft;
    29     public final float cssPageRectTop;
    30     public final float cssPageRectRight;
    31     public final float cssPageRectBottom;
    32     public final float viewportRectLeft;
    33     public final float viewportRectTop;
    34     public final float viewportRectRight;
    35     public final float viewportRectBottom;
    36     public final float marginLeft;
    37     public final float marginTop;
    38     public final float marginRight;
    39     public final float marginBottom;
    40     public final float zoomFactor;
    41     public final boolean isRTL;
    43     public ImmutableViewportMetrics(DisplayMetrics metrics) {
    44         viewportRectLeft   = pageRectLeft   = cssPageRectLeft   = 0;
    45         viewportRectTop    = pageRectTop    = cssPageRectTop    = 0;
    46         viewportRectRight  = pageRectRight  = cssPageRectRight  = metrics.widthPixels;
    47         viewportRectBottom = pageRectBottom = cssPageRectBottom = metrics.heightPixels;
    48         marginLeft = marginTop = marginRight = marginBottom = 0;
    49         zoomFactor = 1.0f;
    50         isRTL = false;
    51     }
    53     /** This constructor is used by native code in AndroidJavaWrappers.cpp, be
    54      * careful when modifying the signature.
    55      */
    56     @WrapElementForJNI(allowMultithread = true)
    57     public ImmutableViewportMetrics(float aPageRectLeft, float aPageRectTop,
    58         float aPageRectRight, float aPageRectBottom, float aCssPageRectLeft,
    59         float aCssPageRectTop, float aCssPageRectRight, float aCssPageRectBottom,
    60         float aViewportRectLeft, float aViewportRectTop, float aViewportRectRight,
    61         float aViewportRectBottom, float aZoomFactor)
    62     {
    63         this(aPageRectLeft, aPageRectTop,
    64              aPageRectRight, aPageRectBottom, aCssPageRectLeft,
    65              aCssPageRectTop, aCssPageRectRight, aCssPageRectBottom,
    66              aViewportRectLeft, aViewportRectTop, aViewportRectRight,
    67              aViewportRectBottom, 0.0f, 0.0f, 0.0f, 0.0f, aZoomFactor, false);
    68     }
    70     private ImmutableViewportMetrics(float aPageRectLeft, float aPageRectTop,
    71         float aPageRectRight, float aPageRectBottom, float aCssPageRectLeft,
    72         float aCssPageRectTop, float aCssPageRectRight, float aCssPageRectBottom,
    73         float aViewportRectLeft, float aViewportRectTop, float aViewportRectRight,
    74         float aViewportRectBottom, float aMarginLeft,
    75         float aMarginTop, float aMarginRight,
    76         float aMarginBottom, float aZoomFactor, boolean aIsRTL)
    77     {
    78         pageRectLeft = aPageRectLeft;
    79         pageRectTop = aPageRectTop;
    80         pageRectRight = aPageRectRight;
    81         pageRectBottom = aPageRectBottom;
    82         cssPageRectLeft = aCssPageRectLeft;
    83         cssPageRectTop = aCssPageRectTop;
    84         cssPageRectRight = aCssPageRectRight;
    85         cssPageRectBottom = aCssPageRectBottom;
    86         viewportRectLeft = aViewportRectLeft;
    87         viewportRectTop = aViewportRectTop;
    88         viewportRectRight = aViewportRectRight;
    89         viewportRectBottom = aViewportRectBottom;
    90         marginLeft = aMarginLeft;
    91         marginTop = aMarginTop;
    92         marginRight = aMarginRight;
    93         marginBottom = aMarginBottom;
    94         zoomFactor = aZoomFactor;
    95         isRTL = aIsRTL;
    96     }
    98     public float getWidth() {
    99         return viewportRectRight - viewportRectLeft;
   100     }
   102     public float getHeight() {
   103         return viewportRectBottom - viewportRectTop;
   104     }
   106     public float getWidthWithoutMargins() {
   107         return viewportRectRight - viewportRectLeft - marginLeft - marginRight;
   108     }
   110     public float getHeightWithoutMargins() {
   111         return viewportRectBottom - viewportRectTop - marginTop - marginBottom;
   112     }
   114     public PointF getOrigin() {
   115         return new PointF(viewportRectLeft, viewportRectTop);
   116     }
   118     public PointF getMarginOffset() {
   119         if (isRTL) {
   120             return new PointF(marginLeft - marginRight, marginTop);
   121         }
   122         return new PointF(marginLeft, marginTop);
   123     }
   125     public FloatSize getSize() {
   126         return new FloatSize(viewportRectRight - viewportRectLeft, viewportRectBottom - viewportRectTop);
   127     }
   129     public RectF getViewport() {
   130         return new RectF(viewportRectLeft,
   131                          viewportRectTop,
   132                          viewportRectRight,
   133                          viewportRectBottom);
   134     }
   136     public RectF getCssViewport() {
   137         return RectUtils.scale(getViewport(), 1/zoomFactor);
   138     }
   140     public RectF getPageRect() {
   141         return new RectF(pageRectLeft, pageRectTop, pageRectRight, pageRectBottom);
   142     }
   144     public float getPageWidth() {
   145         return pageRectRight - pageRectLeft;
   146     }
   148     public float getPageWidthWithMargins() {
   149         return (pageRectRight - pageRectLeft) + marginLeft + marginRight;
   150     }
   152     public float getPageHeight() {
   153         return pageRectBottom - pageRectTop;
   154     }
   156     public float getPageHeightWithMargins() {
   157         return (pageRectBottom - pageRectTop) + marginTop + marginBottom;
   158     }
   160     public RectF getCssPageRect() {
   161         return new RectF(cssPageRectLeft, cssPageRectTop, cssPageRectRight, cssPageRectBottom);
   162     }
   164     public RectF getOverscroll() {
   165         return new RectF(Math.max(0, pageRectLeft - viewportRectLeft),
   166                          Math.max(0, pageRectTop - viewportRectTop),
   167                          Math.max(0, viewportRectRight - pageRectRight),
   168                          Math.max(0, viewportRectBottom - pageRectBottom));
   169     }
   171     /*
   172      * Returns the viewport metrics that represent a linear transition between "this" and "to" at
   173      * time "t", which is on the scale [0, 1). This function interpolates all values stored in
   174      * the viewport metrics.
   175      */
   176     public ImmutableViewportMetrics interpolate(ImmutableViewportMetrics to, float t) {
   177         return new ImmutableViewportMetrics(
   178             FloatUtils.interpolate(pageRectLeft, to.pageRectLeft, t),
   179             FloatUtils.interpolate(pageRectTop, to.pageRectTop, t),
   180             FloatUtils.interpolate(pageRectRight, to.pageRectRight, t),
   181             FloatUtils.interpolate(pageRectBottom, to.pageRectBottom, t),
   182             FloatUtils.interpolate(cssPageRectLeft, to.cssPageRectLeft, t),
   183             FloatUtils.interpolate(cssPageRectTop, to.cssPageRectTop, t),
   184             FloatUtils.interpolate(cssPageRectRight, to.cssPageRectRight, t),
   185             FloatUtils.interpolate(cssPageRectBottom, to.cssPageRectBottom, t),
   186             FloatUtils.interpolate(viewportRectLeft, to.viewportRectLeft, t),
   187             FloatUtils.interpolate(viewportRectTop, to.viewportRectTop, t),
   188             FloatUtils.interpolate(viewportRectRight, to.viewportRectRight, t),
   189             FloatUtils.interpolate(viewportRectBottom, to.viewportRectBottom, t),
   190             FloatUtils.interpolate(marginLeft, to.marginLeft, t),
   191             FloatUtils.interpolate(marginTop, to.marginTop, t),
   192             FloatUtils.interpolate(marginRight, to.marginRight, t),
   193             FloatUtils.interpolate(marginBottom, to.marginBottom, t),
   194             FloatUtils.interpolate(zoomFactor, to.zoomFactor, t),
   195             t >= 0.5 ? to.isRTL : isRTL);
   196     }
   198     public ImmutableViewportMetrics setViewportSize(float width, float height) {
   199         if (FloatUtils.fuzzyEquals(width, getWidth()) && FloatUtils.fuzzyEquals(height, getHeight())) {
   200             return this;
   201         }
   203         return new ImmutableViewportMetrics(
   204             pageRectLeft, pageRectTop, pageRectRight, pageRectBottom,
   205             cssPageRectLeft, cssPageRectTop, cssPageRectRight, cssPageRectBottom,
   206             viewportRectLeft, viewportRectTop, viewportRectLeft + width, viewportRectTop + height,
   207             marginLeft, marginTop, marginRight, marginBottom,
   208             zoomFactor, isRTL);
   209     }
   211     public ImmutableViewportMetrics setViewportOrigin(float newOriginX, float newOriginY) {
   212         return new ImmutableViewportMetrics(
   213             pageRectLeft, pageRectTop, pageRectRight, pageRectBottom,
   214             cssPageRectLeft, cssPageRectTop, cssPageRectRight, cssPageRectBottom,
   215             newOriginX, newOriginY, newOriginX + getWidth(), newOriginY + getHeight(),
   216             marginLeft, marginTop, marginRight, marginBottom,
   217             zoomFactor, isRTL);
   218     }
   220     public ImmutableViewportMetrics setZoomFactor(float newZoomFactor) {
   221         return new ImmutableViewportMetrics(
   222             pageRectLeft, pageRectTop, pageRectRight, pageRectBottom,
   223             cssPageRectLeft, cssPageRectTop, cssPageRectRight, cssPageRectBottom,
   224             viewportRectLeft, viewportRectTop, viewportRectRight, viewportRectBottom,
   225             marginLeft, marginTop, marginRight, marginBottom,
   226             newZoomFactor, isRTL);
   227     }
   229     public ImmutableViewportMetrics offsetViewportBy(float dx, float dy) {
   230         return setViewportOrigin(viewportRectLeft + dx, viewportRectTop + dy);
   231     }
   233     public ImmutableViewportMetrics offsetViewportByAndClamp(float dx, float dy) {
   234         if (isRTL) {
   235             return setViewportOrigin(
   236                 Math.min(pageRectRight - getWidthWithoutMargins(), Math.max(viewportRectLeft + dx, pageRectLeft)),
   237                 Math.max(pageRectTop, Math.min(viewportRectTop + dy, pageRectBottom - getHeightWithoutMargins())));
   238         }
   239         return setViewportOrigin(
   240             Math.max(pageRectLeft, Math.min(viewportRectLeft + dx, pageRectRight - getWidthWithoutMargins())),
   241             Math.max(pageRectTop, Math.min(viewportRectTop + dy, pageRectBottom - getHeightWithoutMargins())));
   242     }
   244     public ImmutableViewportMetrics setPageRect(RectF pageRect, RectF cssPageRect) {
   245         return new ImmutableViewportMetrics(
   246             pageRect.left, pageRect.top, pageRect.right, pageRect.bottom,
   247             cssPageRect.left, cssPageRect.top, cssPageRect.right, cssPageRect.bottom,
   248             viewportRectLeft, viewportRectTop, viewportRectRight, viewportRectBottom,
   249             marginLeft, marginTop, marginRight, marginBottom,
   250             zoomFactor, isRTL);
   251     }
   253     public ImmutableViewportMetrics setMargins(float left, float top, float right, float bottom) {
   254         if (FloatUtils.fuzzyEquals(left, marginLeft)
   255                 && FloatUtils.fuzzyEquals(top, marginTop)
   256                 && FloatUtils.fuzzyEquals(right, marginRight)
   257                 && FloatUtils.fuzzyEquals(bottom, marginBottom)) {
   258             return this;
   259         }
   261         return new ImmutableViewportMetrics(
   262             pageRectLeft, pageRectTop, pageRectRight, pageRectBottom,
   263             cssPageRectLeft, cssPageRectTop, cssPageRectRight, cssPageRectBottom,
   264             viewportRectLeft, viewportRectTop, viewportRectRight, viewportRectBottom,
   265             left, top, right, bottom, zoomFactor, isRTL);
   266     }
   268     public ImmutableViewportMetrics setMarginsFrom(ImmutableViewportMetrics fromMetrics) {
   269         return setMargins(fromMetrics.marginLeft,
   270                           fromMetrics.marginTop,
   271                           fromMetrics.marginRight,
   272                           fromMetrics.marginBottom);
   273     }
   275     public ImmutableViewportMetrics setIsRTL(boolean aIsRTL) {
   276         if (isRTL == aIsRTL) {
   277             return this;
   278         }
   280         return new ImmutableViewportMetrics(
   281             pageRectLeft, pageRectTop, pageRectRight, pageRectBottom,
   282             cssPageRectLeft, cssPageRectTop, cssPageRectRight, cssPageRectBottom,
   283             viewportRectLeft, viewportRectTop, viewportRectRight, viewportRectBottom,
   284             marginLeft, marginTop, marginRight, marginBottom, zoomFactor, aIsRTL);
   285     }
   287     /* This will set the zoom factor and re-scale page-size and viewport offset
   288      * accordingly. The given focus will remain at the same point on the screen
   289      * after scaling.
   290      */
   291     public ImmutableViewportMetrics scaleTo(float newZoomFactor, PointF focus) {
   292         // cssPageRect* is invariant, since we're setting the scale factor
   293         // here. The page rect is based on the CSS page rect.
   294         float newPageRectLeft = cssPageRectLeft * newZoomFactor;
   295         float newPageRectTop = cssPageRectTop * newZoomFactor;
   296         float newPageRectRight = cssPageRectLeft + ((cssPageRectRight - cssPageRectLeft) * newZoomFactor);
   297         float newPageRectBottom = cssPageRectTop + ((cssPageRectBottom - cssPageRectTop) * newZoomFactor);
   299         PointF origin = getOrigin();
   300         origin.offset(focus.x, focus.y);
   301         origin = PointUtils.scale(origin, newZoomFactor / zoomFactor);
   302         origin.offset(-focus.x, -focus.y);
   304         return new ImmutableViewportMetrics(
   305             newPageRectLeft, newPageRectTop, newPageRectRight, newPageRectBottom,
   306             cssPageRectLeft, cssPageRectTop, cssPageRectRight, cssPageRectBottom,
   307             origin.x, origin.y, origin.x + getWidth(), origin.y + getHeight(),
   308             marginLeft, marginTop, marginRight, marginBottom,
   309             newZoomFactor, isRTL);
   310     }
   312     /** Clamps the viewport to remain within the page rect. */
   313     private ImmutableViewportMetrics clamp(float marginLeft, float marginTop,
   314                                            float marginRight, float marginBottom) {
   315         RectF newViewport = getViewport();
   316         PointF offset = getMarginOffset();
   318         // The viewport bounds ought to never exceed the page bounds.
   319         if (newViewport.right > pageRectRight + marginLeft + marginRight)
   320             newViewport.offset((pageRectRight + marginLeft + marginRight) - newViewport.right, 0);
   321         if (newViewport.left < pageRectLeft)
   322             newViewport.offset(pageRectLeft - newViewport.left, 0);
   324         if (newViewport.bottom > pageRectBottom + marginTop + marginBottom)
   325             newViewport.offset(0, (pageRectBottom + marginTop + marginBottom) - newViewport.bottom);
   326         if (newViewport.top < pageRectTop)
   327             newViewport.offset(0, pageRectTop - newViewport.top);
   329         return new ImmutableViewportMetrics(
   330             pageRectLeft, pageRectTop, pageRectRight, pageRectBottom,
   331             cssPageRectLeft, cssPageRectTop, cssPageRectRight, cssPageRectBottom,
   332             newViewport.left, newViewport.top, newViewport.right, newViewport.bottom,
   333             marginLeft, marginTop, marginRight, marginBottom,
   334             zoomFactor, isRTL);
   335     }
   337     public ImmutableViewportMetrics clamp() {
   338         return clamp(0, 0, 0, 0);
   339     }
   341     public ImmutableViewportMetrics clampWithMargins() {
   342         return clamp(marginLeft, marginTop,
   343                      marginRight, marginBottom);
   344     }
   346     public boolean fuzzyEquals(ImmutableViewportMetrics other) {
   347         // Don't bother checking the pageRectXXX values because they are a product
   348         // of the cssPageRectXXX values and the zoomFactor, except with more rounding
   349         // error. Checking those is both inefficient and can lead to false negatives.
   350         //
   351         // This doesn't return false if the margins differ as none of the users
   352         // of this function are interested in the margins in that way.
   353         return FloatUtils.fuzzyEquals(cssPageRectLeft, other.cssPageRectLeft)
   354             && FloatUtils.fuzzyEquals(cssPageRectTop, other.cssPageRectTop)
   355             && FloatUtils.fuzzyEquals(cssPageRectRight, other.cssPageRectRight)
   356             && FloatUtils.fuzzyEquals(cssPageRectBottom, other.cssPageRectBottom)
   357             && FloatUtils.fuzzyEquals(viewportRectLeft, other.viewportRectLeft)
   358             && FloatUtils.fuzzyEquals(viewportRectTop, other.viewportRectTop)
   359             && FloatUtils.fuzzyEquals(viewportRectRight, other.viewportRectRight)
   360             && FloatUtils.fuzzyEquals(viewportRectBottom, other.viewportRectBottom)
   361             && FloatUtils.fuzzyEquals(zoomFactor, other.zoomFactor);
   362     }
   364     @Override
   365     public String toString() {
   366         return "ImmutableViewportMetrics v=(" + viewportRectLeft + "," + viewportRectTop + ","
   367                 + viewportRectRight + "," + viewportRectBottom + ") p=(" + pageRectLeft + ","
   368                 + pageRectTop + "," + pageRectRight + "," + pageRectBottom + ") c=("
   369                 + cssPageRectLeft + "," + cssPageRectTop + "," + cssPageRectRight + ","
   370                 + cssPageRectBottom + ") m=(" + marginLeft + ","
   371                 + marginTop + "," + marginRight + ","
   372                 + marginBottom + ") z=" + zoomFactor + ", rtl=" + isRTL;
   373     }
   374 }

mercurial