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
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org
.mozilla
.gecko
.gfx
;
8 import android
.graphics
.Rect
;
9 import android
.graphics
.RectF
;
10 import android
.graphics
.Region
;
12 import org
.mozilla
.gecko
.util
.FloatUtils
;
14 import java
.nio
.FloatBuffer
;
15 import java
.util
.concurrent
.locks
.ReentrantLock
;
17 public abstract class Layer
{
18 private final ReentrantLock mTransactionLock
;
19 private boolean mInTransaction
;
20 private Rect mNewPosition
;
21 private float mNewResolution
;
23 protected Rect mPosition
;
24 protected float mResolution
;
25 protected boolean mUsesDefaultProgram
= true;
31 public Layer(IntSize size
) {
32 mTransactionLock
= new ReentrantLock();
34 mPosition
= new Rect();
36 mPosition
= new Rect(0, 0, size
.width
, size
.height
);
42 * Updates the layer. This returns false if there is still work to be done
45 public final boolean update(RenderContext context
) {
46 if (mTransactionLock
.isHeldByCurrentThread()) {
47 throw new RuntimeException("draw() called while transaction lock held by this " +
51 if (mTransactionLock
.tryLock()) {
53 performUpdates(context
);
56 mTransactionLock
.unlock();
63 /** Subclasses override this function to draw the layer. */
64 public abstract void draw(RenderContext context
);
66 /** Given the intrinsic size of the layer, returns the pixel boundaries of the layer rect. */
67 protected RectF
getBounds(RenderContext context
) {
68 return RectUtils
.scale(new RectF(mPosition
), context
.zoomFactor
/ mResolution
);
72 * Returns the region of the layer that is considered valid. The default
73 * implementation of this will return the bounds of the layer, but this
76 public Region
getValidRegion(RenderContext context
) {
77 return new Region(RectUtils
.round(getBounds(context
)));
81 * Call this before modifying the layer. Note that, for TileLayers, "modifying the layer"
82 * includes altering the underlying CairoImage in any way. Thus you must call this function
83 * before modifying the byte buffer associated with this layer.
85 * This function may block, so you should never call this on the main UI thread.
87 public void beginTransaction() {
88 if (mTransactionLock
.isHeldByCurrentThread())
89 throw new RuntimeException("Nested transactions are not supported");
90 mTransactionLock
.lock();
91 mInTransaction
= true;
92 mNewResolution
= mResolution
;
95 /** Call this when you're done modifying the layer. */
96 public void endTransaction() {
98 throw new RuntimeException("endTransaction() called outside a transaction");
99 mInTransaction
= false;
100 mTransactionLock
.unlock();
103 /** Returns true if the layer is currently in a transaction and false otherwise. */
104 protected boolean inTransaction() {
105 return mInTransaction
;
108 /** Returns the current layer position. */
109 public Rect
getPosition() {
113 /** Sets the position. Only valid inside a transaction. */
114 public void setPosition(Rect newPosition
) {
116 throw new RuntimeException("setPosition() is only valid inside a transaction");
117 mNewPosition
= newPosition
;
120 /** Returns the current layer's resolution. */
121 public float getResolution() {
126 * Sets the layer resolution. This value is used to determine how many pixels per
127 * device pixel this layer was rendered at. This will be reflected by scaling by
128 * the reciprocal of the resolution in the layer's transform() function.
129 * Only valid inside a transaction. */
130 public void setResolution(float newResolution
) {
132 throw new RuntimeException("setResolution() is only valid inside a transaction");
133 mNewResolution
= newResolution
;
136 public boolean usesDefaultProgram() {
137 return mUsesDefaultProgram
;
141 * Subclasses may override this method to perform custom layer updates. This will be called
142 * with the transaction lock held. Subclass implementations of this method must call the
143 * superclass implementation. Returns false if there is still work to be done after this
144 * update is complete.
146 protected void performUpdates(RenderContext context
) {
147 if (mNewPosition
!= null) {
148 mPosition
= mNewPosition
;
151 if (mNewResolution
!= 0.0f
) {
152 mResolution
= mNewResolution
;
153 mNewResolution
= 0.0f
;
158 * This function fills in the provided <tt>dest</tt> array with values to render a texture.
159 * The array is filled with 4 sets of {x, y, z, texture_x, texture_y} values (so 20 values
160 * in total) corresponding to the corners of the rect.
162 protected final void fillRectCoordBuffer(float[] dest
, RectF rect
, float viewWidth
, float viewHeight
,
163 Rect cropRect
, float texWidth
, float texHeight
) {
164 //x, y, z, texture_x, texture_y
165 dest
[0] = rect
.left
/ viewWidth
;
166 dest
[1] = rect
.bottom
/ viewHeight
;
168 dest
[3] = cropRect
.left
/ texWidth
;
169 dest
[4] = cropRect
.top
/ texHeight
;
171 dest
[5] = rect
.left
/ viewWidth
;
172 dest
[6] = rect
.top
/ viewHeight
;
174 dest
[8] = cropRect
.left
/ texWidth
;
175 dest
[9] = cropRect
.bottom
/ texHeight
;
177 dest
[10] = rect
.right
/ viewWidth
;
178 dest
[11] = rect
.bottom
/ viewHeight
;
180 dest
[13] = cropRect
.right
/ texWidth
;
181 dest
[14] = cropRect
.top
/ texHeight
;
183 dest
[15] = rect
.right
/ viewWidth
;
184 dest
[16] = rect
.top
/ viewHeight
;
186 dest
[18] = cropRect
.right
/ texWidth
;
187 dest
[19] = cropRect
.bottom
/ texHeight
;
190 public static class RenderContext
{
191 public final RectF viewport
;
192 public final RectF pageRect
;
193 public final float zoomFactor
;
194 public final int positionHandle
;
195 public final int textureHandle
;
196 public final FloatBuffer coordBuffer
;
198 public RenderContext(RectF aViewport
, RectF aPageRect
, float aZoomFactor
,
199 int aPositionHandle
, int aTextureHandle
, FloatBuffer aCoordBuffer
) {
200 viewport
= aViewport
;
201 pageRect
= aPageRect
;
202 zoomFactor
= aZoomFactor
;
203 positionHandle
= aPositionHandle
;
204 textureHandle
= aTextureHandle
;
205 coordBuffer
= aCoordBuffer
;
208 public boolean fuzzyEquals(RenderContext other
) {
212 return RectUtils
.fuzzyEquals(viewport
, other
.viewport
)
213 && RectUtils
.fuzzyEquals(pageRect
, other
.pageRect
)
214 && FloatUtils
.fuzzyEquals(zoomFactor
, other
.zoomFactor
);