Bug 710533 - Tint the checkerboard with the background color of the page. r=Cwiiis

This commit is contained in:
Patrick Walton 2012-01-23 20:10:24 -08:00
parent 7ecf47a080
commit 9120d78e9d
7 changed files with 226 additions and 8 deletions

View File

@ -101,6 +101,7 @@ FENNEC_JAVA_FILES = \
gfx/CairoGLInfo.java \
gfx/CairoImage.java \
gfx/CairoUtils.java \
gfx/CheckerboardImage.java \
gfx/FloatSize.java \
gfx/GeckoSoftwareLayerClient.java \
gfx/InputConnectionHandler.java \
@ -510,7 +511,6 @@ MOZ_ANDROID_DRAWABLES += \
mobile/android/base/resources/drawable/tabs_tray_close_button.xml \
mobile/android/base/resources/drawable/tabs_tray_list_divider.xml \
mobile/android/base/resources/drawable/tabs_tray_list_selector.xml \
mobile/android/base/resources/drawable/checkerboard.png \
mobile/android/base/resources/drawable/shadow.png \
$(NULL)

View File

@ -0,0 +1,150 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Patrick Walton <pcwalton@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.GeckoAppShell;
import android.graphics.Color;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.util.Arrays;
/** A Cairo image that displays a tinted checkerboard. */
public class CheckerboardImage extends CairoImage {
// The width and height of the checkerboard tile.
private static final int SIZE = 16;
// The pixel format of the checkerboard tile.
private static final int FORMAT = CairoImage.FORMAT_RGB16_565;
// The color to mix in to tint the background color.
private static final int TINT_COLOR = Color.GRAY;
// The amount to mix in.
private static final float TINT_OPACITY = 0.4f;
private ByteBuffer mBuffer;
private int mMainColor;
/** Creates a new checkerboard image. */
public CheckerboardImage() {
int bpp = CairoUtils.bitsPerPixelForCairoFormat(FORMAT);
mBuffer = GeckoAppShell.allocateDirectBuffer(SIZE * SIZE * bpp / 8);
setColor(Color.WHITE);
}
/** Returns the current color of the checkerboard. */
public int getColor() {
return mMainColor;
}
/** Sets the color of the checkerboard image and regenerates it. */
public void setColor(int color) {
if (mMainColor == color) {
return;
}
mMainColor = color;
int tintColor = tint(mMainColor);
short mainColor16 = convertTo16Bit(mMainColor), tintColor16 = convertTo16Bit(tintColor);
short[] mainPattern = new short[SIZE / 2], tintPattern = new short[SIZE / 2];
Arrays.fill(mainPattern, mainColor16);
Arrays.fill(tintPattern, tintColor16);
// The checkerboard pattern looks like this:
//
// +---+---+
// | N | T | N = normal
// +---+---+ T = tinted
// | T | N |
// +---+---+
mBuffer.rewind();
ShortBuffer shortBuffer = mBuffer.asShortBuffer();
for (int i = 0; i < SIZE / 2; i++) {
shortBuffer.put(mainPattern);
shortBuffer.put(tintPattern);
}
for (int i = SIZE / 2; i < SIZE; i++) {
shortBuffer.put(tintPattern);
shortBuffer.put(mainPattern);
}
}
// Tints the given color appropriately and returns the tinted color.
private int tint(int color) {
float negTintOpacity = 1.0f - TINT_OPACITY;
float r = Color.red(color) * negTintOpacity + Color.red(TINT_COLOR) * TINT_OPACITY;
float g = Color.green(color) * negTintOpacity + Color.green(TINT_COLOR) * TINT_OPACITY;
float b = Color.blue(color) * negTintOpacity + Color.blue(TINT_COLOR) * TINT_OPACITY;
return Color.rgb(Math.round(r), Math.round(g), Math.round(b));
}
// Converts a 32-bit ARGB color to 16-bit R5G6B5, truncating values and discarding the alpha
// channel.
private short convertTo16Bit(int color) {
int r = Color.red(color) >> 3, g = Color.green(color) >> 2, b = Color.blue(color) >> 3;
int c = ((r << 11) | (g << 5) | b);
// Swap endianness.
return (short)((c >> 8) | ((c & 0xff) << 8));
}
@Override
protected void finalize() throws Throwable {
try {
if (mBuffer != null) {
GeckoAppShell.freeDirectBuffer(mBuffer);
}
} finally {
super.finalize();
}
}
@Override
public ByteBuffer getBuffer() {
return mBuffer;
}
@Override
public IntSize getSize() {
return new IntSize(SIZE, SIZE);
}
@Override
public int getFormat() {
return FORMAT;
}
}

View File

@ -54,6 +54,7 @@ import org.mozilla.gecko.GeckoEventListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@ -63,6 +64,8 @@ import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.nio.ByteBuffer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Transfers a software-rendered Gecko to an ImageLayer so that it can be rendered by our
@ -102,6 +105,8 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
// inside a transaction, so no synchronization is needed.
private boolean mUpdateViewportOnEndDraw;
private static Pattern sColorPattern;
public GeckoSoftwareLayerClient(Context context) {
mContext = context;
@ -227,6 +232,9 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
mTileLayer.setOrigin(PointUtils.round(displayportOrigin));
mTileLayer.setResolution(mGeckoViewport.getZoomFactor());
int backgroundColor = parseColorFromGecko(viewportObject.getString("backgroundColor"));
controller.setCheckerboardColor(backgroundColor);
if (onlyUpdatePageSize) {
// Don't adjust page size when zooming unless zoom levels are
// approximately equal.
@ -454,5 +462,23 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
mUpdateViewportOnEndDraw = true;
}
}
// Parses a color from an RGB triple of the form "rgb([0-9]+, [0-9]+, [0-9]+)". If the color
// cannot be parsed, returns white.
private static int parseColorFromGecko(String string) {
if (sColorPattern == null) {
sColorPattern = Pattern.compile("rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)");
}
Matcher matcher = sColorPattern.matcher(string);
if (!matcher.matches()) {
return Color.WHITE;
}
int r = Integer.parseInt(matcher.group(1));
int g = Integer.parseInt(matcher.group(2));
int b = Integer.parseInt(matcher.group(3));
return Color.rgb(r, g, b);
}
}

View File

@ -81,8 +81,11 @@ public class LayerController {
* updates our visible rect appropriately.
*/
private OnTouchListener mOnTouchListener; /* The touch listener. */
private LayerClient mLayerClient; /* The layer client. */
private OnTouchListener mOnTouchListener; /* The touch listener. */
private LayerClient mLayerClient; /* The layer client. */
/* The new color for the checkerboard. */
private int mCheckerboardColor;
private boolean mForceRedraw;
@ -144,7 +147,6 @@ public class LayerController {
}
public Bitmap getBackgroundPattern() { return getDrawable("background"); }
public Bitmap getCheckerboardPattern() { return getDrawable("checkerboard"); }
public Bitmap getShadowPattern() { return getDrawable("shadow"); }
public GestureDetector.OnGestureListener getGestureListener() { return mPanZoomController; }
@ -351,5 +353,16 @@ public class LayerController {
return mOnTouchListener.onTouch(mView, event);
return false;
}
/** Retrieves the color that the checkerboard should be. */
public int getCheckerboardColor() {
return mCheckerboardColor;
}
/** Sets a new color for the checkerboard. */
public void setCheckerboardColor(int newColor) {
mCheckerboardColor = newColor;
mView.requestRender();
}
}

View File

@ -80,6 +80,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
private final LayerView mView;
private final SingleTileLayer mBackgroundLayer;
private final CheckerboardImage mCheckerboardImage;
private final SingleTileLayer mCheckerboardLayer;
private final NinePatchTileLayer mShadowLayer;
private final TextLayer mFrameRateLayer;
@ -102,8 +103,8 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
CairoImage backgroundImage = new BufferedCairoImage(controller.getBackgroundPattern());
mBackgroundLayer = new SingleTileLayer(true, backgroundImage);
CairoImage checkerboardImage = new BufferedCairoImage(controller.getCheckerboardPattern());
mCheckerboardLayer = new SingleTileLayer(true, checkerboardImage);
mCheckerboardImage = new CheckerboardImage();
mCheckerboardLayer = new SingleTileLayer(true, mCheckerboardImage);
CairoImage shadowImage = new BufferedCairoImage(controller.getShadowPattern());
mShadowLayer = new NinePatchTileLayer(shadowImage);
@ -171,7 +172,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
if (rootLayer != null) updated &= rootLayer.update(gl, pageContext);
updated &= mBackgroundLayer.update(gl, screenContext);
updated &= mShadowLayer.update(gl, pageContext);
updated &= mCheckerboardLayer.update(gl, screenContext);
updateCheckerboardLayer(gl, screenContext);
updated &= mFrameRateLayer.update(gl, screenContext);
updated &= mVertScrollLayer.update(gl, pageContext);
updated &= mHorizScrollLayer.update(gl, pageContext);
@ -334,6 +335,23 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
}).start();
}
private void updateCheckerboardLayer(GL10 gl, RenderContext renderContext) {
int newCheckerboardColor = mView.getController().getCheckerboardColor();
if (newCheckerboardColor == mCheckerboardImage.getColor()) {
return;
}
mCheckerboardLayer.beginTransaction();
try {
mCheckerboardImage.setColor(newCheckerboardColor);
mCheckerboardLayer.invalidate();
} finally {
mCheckerboardLayer.endTransaction();
}
mCheckerboardLayer.update(gl, renderContext);
}
class FadeRunnable implements Runnable {
private boolean mStarted;
private long mRunAt;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

View File

@ -802,7 +802,18 @@ var BrowserApp = {
},
getDrawMetadata: function getDrawMetadata() {
return JSON.stringify(this.selectedTab.viewport);
let viewport = this.selectedTab.viewport;
// Sample the background color of the page and pass it along. (This is used to draw the
// checkerboard.)
let browser = this.selectedBrowser;
if (browser) {
let { contentDocument, contentWindow } = browser;
let computedStyle = contentWindow.getComputedStyle(contentDocument.body);
viewport.backgroundColor = computedStyle.backgroundColor;
}
return JSON.stringify(viewport);
},
observe: function(aSubject, aTopic, aData) {