mobile/android/base/gfx/ImmutableViewportMetrics.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial