Update git submodules
[LibreOffice.git] / android / source / src / java / org / mozilla / gecko / gfx / SubTile.java
blobd2b0bf9e8114a3a8750c62a69962e976dfc00722
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;
11 import android.graphics.RegionIterator;
12 import android.opengl.GLES20;
13 import android.util.Log;
15 import org.libreoffice.TileIdentifier;
17 import java.nio.ByteBuffer;
18 import java.nio.FloatBuffer;
20 public class SubTile extends Layer {
21 private static String LOGTAG = SubTile.class.getSimpleName();
22 public final TileIdentifier id;
24 private final RectF mBounds;
25 private final RectF mTextureBounds;
26 private final RectF mViewport;
27 private final Rect mIntBounds;
28 private final Rect mSubRect;
29 private final RectF mSubRectF;
30 private final Region mMaskedBounds;
31 private final Rect mCropRect;
32 private final RectF mObjRectF;
33 private final float[] mCoords;
35 public boolean markedForRemoval = false;
37 private CairoImage mImage;
38 private IntSize mSize;
39 private int[] mTextureIDs;
40 private boolean mDirtyTile;
42 public SubTile(TileIdentifier id) {
43 super();
44 this.id = id;
46 mBounds = new RectF();
47 mTextureBounds = new RectF();
48 mViewport = new RectF();
49 mIntBounds = new Rect();
50 mSubRect = new Rect();
51 mSubRectF = new RectF();
52 mMaskedBounds = new Region();
53 mCropRect = new Rect();
54 mObjRectF = new RectF();
55 mCoords = new float[20];
57 mImage = null;
58 mTextureIDs = null;
59 mSize = new IntSize(0, 0);
60 mDirtyTile = false;
63 public void setImage(CairoImage image) {
64 if (image.getSize().isPositive()) {
65 this.mImage = image;
69 public void refreshTileMetrics() {
70 setPosition(id.getCSSRect());
73 public void markForRemoval() {
74 markedForRemoval = true;
77 protected int getTextureID() {
78 return mTextureIDs[0];
81 protected boolean initialized() {
82 return mTextureIDs != null;
85 @Override
86 protected void finalize() throws Throwable {
87 try {
88 destroyImage();
89 cleanTexture();
90 } finally {
91 super.finalize();
95 private void cleanTexture() {
96 if (mTextureIDs != null) {
97 TextureReaper.get().add(mTextureIDs);
98 mTextureIDs = null;
99 TextureReaper.get().reap();
103 public void destroy() {
104 try {
105 destroyImage();
106 cleanTexture();
107 } catch (Exception ex) {
108 Log.e(LOGTAG, "Error clearing buffers: ", ex);
112 public void destroyImage() {
113 if (mImage != null) {
114 mImage.destroy();
115 mImage = null;
120 * Invalidates the entire buffer so that it will be uploaded again. Only valid inside a
121 * transaction.
123 public void invalidate() {
124 if (!inTransaction()) {
125 throw new RuntimeException("invalidate() is only valid inside a transaction");
127 if (mImage == null) {
128 return;
130 mDirtyTile = true;
134 * Remove the texture if the image is of different size than the current uploaded texture.
136 private void validateTexture() {
137 IntSize textureSize = mImage.getSize().nextPowerOfTwo();
139 if (!textureSize.equals(mSize)) {
140 mSize = textureSize;
141 cleanTexture();
145 @Override
146 protected void performUpdates(RenderContext context) {
147 super.performUpdates(context);
148 if (mImage == null && !mDirtyTile) {
149 return;
151 validateTexture();
152 uploadNewTexture();
153 mDirtyTile = false;
156 private void uploadNewTexture() {
157 ByteBuffer imageBuffer = mImage.getBuffer();
158 if (imageBuffer == null) {
159 return;
162 if (mTextureIDs == null) {
163 mTextureIDs = new int[1];
164 GLES20.glGenTextures(mTextureIDs.length, mTextureIDs, 0);
167 int cairoFormat = mImage.getFormat();
168 CairoGLInfo glInfo = new CairoGLInfo(cairoFormat);
170 bindAndSetGLParameters();
172 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, glInfo.internalFormat,
173 mSize.width, mSize.height, 0, glInfo.format, glInfo.type, imageBuffer);
175 destroyImage();
178 private void bindAndSetGLParameters() {
179 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
180 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIDs[0]);
182 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
183 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
184 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
185 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
188 @Override
189 public void draw(RenderContext context) {
190 // mTextureIDs may be null here during startup if Layer.java's draw method
191 // failed to acquire the transaction lock and call performUpdates.
192 if (!initialized())
193 return;
195 mViewport.set(context.viewport);
197 mBounds.set(getBounds(context));
198 mTextureBounds.set(mBounds);
200 mBounds.roundOut(mIntBounds);
201 mMaskedBounds.set(mIntBounds);
203 // XXX Possible optimisation here, form this array so we can draw it in
204 // a single call.
205 RegionIterator iterator = new RegionIterator(mMaskedBounds);
206 while (iterator.next(mSubRect)) {
207 // Compensate for rounding errors at the edge of the tile caused by
208 // the roundOut above
209 mSubRectF.set(Math.max(mBounds.left, (float) mSubRect.left),
210 Math.max(mBounds.top, (float) mSubRect.top),
211 Math.min(mBounds.right, (float) mSubRect.right),
212 Math.min(mBounds.bottom, (float) mSubRect.bottom));
214 // This is the left/top/right/bottom of the rect, relative to the
215 // bottom-left of the layer, to use for texture coordinates.
216 mCropRect.set(Math.round(mSubRectF.left - mBounds.left),
217 Math.round(mBounds.bottom - mSubRectF.top),
218 Math.round(mSubRectF.right - mBounds.left),
219 Math.round(mBounds.bottom - mSubRectF.bottom));
221 mObjRectF.set(mSubRectF.left - mViewport.left,
222 mViewport.bottom - mSubRectF.bottom,
223 mSubRectF.right - mViewport.left,
224 mViewport.bottom - mSubRectF.top);
226 fillRectCoordBuffer(mCoords, mObjRectF, mViewport.width(), mViewport.height(), mCropRect, mTextureBounds.width(), mTextureBounds.height());
228 FloatBuffer coordBuffer = context.coordBuffer;
229 int positionHandle = context.positionHandle;
230 int textureHandle = context.textureHandle;
232 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
233 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureID());
235 // Make sure we are at position zero in the buffer
236 coordBuffer.position(0);
237 coordBuffer.put(mCoords);
239 // Unbind any the current array buffer so we can use client side buffers
240 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
242 // Vertex coordinates are x,y,z starting at position 0 into the buffer.
243 coordBuffer.position(0);
244 GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20, coordBuffer);
246 // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
247 coordBuffer.position(3);
248 GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20, coordBuffer);
249 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);