LibreOffice Module android (master) 1
ScrollbarLayer.java
Go to the documentation of this file.
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/. */
5
6package org.mozilla.gecko.gfx;
7
8import android.graphics.Bitmap;
9import android.graphics.Canvas;
10import android.graphics.Color;
11import android.graphics.Paint;
12import android.graphics.PorterDuff;
13import android.graphics.Rect;
14import android.graphics.RectF;
15import android.opengl.GLES20;
16
19
20import java.nio.ByteBuffer;
21import java.nio.FloatBuffer;
22
26public class ScrollbarLayer extends TileLayer {
27 private static String LOGTAG = LayerView.class.getName();
28 public static final long FADE_DELAY = 500; // milliseconds before fade-out starts
29 private static final float FADE_AMOUNT = 0.03f; // how much (as a percent) the scrollbar should fade per frame
30
31 private static final int PADDING = 1; // gap between scrollbar and edge of viewport
32 private static final int BAR_SIZE = 6;
33 private static final int CAP_RADIUS = (BAR_SIZE / 2);
34
35 private final boolean mVertical;
36 private final Bitmap mBitmap;
37 private final Canvas mCanvas;
38 private float mOpacity;
39
41 private int mProgram;
42 private int mPositionHandle;
43 private int mTextureHandle;
44 private int mSampleHandle;
45 private int mTMatrixHandle;
46 private int mOpacityHandle;
47
48 // Fragment shader used to draw the scroll-bar with opacity
49 private static final String FRAGMENT_SHADER =
50 "precision mediump float;\n" +
51 "varying vec2 vTexCoord;\n" +
52 "uniform sampler2D sTexture;\n" +
53 "uniform float uOpacity;\n" +
54 "void main() {\n" +
55 " gl_FragColor = texture2D(sTexture, vec2(vTexCoord.x, 1.0 - vTexCoord.y));\n" +
56 " gl_FragColor.a *= uOpacity;\n" +
57 "}\n";
58
59 // Dimensions of the texture image
60 private static final float TEX_HEIGHT = 8.0f;
61 private static final float TEX_WIDTH = 8.0f;
62
63 // Texture coordinates for the scrollbar's body
64 // We take a 1x1 pixel from the center of the image and scale it to become the bar
65 private static final float[] BODY_TEX_COORDS = {
66 // x, y
71 };
72
73 // Texture coordinates for the top cap of the scrollbar
74 private static final float[] TOP_CAP_TEX_COORDS = {
75 // x, y
76 0 , 1.0f - CAP_RADIUS/TEX_HEIGHT,
77 0 , 1.0f,
80 };
81
82 // Texture coordinates for the bottom cap of the scrollbar
83 private static final float[] BOT_CAP_TEX_COORDS = {
84 // x, y
85 0 , 1.0f - BAR_SIZE/TEX_HEIGHT,
86 0 , 1.0f - CAP_RADIUS/TEX_HEIGHT,
89 };
90
91 // Texture coordinates for the left cap of the scrollbar
92 private static final float[] LEFT_CAP_TEX_COORDS = {
93 // x, y
94 0 , 1.0f - BAR_SIZE/TEX_HEIGHT,
95 0 , 1.0f,
98 };
99
100 // Texture coordinates for the right cap of the scrollbar
101 private static final float[] RIGHT_CAP_TEX_COORDS = {
102 // x, y
104 CAP_RADIUS/TEX_WIDTH, 1.0f,
106 BAR_SIZE/TEX_WIDTH , 1.0f
107 };
108
109 private ScrollbarLayer(LayerRenderer renderer, CairoImage image, boolean vertical, ByteBuffer buffer) {
110 super(image, TileLayer.PaintMode.NORMAL);
111 mVertical = vertical;
112 mRenderer = renderer;
113
114 IntSize size = image.getSize();
115 mBitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888);
116 mCanvas = new Canvas(mBitmap);
117
118 // Paint a spot to use as the scroll indicator
119 Paint foregroundPaint = new Paint();
120 foregroundPaint.setAntiAlias(true);
121 foregroundPaint.setStyle(Paint.Style.FILL);
122 foregroundPaint.setColor(Color.argb(127, 0, 0, 0));
123
124 mCanvas.drawColor(Color.argb(0, 0, 0, 0), PorterDuff.Mode.CLEAR);
125 mCanvas.drawCircle(CAP_RADIUS, CAP_RADIUS, CAP_RADIUS, foregroundPaint);
126
127 mBitmap.copyPixelsToBuffer(buffer.asIntBuffer());
128 }
129
130 public static ScrollbarLayer create(LayerRenderer renderer, boolean vertical) {
131 // just create an empty image for now, it will get drawn
132 // on demand anyway
134 ByteBuffer buffer = DirectBufferAllocator.allocate(imageSize * imageSize * 4);
137 return new ScrollbarLayer(renderer, image, vertical, buffer);
138 }
139
140 private void createProgram() {
141 int vertexShader = LayerRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
143 int fragmentShader = LayerRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
145
146 mProgram = GLES20.glCreateProgram();
147 GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
148 GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
149 GLES20.glLinkProgram(mProgram); // creates OpenGL program executables
150
151 // Get handles to the shaders' vPosition, aTexCoord, sTexture, and uTMatrix members.
152 mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
153 mTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoord");
154 mSampleHandle = GLES20.glGetUniformLocation(mProgram, "sTexture");
155 mTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uTMatrix");
156 mOpacityHandle = GLES20.glGetUniformLocation(mProgram, "uOpacity");
157 }
158
159 private void activateProgram() {
160 // Add the program to the OpenGL environment
161 GLES20.glUseProgram(mProgram);
162
163 // Set the transformation matrix
164 GLES20.glUniformMatrix4fv(mTMatrixHandle, 1, false,
166
167 // Enable the arrays from which we get the vertex and texture coordinates
168 GLES20.glEnableVertexAttribArray(mPositionHandle);
169 GLES20.glEnableVertexAttribArray(mTextureHandle);
170
171 GLES20.glUniform1i(mSampleHandle, 0);
172 GLES20.glUniform1f(mOpacityHandle, mOpacity);
173 }
174
175 private void deactivateProgram() {
176 GLES20.glDisableVertexAttribArray(mTextureHandle);
177 GLES20.glDisableVertexAttribArray(mPositionHandle);
178 GLES20.glUseProgram(0);
179 }
180
186 public boolean fade() {
187 if (FloatUtils.fuzzyEquals(mOpacity, 0.0f)) {
188 return false;
189 }
190 beginTransaction(); // called on compositor thread
191 mOpacity = Math.max(mOpacity - FADE_AMOUNT, 0.0f);
193 return true;
194 }
195
201 public boolean unfade() {
202 if (FloatUtils.fuzzyEquals(mOpacity, 1.0f)) {
203 return false;
204 }
205 beginTransaction(); // called on compositor thread
206 mOpacity = 1.0f;
208
209 return true;
210 }
211
212 @Override
213 public void draw(RenderContext context) {
214 if (!initialized())
215 return;
216
217 // Create the shader program, if necessary
218 if (mProgram == 0) {
220 }
221
222 // Enable the shader program
225
226 GLES20.glEnable(GLES20.GL_BLEND);
227 GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
228
230 ? getVerticalRect(context)
231 : getHorizontalRect(context));
232 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureID());
233
234 float viewWidth = context.viewport.width();
235 float viewHeight = context.viewport.height();
236
237 float top = viewHeight - rect.top;
238 float bot = viewHeight - rect.bottom;
239
240 // Coordinates for the scrollbar's body combined with the texture coordinates
241 float[] bodyCoords = {
242 // x, y, z, texture_x, texture_y
243 rect.left/viewWidth, bot/viewHeight, 0,
245
246 rect.left/viewWidth, (bot+rect.height())/viewHeight, 0,
248
249 (rect.left+rect.width())/viewWidth, bot/viewHeight, 0,
251
252 (rect.left+rect.width())/viewWidth, (bot+rect.height())/viewHeight, 0,
254 };
255
256 // Get the buffer and handles from the context
257 FloatBuffer coordBuffer = context.coordBuffer;
258 int positionHandle = mPositionHandle;
259 int textureHandle = mTextureHandle;
260
261 // Make sure we are at position zero in the buffer in case other draw methods did not
262 // clean up after themselves
263 coordBuffer.position(0);
264 coordBuffer.put(bodyCoords);
265
266 // Unbind any the current array buffer so we can use client side buffers
267 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
268
269 // Vertex coordinates are x,y,z starting at position 0 into the buffer.
270 coordBuffer.position(0);
271 GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
272 coordBuffer);
273
274 // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
275 coordBuffer.position(3);
276 GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
277 coordBuffer);
278
279 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
280
281 // Reset the position in the buffer for the next set of vertex and texture coordinates.
282 coordBuffer.position(0);
283
284 if (mVertical) {
285 // top endcap
286 float[] topCap = {
287 // x, y, z, texture_x, texture_y
288 rect.left/viewWidth, top/viewHeight, 0,
290
291 rect.left/viewWidth, (top+CAP_RADIUS)/viewHeight, 0,
293
294 (rect.left+BAR_SIZE)/viewWidth, top/viewHeight, 0,
296
297 (rect.left+BAR_SIZE)/viewWidth, (top+CAP_RADIUS)/viewHeight, 0,
299 };
300
301 coordBuffer.put(topCap);
302
303 // Vertex coordinates are x,y,z starting at position 0 into the buffer.
304 coordBuffer.position(0);
305 GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
306 coordBuffer);
307
308 // Texture coordinates are texture_x, texture_y starting at position 3 into the
309 // buffer.
310 coordBuffer.position(3);
311 GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
312 coordBuffer);
313
314 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
315
316 // Reset the position in the buffer for the next set of vertex and texture
317 // coordinates.
318 coordBuffer.position(0);
319
320 // bottom endcap
321 float[] botCap = {
322 // x, y, z, texture_x, texture_y
323 rect.left/viewWidth, (bot-CAP_RADIUS)/viewHeight, 0,
325
326 rect.left/viewWidth, (bot)/viewHeight, 0,
328
329 (rect.left+BAR_SIZE)/viewWidth, (bot-CAP_RADIUS)/viewHeight, 0,
331
332 (rect.left+BAR_SIZE)/viewWidth, (bot)/viewHeight, 0,
334 };
335
336 coordBuffer.put(botCap);
337
338 // Vertex coordinates are x,y,z starting at position 0 into the buffer.
339 coordBuffer.position(0);
340 GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
341 coordBuffer);
342
343 // Texture coordinates are texture_x, texture_y starting at position 3 into the
344 // buffer.
345 coordBuffer.position(3);
346 GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
347 coordBuffer);
348
349 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
350
351 // Reset the position in the buffer for the next set of vertex and texture
352 // coordinates.
353 coordBuffer.position(0);
354 } else {
355 // left endcap
356 float[] leftCap = {
357 // x, y, z, texture_x, texture_y
358 (rect.left-CAP_RADIUS)/viewWidth, bot/viewHeight, 0,
360 (rect.left-CAP_RADIUS)/viewWidth, (bot+BAR_SIZE)/viewHeight, 0,
362 (rect.left)/viewWidth, bot/viewHeight, 0, LEFT_CAP_TEX_COORDS[4],
364 (rect.left)/viewWidth, (bot+BAR_SIZE)/viewHeight, 0,
366 };
367
368 coordBuffer.put(leftCap);
369
370 // Vertex coordinates are x,y,z starting at position 0 into the buffer.
371 coordBuffer.position(0);
372 GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
373 coordBuffer);
374
375 // Texture coordinates are texture_x, texture_y starting at position 3 into the
376 // buffer.
377 coordBuffer.position(3);
378 GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
379 coordBuffer);
380
381 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
382
383 // Reset the position in the buffer for the next set of vertex and texture
384 // coordinates.
385 coordBuffer.position(0);
386
387 // right endcap
388 float[] rightCap = {
389 // x, y, z, texture_x, texture_y
390 rect.right/viewWidth, (bot)/viewHeight, 0,
392
393 rect.right/viewWidth, (bot+BAR_SIZE)/viewHeight, 0,
395
396 (rect.right+CAP_RADIUS)/viewWidth, (bot)/viewHeight, 0,
398
399 (rect.right+CAP_RADIUS)/viewWidth, (bot+BAR_SIZE)/viewHeight, 0,
401 };
402
403 coordBuffer.put(rightCap);
404
405 // Vertex coordinates are x,y,z starting at position 0 into the buffer.
406 coordBuffer.position(0);
407 GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20,
408 coordBuffer);
409
410 // Texture coordinates are texture_x, texture_y starting at position 3 into the
411 // buffer.
412 coordBuffer.position(3);
413 GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20,
414 coordBuffer);
415
416 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
417 }
418
419 // Enable the default shader program again
422 }
423
424 private RectF getVerticalRect(RenderContext context) {
425 RectF viewport = context.viewport;
426 RectF pageRect = context.pageRect;
427 float barStart = ((viewport.top - pageRect.top) * (viewport.height() / pageRect.height())) + CAP_RADIUS;
428 float barEnd = ((viewport.bottom - pageRect.top) * (viewport.height() / pageRect.height())) - CAP_RADIUS;
429 if (barStart > barEnd) {
430 float middle = (barStart + barEnd) / 2.0f;
431 barStart = barEnd = middle;
432 }
433 float right = viewport.width() - PADDING;
434 return new RectF(right - BAR_SIZE, barStart, right, barEnd);
435 }
436
437 private RectF getHorizontalRect(RenderContext context) {
438 RectF viewport = context.viewport;
439 RectF pageRect = context.pageRect;
440 float barStart = ((viewport.left - pageRect.left) * (viewport.width() / pageRect.width())) + CAP_RADIUS;
441 float barEnd = ((viewport.right - pageRect.left) * (viewport.width() / pageRect.width())) - CAP_RADIUS;
442 if (barStart > barEnd) {
443 float middle = (barStart + barEnd) / 2.0f;
444 barStart = barEnd = middle;
445 }
446 float bottom = viewport.height() - PADDING;
447 return new RectF(barStart, bottom - BAR_SIZE, barEnd, bottom);
448 }
449}
450
451/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
A Cairo image that simply saves a buffer of pixel data.
static int nextPowerOfTwo(int value)
Definition: IntSize.java:52
The layer renderer implements the rendering logic for a layer view.
static final float[] DEFAULT_TEXTURE_MATRIX
static int loadShader(int type, String shaderCode)
static final String DEFAULT_VERTEX_SHADER
A view rendered by the layer compositor.
Definition: LayerView.java:41
void endTransaction()
Call this when you're done modifying the layer.
Definition: Layer.java:96
void beginTransaction()
Call this before modifying the layer.
Definition: Layer.java:87
static Rect round(RectF rect)
Returns the nearest integer rect of the given rect.
Definition: RectUtils.java:61
boolean unfade()
Restore the opacity of the scrollbar to fully opaque.
static ScrollbarLayer create(LayerRenderer renderer, boolean vertical)
static final float[] LEFT_CAP_TEX_COORDS
void draw(RenderContext context)
Subclasses override this function to draw the layer.
boolean fade()
Decrease the opacity of the scrollbar by one frame's worth.
ScrollbarLayer(LayerRenderer renderer, CairoImage image, boolean vertical, ByteBuffer buffer)
RectF getHorizontalRect(RenderContext context)
RectF getVerticalRect(RenderContext context)
Base class for tile layers, which encapsulate the logic needed to draw textured tiles in OpenGL ES.
Definition: TileLayer.java:18
static boolean fuzzyEquals(float a, float b)
Definition: FloatUtils.java:13
OString right
OString top
OString bottom
Size imageSize(const sk_sp< SkImage > &image)
size