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
) {
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];
59 mSize
= new IntSize(0, 0);
63 public void setImage(CairoImage image
) {
64 if (image
.getSize().isPositive()) {
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;
86 protected void finalize() throws Throwable
{
95 private void cleanTexture() {
96 if (mTextureIDs
!= null) {
97 TextureReaper
.get().add(mTextureIDs
);
99 TextureReaper
.get().reap();
103 public void destroy() {
107 } catch (Exception ex
) {
108 Log
.e(LOGTAG
, "Error clearing buffers: ", ex
);
112 public void destroyImage() {
113 if (mImage
!= null) {
120 * Invalidates the entire buffer so that it will be uploaded again. Only valid inside a
123 public void invalidate() {
124 if (!inTransaction()) {
125 throw new RuntimeException("invalidate() is only valid inside a transaction");
127 if (mImage
== null) {
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
)) {
146 protected void performUpdates(RenderContext context
) {
147 super.performUpdates(context
);
148 if (mImage
== null && !mDirtyTile
) {
156 private void uploadNewTexture() {
157 ByteBuffer imageBuffer
= mImage
.getBuffer();
158 if (imageBuffer
== null) {
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 IntSize bufferSize
= mImage
.getSize();
174 GLES20
.glTexImage2D(GLES20
.GL_TEXTURE_2D
, 0, glInfo
.internalFormat
,
175 mSize
.width
, mSize
.height
, 0, glInfo
.format
, glInfo
.type
, imageBuffer
);
180 private void bindAndSetGLParameters() {
181 GLES20
.glActiveTexture(GLES20
.GL_TEXTURE0
);
182 GLES20
.glBindTexture(GLES20
.GL_TEXTURE_2D
, mTextureIDs
[0]);
184 GLES20
.glTexParameterf(GLES20
.GL_TEXTURE_2D
, GLES20
.GL_TEXTURE_MIN_FILTER
, GLES20
.GL_LINEAR
);
185 GLES20
.glTexParameterf(GLES20
.GL_TEXTURE_2D
, GLES20
.GL_TEXTURE_MAG_FILTER
, GLES20
.GL_LINEAR
);
186 GLES20
.glTexParameterf(GLES20
.GL_TEXTURE_2D
, GLES20
.GL_TEXTURE_WRAP_S
, GLES20
.GL_CLAMP_TO_EDGE
);
187 GLES20
.glTexParameterf(GLES20
.GL_TEXTURE_2D
, GLES20
.GL_TEXTURE_WRAP_T
, GLES20
.GL_CLAMP_TO_EDGE
);
191 public void draw(RenderContext context
) {
192 // mTextureIDs may be null here during startup if Layer.java's draw method
193 // failed to acquire the transaction lock and call performUpdates.
197 mViewport
.set(context
.viewport
);
199 mBounds
.set(getBounds(context
));
200 mTextureBounds
.set(mBounds
);
202 mBounds
.roundOut(mIntBounds
);
203 mMaskedBounds
.set(mIntBounds
);
205 // XXX Possible optimisation here, form this array so we can draw it in
207 RegionIterator iterator
= new RegionIterator(mMaskedBounds
);
208 while (iterator
.next(mSubRect
)) {
209 // Compensate for rounding errors at the edge of the tile caused by
210 // the roundOut above
211 mSubRectF
.set(Math
.max(mBounds
.left
, (float) mSubRect
.left
),
212 Math
.max(mBounds
.top
, (float) mSubRect
.top
),
213 Math
.min(mBounds
.right
, (float) mSubRect
.right
),
214 Math
.min(mBounds
.bottom
, (float) mSubRect
.bottom
));
216 // This is the left/top/right/bottom of the rect, relative to the
217 // bottom-left of the layer, to use for texture coordinates.
218 mCropRect
.set(Math
.round(mSubRectF
.left
- mBounds
.left
),
219 Math
.round(mBounds
.bottom
- mSubRectF
.top
),
220 Math
.round(mSubRectF
.right
- mBounds
.left
),
221 Math
.round(mBounds
.bottom
- mSubRectF
.bottom
));
223 mObjRectF
.set(mSubRectF
.left
- mViewport
.left
,
224 mViewport
.bottom
- mSubRectF
.bottom
,
225 mSubRectF
.right
- mViewport
.left
,
226 mViewport
.bottom
- mSubRectF
.top
);
228 fillRectCoordBuffer(mCoords
, mObjRectF
, mViewport
.width(), mViewport
.height(), mCropRect
, mTextureBounds
.width(), mTextureBounds
.height());
230 FloatBuffer coordBuffer
= context
.coordBuffer
;
231 int positionHandle
= context
.positionHandle
;
232 int textureHandle
= context
.textureHandle
;
234 GLES20
.glActiveTexture(GLES20
.GL_TEXTURE0
);
235 GLES20
.glBindTexture(GLES20
.GL_TEXTURE_2D
, getTextureID());
237 // Make sure we are at position zero in the buffer
238 coordBuffer
.position(0);
239 coordBuffer
.put(mCoords
);
241 // Unbind any the current array buffer so we can use client side buffers
242 GLES20
.glBindBuffer(GLES20
.GL_ARRAY_BUFFER
, 0);
244 // Vertex coordinates are x,y,z starting at position 0 into the buffer.
245 coordBuffer
.position(0);
246 GLES20
.glVertexAttribPointer(positionHandle
, 3, GLES20
.GL_FLOAT
, false, 20, coordBuffer
);
248 // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
249 coordBuffer
.position(3);
250 GLES20
.glVertexAttribPointer(textureHandle
, 2, GLES20
.GL_FLOAT
, false, 20, coordBuffer
);
251 GLES20
.glDrawArrays(GLES20
.GL_TRIANGLE_STRIP
, 0, 4);