mobile/android/base/gfx/Layer.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/gfx/Layer.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,207 @@
     1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +package org.mozilla.gecko.gfx;
    1.10 +
    1.11 +import org.mozilla.gecko.util.FloatUtils;
    1.12 +
    1.13 +import android.graphics.PointF;
    1.14 +import android.graphics.Rect;
    1.15 +import android.graphics.RectF;
    1.16 +
    1.17 +import java.nio.FloatBuffer;
    1.18 +import java.util.concurrent.locks.ReentrantLock;
    1.19 +
    1.20 +public abstract class Layer {
    1.21 +    private final ReentrantLock mTransactionLock;
    1.22 +    private boolean mInTransaction;
    1.23 +    private Rect mNewPosition;
    1.24 +    private float mNewResolution;
    1.25 +
    1.26 +    protected Rect mPosition;
    1.27 +    protected float mResolution;
    1.28 +
    1.29 +    public Layer() {
    1.30 +        this(null);
    1.31 +    }
    1.32 +
    1.33 +    public Layer(IntSize size) {
    1.34 +        mTransactionLock = new ReentrantLock();
    1.35 +        if (size == null) {
    1.36 +            mPosition = new Rect();
    1.37 +        } else {
    1.38 +            mPosition = new Rect(0, 0, size.width, size.height);
    1.39 +        }
    1.40 +        mResolution = 1.0f;
    1.41 +    }
    1.42 +
    1.43 +    /**
    1.44 +     * Updates the layer. This returns false if there is still work to be done
    1.45 +     * after this update.
    1.46 +     */
    1.47 +    public final boolean update(RenderContext context) {
    1.48 +        if (mTransactionLock.isHeldByCurrentThread()) {
    1.49 +            throw new RuntimeException("draw() called while transaction lock held by this " +
    1.50 +                                       "thread?!");
    1.51 +        }
    1.52 +
    1.53 +        if (mTransactionLock.tryLock()) {
    1.54 +            try {
    1.55 +                performUpdates(context);
    1.56 +                return true;
    1.57 +            } finally {
    1.58 +                mTransactionLock.unlock();
    1.59 +            }
    1.60 +        }
    1.61 +
    1.62 +        return false;
    1.63 +    }
    1.64 +
    1.65 +    /** Subclasses override this function to draw the layer. */
    1.66 +    public abstract void draw(RenderContext context);
    1.67 +
    1.68 +    /** Given the intrinsic size of the layer, returns the pixel boundaries of the layer rect. */
    1.69 +    protected RectF getBounds(RenderContext context) {
    1.70 +        return RectUtils.scale(new RectF(mPosition), context.zoomFactor / mResolution);
    1.71 +    }
    1.72 +
    1.73 +    /**
    1.74 +     * Call this before modifying the layer. Note that, for TileLayers, "modifying the layer"
    1.75 +     * includes altering the underlying CairoImage in any way. Thus you must call this function
    1.76 +     * before modifying the byte buffer associated with this layer.
    1.77 +     *
    1.78 +     * This function may block, so you should never call this on the main UI thread.
    1.79 +     */
    1.80 +    public void beginTransaction() {
    1.81 +        if (mTransactionLock.isHeldByCurrentThread())
    1.82 +            throw new RuntimeException("Nested transactions are not supported");
    1.83 +        mTransactionLock.lock();
    1.84 +        mInTransaction = true;
    1.85 +        mNewResolution = mResolution;
    1.86 +    }
    1.87 +
    1.88 +    /** Call this when you're done modifying the layer. */
    1.89 +    public void endTransaction() {
    1.90 +        if (!mInTransaction)
    1.91 +            throw new RuntimeException("endTransaction() called outside a transaction");
    1.92 +        mInTransaction = false;
    1.93 +        mTransactionLock.unlock();
    1.94 +    }
    1.95 +
    1.96 +    /** Returns true if the layer is currently in a transaction and false otherwise. */
    1.97 +    protected boolean inTransaction() {
    1.98 +        return mInTransaction;
    1.99 +    }
   1.100 +
   1.101 +    /** Returns the current layer position. */
   1.102 +    public Rect getPosition() {
   1.103 +        return mPosition;
   1.104 +    }
   1.105 +
   1.106 +    /** Sets the position. Only valid inside a transaction. */
   1.107 +    public void setPosition(Rect newPosition) {
   1.108 +        if (!mInTransaction)
   1.109 +            throw new RuntimeException("setPosition() is only valid inside a transaction");
   1.110 +        mNewPosition = newPosition;
   1.111 +    }
   1.112 +
   1.113 +    /** Returns the current layer's resolution. */
   1.114 +    public float getResolution() {
   1.115 +        return mResolution;
   1.116 +    }
   1.117 +
   1.118 +    /**
   1.119 +     * Sets the layer resolution. This value is used to determine how many pixels per
   1.120 +     * device pixel this layer was rendered at. This will be reflected by scaling by
   1.121 +     * the reciprocal of the resolution in the layer's transform() function.
   1.122 +     * Only valid inside a transaction. */
   1.123 +    public void setResolution(float newResolution) {
   1.124 +        if (!mInTransaction)
   1.125 +            throw new RuntimeException("setResolution() is only valid inside a transaction");
   1.126 +        mNewResolution = newResolution;
   1.127 +    }
   1.128 +
   1.129 +    /**
   1.130 +     * Subclasses may override this method to perform custom layer updates. This will be called
   1.131 +     * with the transaction lock held. Subclass implementations of this method must call the
   1.132 +     * superclass implementation. Returns false if there is still work to be done after this
   1.133 +     * update is complete.
   1.134 +     */
   1.135 +    protected void performUpdates(RenderContext context) {
   1.136 +        if (mNewPosition != null) {
   1.137 +            mPosition = mNewPosition;
   1.138 +            mNewPosition = null;
   1.139 +        }
   1.140 +        if (mNewResolution != 0.0f) {
   1.141 +            mResolution = mNewResolution;
   1.142 +            mNewResolution = 0.0f;
   1.143 +        }
   1.144 +    }
   1.145 +
   1.146 +    /**
   1.147 +     * This function fills in the provided <tt>dest</tt> array with values to render a texture.
   1.148 +     * The array is filled with 4 sets of {x, y, z, texture_x, texture_y} values (so 20 values
   1.149 +     * in total) corresponding to the corners of the rect.
   1.150 +     */
   1.151 +    protected final void fillRectCoordBuffer(float[] dest, RectF rect, float viewWidth, float viewHeight,
   1.152 +                                             Rect cropRect, float texWidth, float texHeight) {
   1.153 +        //x, y, z, texture_x, texture_y
   1.154 +        dest[0] = rect.left / viewWidth;
   1.155 +        dest[1] = rect.bottom / viewHeight;
   1.156 +        dest[2] = 0;
   1.157 +        dest[3] = cropRect.left / texWidth;
   1.158 +        dest[4] = cropRect.top / texHeight;
   1.159 +
   1.160 +        dest[5] = rect.left / viewWidth;
   1.161 +        dest[6] = rect.top / viewHeight;
   1.162 +        dest[7] = 0;
   1.163 +        dest[8] = cropRect.left / texWidth;
   1.164 +        dest[9] = cropRect.bottom / texHeight;
   1.165 +
   1.166 +        dest[10] = rect.right / viewWidth;
   1.167 +        dest[11] = rect.bottom / viewHeight;
   1.168 +        dest[12] = 0;
   1.169 +        dest[13] = cropRect.right / texWidth;
   1.170 +        dest[14] = cropRect.top / texHeight;
   1.171 +
   1.172 +        dest[15] = rect.right / viewWidth;
   1.173 +        dest[16] = rect.top / viewHeight;
   1.174 +        dest[17] = 0;
   1.175 +        dest[18] = cropRect.right / texWidth;
   1.176 +        dest[19] = cropRect.bottom / texHeight;
   1.177 +    }
   1.178 +
   1.179 +    public static class RenderContext {
   1.180 +        public final RectF viewport;
   1.181 +        public final RectF pageRect;
   1.182 +        public final float zoomFactor;
   1.183 +        public final PointF offset;
   1.184 +        public final int positionHandle;
   1.185 +        public final int textureHandle;
   1.186 +        public final FloatBuffer coordBuffer;
   1.187 +
   1.188 +        public RenderContext(RectF aViewport, RectF aPageRect, float aZoomFactor, PointF aOffset,
   1.189 +                             int aPositionHandle, int aTextureHandle, FloatBuffer aCoordBuffer) {
   1.190 +            viewport = aViewport;
   1.191 +            pageRect = aPageRect;
   1.192 +            zoomFactor = aZoomFactor;
   1.193 +            offset = aOffset;
   1.194 +            positionHandle = aPositionHandle;
   1.195 +            textureHandle = aTextureHandle;
   1.196 +            coordBuffer = aCoordBuffer;
   1.197 +        }
   1.198 +
   1.199 +        public boolean fuzzyEquals(RenderContext other) {
   1.200 +            if (other == null) {
   1.201 +                return false;
   1.202 +            }
   1.203 +            return RectUtils.fuzzyEquals(viewport, other.viewport)
   1.204 +                && RectUtils.fuzzyEquals(pageRect, other.pageRect)
   1.205 +                && FloatUtils.fuzzyEquals(zoomFactor, other.zoomFactor)
   1.206 +                && FloatUtils.fuzzyEquals(offset, other.offset);
   1.207 +        }
   1.208 +    }
   1.209 +}
   1.210 +

mercurial