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
;
14 import java
.nio
.FloatBuffer
;
17 * Encapsulates the logic needed to draw a single textured tile.
19 * TODO: Repeating textures really should be their own type of layer.
21 public class SingleTileLayer
extends TileLayer
{
22 private static final String LOGTAG
= "GeckoSingleTileLayer";
26 // To avoid excessive GC, declare some objects here that would otherwise
27 // be created and destroyed frequently during draw().
28 private final RectF mBounds
;
29 private final RectF mTextureBounds
;
30 private final RectF mViewport
;
31 private final Rect mIntBounds
;
32 private final Rect mSubRect
;
33 private final RectF mSubRectF
;
34 private final Region mMaskedBounds
;
35 private final Rect mCropRect
;
36 private final RectF mObjRectF
;
37 private final float[] mCoords
;
39 public SingleTileLayer(CairoImage image
) {
43 public SingleTileLayer(boolean repeat
, CairoImage image
) {
44 this(image
, repeat ? TileLayer
.PaintMode
.REPEAT
: TileLayer
.PaintMode
.NORMAL
);
47 public SingleTileLayer(CairoImage image
, TileLayer
.PaintMode paintMode
) {
48 super(image
, paintMode
);
50 mBounds
= new RectF();
51 mTextureBounds
= new RectF();
52 mViewport
= new RectF();
53 mIntBounds
= new Rect();
54 mSubRect
= new Rect();
55 mSubRectF
= new RectF();
56 mMaskedBounds
= new Region();
57 mCropRect
= new Rect();
58 mObjRectF
= new RectF();
59 mCoords
= new float[20];
63 * Set an area to mask out when rendering.
65 public void setMask(Rect aMaskRect
) {
70 public void draw(RenderContext context
) {
71 // mTextureIDs may be null here during startup if Layer.java's draw method
72 // failed to acquire the transaction lock and call performUpdates.
76 mViewport
.set(context
.viewport
);
79 // If we're repeating, we want to adjust the texture bounds so that
80 // the texture repeats the correct number of times when drawn at
81 // the size of the viewport.
82 mBounds
.set(getBounds(context
));
83 mTextureBounds
.set(0.0f
, 0.0f
, mBounds
.width(), mBounds
.height());
84 mBounds
.set(0.0f
, 0.0f
, mViewport
.width(), mViewport
.height());
85 } else if (stretches()) {
86 // If we're stretching, we just want the bounds and texture bounds
87 // to fit to the page.
88 mBounds
.set(context
.pageRect
);
89 mTextureBounds
.set(mBounds
);
91 mBounds
.set(getBounds(context
));
92 mTextureBounds
.set(mBounds
);
95 mBounds
.roundOut(mIntBounds
);
96 mMaskedBounds
.set(mIntBounds
);
98 mMaskedBounds
.op(mMask
, Region
.Op
.DIFFERENCE
);
99 if (mMaskedBounds
.isEmpty())
103 // XXX Possible optimisation here, form this array so we can draw it in
105 RegionIterator i
= new RegionIterator(mMaskedBounds
);
106 while (i
.next(mSubRect
)) {
107 // Compensate for rounding errors at the edge of the tile caused by
108 // the roundOut above
109 mSubRectF
.set(Math
.max(mBounds
.left
, (float)mSubRect
.left
),
110 Math
.max(mBounds
.top
, (float)mSubRect
.top
),
111 Math
.min(mBounds
.right
, (float)mSubRect
.right
),
112 Math
.min(mBounds
.bottom
, (float)mSubRect
.bottom
));
114 // This is the left/top/right/bottom of the rect, relative to the
115 // bottom-left of the layer, to use for texture coordinates.
116 mCropRect
.set(Math
.round(mSubRectF
.left
- mBounds
.left
),
117 Math
.round(mBounds
.bottom
- mSubRectF
.top
),
118 Math
.round(mSubRectF
.right
- mBounds
.left
),
119 Math
.round(mBounds
.bottom
- mSubRectF
.bottom
));
121 mObjRectF
.set(mSubRectF
.left
- mViewport
.left
,
122 mViewport
.bottom
- mSubRectF
.bottom
,
123 mSubRectF
.right
- mViewport
.left
,
124 mViewport
.bottom
- mSubRectF
.top
);
126 fillRectCoordBuffer(mCoords
, mObjRectF
, mViewport
.width(), mViewport
.height(),
127 mCropRect
, mTextureBounds
.width(), mTextureBounds
.height());
129 FloatBuffer coordBuffer
= context
.coordBuffer
;
130 int positionHandle
= context
.positionHandle
;
131 int textureHandle
= context
.textureHandle
;
133 GLES20
.glActiveTexture(GLES20
.GL_TEXTURE0
);
134 GLES20
.glBindTexture(GLES20
.GL_TEXTURE_2D
, getTextureID());
136 // Make sure we are at position zero in the buffer
137 coordBuffer
.position(0);
138 coordBuffer
.put(mCoords
);
140 // Unbind any the current array buffer so we can use client side buffers
141 GLES20
.glBindBuffer(GLES20
.GL_ARRAY_BUFFER
, 0);
143 // Vertex coordinates are x,y,z starting at position 0 into the buffer.
144 coordBuffer
.position(0);
145 GLES20
.glVertexAttribPointer(positionHandle
, 3, GLES20
.GL_FLOAT
, false, 20, coordBuffer
);
147 // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
148 coordBuffer
.position(3);
149 GLES20
.glVertexAttribPointer(textureHandle
, 2, GLES20
.GL_FLOAT
, false, 20, coordBuffer
);
150 GLES20
.glDrawArrays(GLES20
.GL_TRIANGLE_STRIP
, 0, 4);