Avoid potential negative array index access to cached text.
[LibreOffice.git] / android / source / src / java / org / mozilla / gecko / gfx / SingleTileLayer.java
blob0bc271678368a60ad6d0e0591df8cfdb26016d7f
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;
16 /**
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";
24 private Rect mMask;
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) {
40 this(false, 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];
62 /**
63 * Set an area to mask out when rendering.
65 public void setMask(Rect aMaskRect) {
66 mMask = aMaskRect;
69 @Override
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.
73 if (!initialized())
74 return;
76 mViewport.set(context.viewport);
78 if (repeats()) {
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);
90 } else {
91 mBounds.set(getBounds(context));
92 mTextureBounds.set(mBounds);
95 mBounds.roundOut(mIntBounds);
96 mMaskedBounds.set(mIntBounds);
97 if (mMask != null) {
98 mMaskedBounds.op(mMask, Region.Op.DIFFERENCE);
99 if (mMaskedBounds.isEmpty())
100 return;
103 // XXX Possible optimisation here, form this array so we can draw it in
104 // a single call.
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);