Bug 704784 - Tweak scrollbars to look nicer [r=pcwalton]

Scrollbars now have rounded endcaps, are a little smaller, and there
is a 1-pixel gap between the bar and the edge of the viewport. Just
generally making them look nicer.
This commit is contained in:
Kartikaya Gupta 2011-12-09 15:58:36 -05:00
parent 891ca8a49d
commit d8bfd1e721
2 changed files with 85 additions and 13 deletions

View File

@ -167,6 +167,20 @@ public abstract class Layer {
}
}
/* Returns the power of two that is greater than or equal to value */
protected static int nextPowerOfTwo(int value) {
// code taken from http://acius2.blogspot.com/2007/11/calculating-next-power-of-2.html
if (0 == value--) {
return 1;
}
value = (value >> 1) | value;
value = (value >> 2) | value;
value = (value >> 4) | value;
value = (value >> 8) | value;
value = (value >> 16) | value;
return value + 1;
}
public static class RenderContext {
public final RectF viewport;
public final FloatSize pageSize;

View File

@ -37,7 +37,13 @@
package org.mozilla.gecko.gfx;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.opengl.GLES11;
import android.opengl.GLES11Ext;
@ -49,7 +55,16 @@ import javax.microedition.khronos.opengles.GL10;
* Draws a small rect. This is scaled to become a scrollbar.
*/
public class ScrollbarLayer extends TileLayer {
private static final int BAR_SIZE = 8; // has to be power of 2
private static final int PADDING = 1; // gap between scrollbar and edge of viewport
private static final int BAR_SIZE = 6;
private static final int CAP_RADIUS = (BAR_SIZE / 2);
private static final int SCROLLBAR_COLOR = Color.argb(127, 0, 0, 0);
private static final int[] CROPRECT_MIDPIXEL = new int[] { CAP_RADIUS, CAP_RADIUS, 1, 1 };
private static final int[] CROPRECT_TOPCAP = new int[] { 0, CAP_RADIUS, BAR_SIZE, -CAP_RADIUS };
private static final int[] CROPRECT_BOTTOMCAP = new int[] { 0, BAR_SIZE, BAR_SIZE, -CAP_RADIUS };
private static final int[] CROPRECT_LEFTCAP = new int[] { 0, BAR_SIZE, CAP_RADIUS, -BAR_SIZE };
private static final int[] CROPRECT_RIGHTCAP = new int[] { CAP_RADIUS, BAR_SIZE, CAP_RADIUS, -BAR_SIZE };
private final boolean mVertical;
@ -59,9 +74,22 @@ public class ScrollbarLayer extends TileLayer {
}
public static ScrollbarLayer create(boolean vertical) {
ByteBuffer buffer = ByteBuffer.allocateDirect(4);
buffer.put(3, (byte)127); // Set A to 0.5; leave R/G/B at 0.
CairoImage image = new BufferedCairoImage(buffer, 1, 1, CairoImage.FORMAT_ARGB32);
int imageSize = nextPowerOfTwo(BAR_SIZE);
Bitmap bitmap = Bitmap.createBitmap(imageSize, imageSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint foregroundPaint = new Paint();
foregroundPaint.setAntiAlias(true);
foregroundPaint.setStyle(Paint.Style.FILL);
foregroundPaint.setColor(SCROLLBAR_COLOR);
canvas.drawColor(Color.argb(0, 0, 0, 0), PorterDuff.Mode.CLEAR);
canvas.drawCircle(CAP_RADIUS, CAP_RADIUS, CAP_RADIUS, foregroundPaint);
ByteBuffer buffer = ByteBuffer.allocateDirect(imageSize * imageSize * 4);
bitmap.copyPixelsToBuffer(buffer.asIntBuffer());
CairoImage image = new BufferedCairoImage(buffer, imageSize, imageSize, CairoImage.FORMAT_ARGB32);
return new ScrollbarLayer(image, vertical);
}
@ -73,11 +101,31 @@ public class ScrollbarLayer extends TileLayer {
try {
GLES11.glEnable(GL10.GL_BLEND);
RectF rect = mVertical ? getVerticalRect(context) : getHorizontalRect(context);
Rect rect = RectUtils.round(mVertical ? getVerticalRect(context) : getHorizontalRect(context));
GLES11.glBindTexture(GL10.GL_TEXTURE_2D, getTextureID());
float y = context.viewport.height() - rect.bottom;
GLES11Ext.glDrawTexfOES(rect.left, y, 0.0f, rect.width(), rect.height());
float viewHeight = context.viewport.height();
// for the body of the scrollbar, we take a 1x1 pixel from the center of the image
// and scale it to become the bar
GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_MIDPIXEL, 0);
GLES11Ext.glDrawTexfOES(rect.left, viewHeight - rect.bottom, 0.0f, rect.width(), rect.height());
if (mVertical) {
// top endcap
GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_TOPCAP, 0);
GLES11Ext.glDrawTexfOES(rect.left, viewHeight - rect.top, 0.0f, BAR_SIZE, CAP_RADIUS);
// bottom endcap
GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_BOTTOMCAP, 0);
GLES11Ext.glDrawTexfOES(rect.left, viewHeight - (rect.bottom + CAP_RADIUS), 0.0f, BAR_SIZE, CAP_RADIUS);
} else {
// left endcap
GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_LEFTCAP, 0);
GLES11Ext.glDrawTexfOES(rect.left - CAP_RADIUS, viewHeight - rect.bottom, 0.0f, CAP_RADIUS, BAR_SIZE);
// right endcap
GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, CROPRECT_RIGHTCAP, 0);
GLES11Ext.glDrawTexfOES(rect.right, viewHeight - rect.bottom, 0.0f, CAP_RADIUS, BAR_SIZE);
}
} finally {
GLES11.glDisable(GL10.GL_BLEND);
}
@ -86,16 +134,26 @@ public class ScrollbarLayer extends TileLayer {
private RectF getVerticalRect(RenderContext context) {
RectF viewport = context.viewport;
FloatSize pageSize = context.pageSize;
float barStart = viewport.height() * viewport.top / pageSize.height;
float barEnd = viewport.height() * viewport.bottom / pageSize.height;
return new RectF(viewport.width() - BAR_SIZE, barStart, viewport.width(), barEnd);
float barStart = (viewport.height() * viewport.top / pageSize.height) + CAP_RADIUS;
float barEnd = (viewport.height() * viewport.bottom / pageSize.height) - CAP_RADIUS;
if (barStart > barEnd) {
float middle = (barStart + barEnd) / 2.0f;
barStart = barEnd = middle;
}
float right = viewport.width() - PADDING;
return new RectF(right - BAR_SIZE, barStart, right, barEnd);
}
private RectF getHorizontalRect(RenderContext context) {
RectF viewport = context.viewport;
FloatSize pageSize = context.pageSize;
float barStart = viewport.width() * viewport.left / pageSize.width;
float barEnd = viewport.width() * viewport.right / pageSize.width;
return new RectF(barStart, viewport.height() - BAR_SIZE, barEnd, viewport.height());
float barStart = (viewport.width() * viewport.left / pageSize.width) + CAP_RADIUS;
float barEnd = (viewport.width() * viewport.right / pageSize.width) - CAP_RADIUS;
if (barStart > barEnd) {
float middle = (barStart + barEnd) / 2.0f;
barStart = barEnd = middle;
}
float bottom = viewport.height() - PADDING;
return new RectF(barStart, bottom - BAR_SIZE, barEnd, bottom);
}
}