mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 746016 - Cache low res version of the page in the java ui for use instead of checkerboarding r=kats
--HG-- extra : rebase_source : d6de0327a46393cd4cfc327dea5689364744a71d
This commit is contained in:
parent
4963a1fea8
commit
142a463d8e
@ -603,9 +603,13 @@ public class GeckoAppShell
|
|||||||
imm, text, start, end, newEnd);
|
imm, text, start, end, newEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void notifyScreenShot(ByteBuffer data, int tabId, int width, int height) {
|
// these 2 stubs are never called in XUL Fennec, but we need them so that
|
||||||
// this stub is never called in XUL Fennec, but we need it so that the JNI code
|
// the JNI code shared between XUL and Native Fennec doesn't die.
|
||||||
// shared between XUL and Native Fennec doesn't die.
|
public static void notifyScreenShot(final ByteBuffer data, final int tabId, final int x, final int y,
|
||||||
|
final int width, final int height, final int token) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void notifyPaintedRect(float top, float left, float bottom, float right) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CountDownLatch sGeckoPendingAcks = null;
|
private static CountDownLatch sGeckoPendingAcks = null;
|
||||||
|
@ -728,7 +728,7 @@ pref("direct-texture.force.enabled", false);
|
|||||||
pref("direct-texture.force.disabled", false);
|
pref("direct-texture.force.disabled", false);
|
||||||
|
|
||||||
// show checkerboard pattern on android; we use background colour instead
|
// show checkerboard pattern on android; we use background colour instead
|
||||||
pref("gfx.show_checkerboard_pattern", false);
|
pref("gfx.show_checkerboard_pattern", true);
|
||||||
|
|
||||||
pref("remote-debugger.enabled", false);
|
pref("remote-debugger.enabled", false);
|
||||||
pref("remote-debugger.port", 6000);
|
pref("remote-debugger.port", 6000);
|
||||||
|
@ -556,7 +556,7 @@ abstract public class GeckoApp
|
|||||||
int sh = tab.getMinScreenshotHeight();
|
int sh = tab.getMinScreenshotHeight();
|
||||||
int dw = tab.getThumbnailWidth();
|
int dw = tab.getThumbnailWidth();
|
||||||
int dh = tab.getThumbnailHeight();
|
int dh = tab.getThumbnailHeight();
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), sw, sh, dw, dh));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), 0, 0, sw, sh, 0, 0, dw, dh, GeckoAppShell.SCREENSHOT_THUMBNAIL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1193,7 +1193,8 @@ abstract public class GeckoApp
|
|||||||
tab.updateURL(uri);
|
tab.updateURL(uri);
|
||||||
tab.setState(Tab.STATE_LOADING);
|
tab.setState(Tab.STATE_LOADING);
|
||||||
tab.updateSecurityMode("unknown");
|
tab.updateSecurityMode("unknown");
|
||||||
|
if (Tabs.getInstance().isSelectedTab(tab))
|
||||||
|
getLayerController().getView().getRenderer().resetCheckerboard();
|
||||||
mMainHandler.post(new Runnable() {
|
mMainHandler.post(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (Tabs.getInstance().isSelectedTab(tab)) {
|
if (Tabs.getInstance().isSelectedTab(tab)) {
|
||||||
@ -1223,6 +1224,11 @@ abstract public class GeckoApp
|
|||||||
GeckoAppShell.getHandler().postDelayed(new Runnable() {
|
GeckoAppShell.getHandler().postDelayed(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
getAndProcessThumbnailForTab(tab);
|
getAndProcessThumbnailForTab(tab);
|
||||||
|
if (Tabs.getInstance().isSelectedTab(tab)) {
|
||||||
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createStartPaintListentingEvent(tab.getId()));
|
||||||
|
GeckoAppShell.screenshotWholePage(tab);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,13 @@
|
|||||||
package org.mozilla.gecko;
|
package org.mozilla.gecko;
|
||||||
|
|
||||||
import org.mozilla.gecko.gfx.BitmapUtils;
|
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||||
|
import org.mozilla.gecko.gfx.IntSize;
|
||||||
import org.mozilla.gecko.gfx.GeckoLayerClient;
|
import org.mozilla.gecko.gfx.GeckoLayerClient;
|
||||||
|
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
|
||||||
import org.mozilla.gecko.gfx.LayerController;
|
import org.mozilla.gecko.gfx.LayerController;
|
||||||
import org.mozilla.gecko.gfx.LayerView;
|
import org.mozilla.gecko.gfx.LayerView;
|
||||||
|
import org.mozilla.gecko.gfx.ScreenshotLayer;
|
||||||
|
import org.mozilla.gecko.FloatUtils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
@ -110,6 +114,10 @@ public class GeckoAppShell
|
|||||||
public static final String SHORTCUT_TYPE_WEBAPP = "webapp";
|
public static final String SHORTCUT_TYPE_WEBAPP = "webapp";
|
||||||
public static final String SHORTCUT_TYPE_BOOKMARK = "bookmark";
|
public static final String SHORTCUT_TYPE_BOOKMARK = "bookmark";
|
||||||
|
|
||||||
|
static public final int SCREENSHOT_THUMBNAIL = 0;
|
||||||
|
static public final int SCREENSHOT_WHOLE_PAGE = 1;
|
||||||
|
static public final int SCREENSHOT_UPDATE = 2;
|
||||||
|
|
||||||
static private File sCacheFile = null;
|
static private File sCacheFile = null;
|
||||||
static private int sFreeSpace = -1;
|
static private int sFreeSpace = -1;
|
||||||
static File sHomeDir = null;
|
static File sHomeDir = null;
|
||||||
@ -118,6 +126,9 @@ public class GeckoAppShell
|
|||||||
private static Boolean sNSSLibsLoaded = false;
|
private static Boolean sNSSLibsLoaded = false;
|
||||||
private static Boolean sLibsSetup = false;
|
private static Boolean sLibsSetup = false;
|
||||||
private static File sGREDir = null;
|
private static File sGREDir = null;
|
||||||
|
private static float sCheckerboardPageWidth, sCheckerboardPageHeight;
|
||||||
|
private static float sLastCheckerboardWidthRatio, sLastCheckerboardHeightRatio;
|
||||||
|
private static RepaintRunnable sRepaintRunnable = new RepaintRunnable();
|
||||||
|
|
||||||
private static Map<String, CopyOnWriteArrayList<GeckoEventListener>> mEventListeners
|
private static Map<String, CopyOnWriteArrayList<GeckoEventListener>> mEventListeners
|
||||||
= new HashMap<String, CopyOnWriteArrayList<GeckoEventListener>>();
|
= new HashMap<String, CopyOnWriteArrayList<GeckoEventListener>>();
|
||||||
@ -525,8 +536,9 @@ public class GeckoAppShell
|
|||||||
mInputConnection.notifyIMEChange(text, start, end, newEnd);
|
mInputConnection.notifyIMEChange(text, start, end, newEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void notifyScreenShot(final ByteBuffer data, final int tabId,
|
// Called by AndroidBridge using JNI
|
||||||
final int width, final int height) {
|
public static void notifyScreenShot(final ByteBuffer data, final int tabId, final int x, final int y,
|
||||||
|
final int width, final int height, final int token) {
|
||||||
getHandler().post(new Runnable() {
|
getHandler().post(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@ -534,9 +546,28 @@ public class GeckoAppShell
|
|||||||
if (tab == null)
|
if (tab == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!Tabs.getInstance().isSelectedTab(tab) && SCREENSHOT_THUMBNAIL != token)
|
||||||
|
return;
|
||||||
|
|
||||||
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
||||||
b.copyPixelsFromBuffer(data);
|
b.copyPixelsFromBuffer(data);
|
||||||
GeckoApp.mAppContext.processThumbnail(tab, b, null);
|
switch (token) {
|
||||||
|
case SCREENSHOT_WHOLE_PAGE:
|
||||||
|
GeckoApp.mAppContext.getLayerController()
|
||||||
|
.getView().getRenderer().setCheckerboardBitmap(b);
|
||||||
|
break;
|
||||||
|
case SCREENSHOT_UPDATE:
|
||||||
|
GeckoApp.mAppContext.getLayerController().getView().getRenderer().
|
||||||
|
updateCheckerboardBitmap(
|
||||||
|
b, sLastCheckerboardWidthRatio * x,
|
||||||
|
sLastCheckerboardHeightRatio * y,
|
||||||
|
sLastCheckerboardWidthRatio * width,
|
||||||
|
sLastCheckerboardHeightRatio * height);
|
||||||
|
break;
|
||||||
|
case SCREENSHOT_THUMBNAIL:
|
||||||
|
GeckoApp.mAppContext.processThumbnail(tab, b, null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
freeDirectBuffer(data);
|
freeDirectBuffer(data);
|
||||||
}
|
}
|
||||||
@ -2114,4 +2145,75 @@ public class GeckoAppShell
|
|||||||
if (!GeckoApp.mAppContext.showFilePicker(aMimeType, new AsyncResultHandler(id)))
|
if (!GeckoApp.mAppContext.showFilePicker(aMimeType, new AsyncResultHandler(id)))
|
||||||
GeckoAppShell.notifyFilePickerResult("", id);
|
GeckoAppShell.notifyFilePickerResult("", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class RepaintRunnable implements Runnable {
|
||||||
|
private boolean mIsRepaintRunnablePosted = false;
|
||||||
|
private float mDirtyTop = Float.POSITIVE_INFINITY, mDirtyLeft = Float.POSITIVE_INFINITY;
|
||||||
|
private float mDirtyBottom = Float.NEGATIVE_INFINITY, mDirtyRight = Float.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
float top, left, bottom, right;
|
||||||
|
// synchronize so we don't try to accumulate more rects while painting the ones we have
|
||||||
|
synchronized(this) {
|
||||||
|
top = mDirtyTop;
|
||||||
|
left = mDirtyLeft;
|
||||||
|
right = mDirtyRight;
|
||||||
|
bottom = mDirtyBottom;
|
||||||
|
// reset these to infinity to start accumulating again
|
||||||
|
mDirtyTop = Float.POSITIVE_INFINITY;
|
||||||
|
mDirtyLeft = Float.POSITIVE_INFINITY;
|
||||||
|
mDirtyBottom = Float.NEGATIVE_INFINITY;
|
||||||
|
mDirtyRight = Float.NEGATIVE_INFINITY;
|
||||||
|
mIsRepaintRunnablePosted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tab tab = Tabs.getInstance().getSelectedTab();
|
||||||
|
ImmutableViewportMetrics viewport = GeckoApp.mAppContext.getLayerController().getViewportMetrics();
|
||||||
|
if (FloatUtils.fuzzyEquals(sCheckerboardPageWidth, viewport.pageSizeWidth) &&
|
||||||
|
FloatUtils.fuzzyEquals(sCheckerboardPageHeight, viewport.pageSizeHeight)) {
|
||||||
|
float width = right - left;
|
||||||
|
float height = bottom - top;
|
||||||
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), (int)top, (int)left, (int)width, (int)height, 0, 0, (int)(sLastCheckerboardWidthRatio * width), (int)(sLastCheckerboardHeightRatio * height), GeckoAppShell.SCREENSHOT_UPDATE));
|
||||||
|
} else {
|
||||||
|
GeckoAppShell.screenshotWholePage(tab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRectToRepaint(float top, float left, float bottom, float right) {
|
||||||
|
synchronized(this) {
|
||||||
|
mDirtyTop = Math.min(top, mDirtyTop);
|
||||||
|
mDirtyLeft = Math.min(left, mDirtyLeft);
|
||||||
|
mDirtyBottom = Math.max(bottom, mDirtyBottom);
|
||||||
|
mDirtyRight = Math.max(right, mDirtyRight);
|
||||||
|
if (!mIsRepaintRunnablePosted) {
|
||||||
|
getHandler().postDelayed(this, 5000);
|
||||||
|
mIsRepaintRunnablePosted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by AndroidBridge using JNI
|
||||||
|
public static void notifyPaintedRect(float top, float left, float bottom, float right) {
|
||||||
|
sRepaintRunnable.addRectToRepaint(top, left, bottom, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void screenshotWholePage(Tab tab) {
|
||||||
|
ImmutableViewportMetrics viewport = GeckoApp.mAppContext.getLayerController().getViewportMetrics();
|
||||||
|
// source width and height to screenshot
|
||||||
|
float sw = viewport.pageSizeWidth;
|
||||||
|
float sh = viewport.pageSizeHeight;
|
||||||
|
// 2Mb of 16bit image data
|
||||||
|
// may be bumped by up to 4x for power of 2 alignment
|
||||||
|
float ratio = (float)Math.sqrt((sw * sh) / (ScreenshotLayer.getMaxNumPixels() / 4));
|
||||||
|
// destination width and hight
|
||||||
|
int dw = IntSize.nextPowerOfTwo(sw / ratio);
|
||||||
|
int dh = IntSize.nextPowerOfTwo(sh / ratio);
|
||||||
|
sLastCheckerboardWidthRatio = dw / sw;
|
||||||
|
sLastCheckerboardHeightRatio = dh / sh;
|
||||||
|
sCheckerboardPageWidth = viewport.pageSizeWidth;
|
||||||
|
sCheckerboardPageHeight = viewport.pageSizeHeight;
|
||||||
|
|
||||||
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), 0, 0, (int)sw, (int)sh, 0, 0, dw, dh, GeckoAppShell.SCREENSHOT_WHOLE_PAGE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,8 @@ public class GeckoEvent {
|
|||||||
private static final int UNUSED2_EVENT = 26;
|
private static final int UNUSED2_EVENT = 26;
|
||||||
private static final int SCREENORIENTATION_CHANGED = 27;
|
private static final int SCREENORIENTATION_CHANGED = 27;
|
||||||
private static final int COMPOSITOR_PAUSE = 28;
|
private static final int COMPOSITOR_PAUSE = 28;
|
||||||
private static final int COMPOSITOR_RESUME = 29;
|
private static final int COMPOSITOR_RESUME = 29;
|
||||||
|
private static final int PAINT_LISTEN_START_EVENT = 30;
|
||||||
|
|
||||||
public static final int IME_COMPOSITION_END = 0;
|
public static final int IME_COMPOSITION_END = 0;
|
||||||
public static final int IME_COMPOSITION_BEGIN = 1;
|
public static final int IME_COMPOSITION_BEGIN = 1;
|
||||||
@ -478,12 +479,15 @@ public class GeckoEvent {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GeckoEvent createScreenshotEvent(int tabId, int sw, int sh, int dw, int dh) {
|
public static GeckoEvent createScreenshotEvent(int tabId, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int token) {
|
||||||
GeckoEvent event = new GeckoEvent(SCREENSHOT);
|
GeckoEvent event = new GeckoEvent(SCREENSHOT);
|
||||||
event.mPoints = new Point[2];
|
event.mPoints = new Point[4];
|
||||||
event.mPoints[0] = new Point(sw, sh);
|
event.mPoints[0] = new Point(sx, sy);
|
||||||
event.mPoints[1] = new Point(dw, dh);
|
event.mPoints[1] = new Point(sw, sh);
|
||||||
|
event.mPoints[2] = new Point(dx, dy);
|
||||||
|
event.mPoints[3] = new Point(dw, dh);
|
||||||
event.mMetaState = tabId;
|
event.mMetaState = tabId;
|
||||||
|
event.mFlags = token;
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,4 +496,10 @@ public class GeckoEvent {
|
|||||||
event.mScreenOrientation = aScreenOrientation;
|
event.mScreenOrientation = aScreenOrientation;
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GeckoEvent createStartPaintListentingEvent(int tabId) {
|
||||||
|
GeckoEvent event = new GeckoEvent(PAINT_LISTEN_START_EVENT);
|
||||||
|
event.mMetaState = tabId;
|
||||||
|
return event;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,7 @@ FENNEC_JAVA_FILES = \
|
|||||||
gfx/PanningPerfAPI.java \
|
gfx/PanningPerfAPI.java \
|
||||||
gfx/PointUtils.java \
|
gfx/PointUtils.java \
|
||||||
gfx/RectUtils.java \
|
gfx/RectUtils.java \
|
||||||
|
gfx/ScreenshotLayer.java \
|
||||||
gfx/ScrollbarLayer.java \
|
gfx/ScrollbarLayer.java \
|
||||||
gfx/SingleTileLayer.java \
|
gfx/SingleTileLayer.java \
|
||||||
gfx/SurfaceTextureLayer.java \
|
gfx/SurfaceTextureLayer.java \
|
||||||
|
@ -43,6 +43,7 @@ import org.mozilla.gecko.GeckoApp;
|
|||||||
import org.mozilla.gecko.GeckoAppShell;
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
import org.mozilla.gecko.GeckoEvent;
|
import org.mozilla.gecko.GeckoEvent;
|
||||||
import org.mozilla.gecko.GeckoEventResponder;
|
import org.mozilla.gecko.GeckoEventResponder;
|
||||||
|
import org.mozilla.gecko.Tabs;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@ -341,6 +342,8 @@ public class GeckoLayerClient implements GeckoEventResponder,
|
|||||||
mLayerController.abortPanZoomAnimation();
|
mLayerController.abortPanZoomAnimation();
|
||||||
mLayerController.getView().setPaintState(LayerView.PAINT_BEFORE_FIRST);
|
mLayerController.getView().setPaintState(LayerView.PAINT_BEFORE_FIRST);
|
||||||
}
|
}
|
||||||
|
mLayerController.getView().getRenderer().resetCheckerboard();
|
||||||
|
GeckoAppShell.screenshotWholePage(Tabs.getInstance().getSelectedTab());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This function is invoked by Gecko via JNI; be careful when modifying signature.
|
/** This function is invoked by Gecko via JNI; be careful when modifying signature.
|
||||||
|
@ -96,6 +96,10 @@ public class IntSize {
|
|||||||
return value + 1;
|
return value + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int nextPowerOfTwo(float value) {
|
||||||
|
return nextPowerOfTwo((int) value);
|
||||||
|
}
|
||||||
|
|
||||||
public IntSize nextPowerOfTwo() {
|
public IntSize nextPowerOfTwo() {
|
||||||
return new IntSize(nextPowerOfTwo(width), nextPowerOfTwo(height));
|
return new IntSize(nextPowerOfTwo(width), nextPowerOfTwo(height));
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ import org.mozilla.gecko.gfx.TileLayer;
|
|||||||
import org.mozilla.gecko.GeckoAppShell;
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
@ -90,8 +91,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
|||||||
|
|
||||||
private final LayerView mView;
|
private final LayerView mView;
|
||||||
private final SingleTileLayer mBackgroundLayer;
|
private final SingleTileLayer mBackgroundLayer;
|
||||||
private final CheckerboardImage mCheckerboardImage;
|
private final ScreenshotLayer mCheckerboardLayer;
|
||||||
private final SingleTileLayer mCheckerboardLayer;
|
|
||||||
private final NinePatchTileLayer mShadowLayer;
|
private final NinePatchTileLayer mShadowLayer;
|
||||||
private TextLayer mFrameRateLayer;
|
private TextLayer mFrameRateLayer;
|
||||||
private final ScrollbarLayer mHorizScrollLayer;
|
private final ScrollbarLayer mHorizScrollLayer;
|
||||||
@ -158,6 +158,36 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
|||||||
" gl_FragColor = texture2D(sTexture, vec2(vTexCoord.x, 1.0 - vTexCoord.y));\n" +
|
" gl_FragColor = texture2D(sTexture, vec2(vTexCoord.x, 1.0 - vTexCoord.y));\n" +
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
|
public void setCheckerboardBitmap(Bitmap bitmap) {
|
||||||
|
mCheckerboardLayer.setBitmap(bitmap);
|
||||||
|
mCheckerboardLayer.beginTransaction();
|
||||||
|
try {
|
||||||
|
mCheckerboardLayer.invalidate();
|
||||||
|
} finally {
|
||||||
|
mCheckerboardLayer.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCheckerboardBitmap(Bitmap bitmap, float x, float y, float width, float height) {
|
||||||
|
mCheckerboardLayer.updateBitmap(bitmap, x, y, width, height);
|
||||||
|
mCheckerboardLayer.beginTransaction();
|
||||||
|
try {
|
||||||
|
mCheckerboardLayer.invalidate();
|
||||||
|
} finally {
|
||||||
|
mCheckerboardLayer.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetCheckerboard() {
|
||||||
|
mCheckerboardLayer.reset();
|
||||||
|
mCheckerboardLayer.beginTransaction();
|
||||||
|
try {
|
||||||
|
mCheckerboardLayer.invalidate();
|
||||||
|
} finally {
|
||||||
|
mCheckerboardLayer.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public LayerRenderer(LayerView view) {
|
public LayerRenderer(LayerView view) {
|
||||||
mView = view;
|
mView = view;
|
||||||
|
|
||||||
@ -166,8 +196,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
|||||||
CairoImage backgroundImage = new BufferedCairoImage(controller.getBackgroundPattern());
|
CairoImage backgroundImage = new BufferedCairoImage(controller.getBackgroundPattern());
|
||||||
mBackgroundLayer = new SingleTileLayer(true, backgroundImage);
|
mBackgroundLayer = new SingleTileLayer(true, backgroundImage);
|
||||||
|
|
||||||
mCheckerboardImage = new CheckerboardImage();
|
mCheckerboardLayer = ScreenshotLayer.create();
|
||||||
mCheckerboardLayer = new SingleTileLayer(true, mCheckerboardImage);
|
|
||||||
|
|
||||||
CairoImage shadowImage = new BufferedCairoImage(controller.getShadowPattern());
|
CairoImage shadowImage = new BufferedCairoImage(controller.getShadowPattern());
|
||||||
mShadowLayer = new NinePatchTileLayer(shadowImage);
|
mShadowLayer = new NinePatchTileLayer(shadowImage);
|
||||||
@ -391,18 +420,15 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
|||||||
private void updateCheckerboardImage() {
|
private void updateCheckerboardImage() {
|
||||||
int checkerboardColor = mView.getController().getCheckerboardColor();
|
int checkerboardColor = mView.getController().getCheckerboardColor();
|
||||||
boolean showChecks = mView.getController().checkerboardShouldShowChecks();
|
boolean showChecks = mView.getController().checkerboardShouldShowChecks();
|
||||||
if (checkerboardColor == mCheckerboardImage.getColor() &&
|
|
||||||
showChecks == mCheckerboardImage.getShowChecks()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mCheckerboardLayer.beginTransaction(); // called on compositor thread
|
mCheckerboardLayer.beginTransaction(); // called on compositor thread
|
||||||
try {
|
try {
|
||||||
mCheckerboardImage.update(showChecks, checkerboardColor);
|
if (mCheckerboardLayer.updateBackground(showChecks, checkerboardColor))
|
||||||
mCheckerboardLayer.invalidate();
|
mCheckerboardLayer.invalidate();
|
||||||
} finally {
|
} finally {
|
||||||
mCheckerboardLayer.endTransaction();
|
mCheckerboardLayer.endTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -533,7 +559,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
|||||||
mUpdated &= mBackgroundLayer.update(mScreenContext); // called on compositor thread
|
mUpdated &= mBackgroundLayer.update(mScreenContext); // called on compositor thread
|
||||||
mUpdated &= mShadowLayer.update(mPageContext); // called on compositor thread
|
mUpdated &= mShadowLayer.update(mPageContext); // called on compositor thread
|
||||||
updateCheckerboardImage();
|
updateCheckerboardImage();
|
||||||
mUpdated &= mCheckerboardLayer.update(mScreenContext); // called on compositor thread
|
mUpdated &= mCheckerboardLayer.update(mPageContext); // called on compositor thread
|
||||||
if (mFrameRateLayer != null) mUpdated &= mFrameRateLayer.update(mScreenContext); // called on compositor thread
|
if (mFrameRateLayer != null) mUpdated &= mFrameRateLayer.update(mScreenContext); // called on compositor thread
|
||||||
mUpdated &= mVertScrollLayer.update(mPageContext); // called on compositor thread
|
mUpdated &= mVertScrollLayer.update(mPageContext); // called on compositor thread
|
||||||
mUpdated &= mHorizScrollLayer.update(mPageContext); // called on compositor thread
|
mUpdated &= mHorizScrollLayer.update(mPageContext); // called on compositor thread
|
||||||
@ -569,7 +595,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
|||||||
/* Draw the checkerboard. */
|
/* Draw the checkerboard. */
|
||||||
setScissorRect();
|
setScissorRect();
|
||||||
mCheckerboardLayer.setMask(rootMask);
|
mCheckerboardLayer.setMask(rootMask);
|
||||||
mCheckerboardLayer.draw(mScreenContext);
|
mCheckerboardLayer.draw(mPageContext);
|
||||||
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
|
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ public class LayerView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public GLSurfaceView.Renderer getRenderer() {
|
public LayerRenderer getRenderer() {
|
||||||
return mRenderer;
|
return mRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ public class NinePatchTileLayer extends TileLayer {
|
|||||||
private static final int TEXTURE_SIZE = 64;
|
private static final int TEXTURE_SIZE = 64;
|
||||||
|
|
||||||
public NinePatchTileLayer(CairoImage image) {
|
public NinePatchTileLayer(CairoImage image) {
|
||||||
super(false, image);
|
super(image, TileLayer.PaintMode.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
254
mobile/android/base/gfx/ScreenshotLayer.java
Normal file
254
mobile/android/base/gfx/ScreenshotLayer.java
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.gecko.gfx;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
|
import org.mozilla.gecko.gfx.BufferedCairoImage;
|
||||||
|
import org.mozilla.gecko.gfx.CairoImage;
|
||||||
|
import org.mozilla.gecko.gfx.IntSize;
|
||||||
|
import org.mozilla.gecko.gfx.SingleTileLayer;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.graphics.Region;
|
||||||
|
import android.graphics.RegionIterator;
|
||||||
|
import android.opengl.GLES20;
|
||||||
|
import android.util.Log;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
public class ScreenshotLayer extends SingleTileLayer {
|
||||||
|
private static final int SCREENSHOT_SIZE_LIMIT = 1048576;
|
||||||
|
private ScreenshotImage mImage;
|
||||||
|
// Size of the image buffer
|
||||||
|
private IntSize mBufferSize;
|
||||||
|
// The size of the bitmap painted in the buffer
|
||||||
|
// (may be smaller than mBufferSize due to power of 2 padding)
|
||||||
|
private IntSize mImageSize;
|
||||||
|
// Special case to show the page background color prior to painting a screenshot
|
||||||
|
private boolean mIsSingleColor = true;
|
||||||
|
// Force single color, needed for testing
|
||||||
|
private boolean mForceSingleColor = false;
|
||||||
|
// Cache the passed in background color to determine if we need to update
|
||||||
|
// initialized to 0 so it lets the code run to set it to white on init
|
||||||
|
private int mCurrentBackgroundColor = 0;
|
||||||
|
|
||||||
|
public static int getMaxNumPixels() {
|
||||||
|
return SCREENSHOT_SIZE_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
mIsSingleColor = true;
|
||||||
|
updateBackground(mForceSingleColor, Color.WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBitmap(Bitmap bitmap) {
|
||||||
|
if (mForceSingleColor)
|
||||||
|
return;
|
||||||
|
mImageSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
|
||||||
|
int width = IntSize.nextPowerOfTwo(bitmap.getWidth());
|
||||||
|
int height = IntSize.nextPowerOfTwo(bitmap.getHeight());
|
||||||
|
mBufferSize = new IntSize(width, height);
|
||||||
|
mImage.setBitmap(bitmap, width, height, CairoImage.FORMAT_RGB16_565);
|
||||||
|
mIsSingleColor = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateBitmap(Bitmap bitmap, float x, float y, float width, float height) {
|
||||||
|
mImage.updateBitmap(bitmap, x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScreenshotLayer create() {
|
||||||
|
// 3 x 3 min for the single color case. Less than 3x3 will blend
|
||||||
|
// the colors from outside this single color block when scaled
|
||||||
|
return ScreenshotLayer.create(new IntSize(3, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScreenshotLayer create(IntSize size) {
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.RGB_565);
|
||||||
|
ScreenshotLayer sl = create(bitmap);
|
||||||
|
sl.reset();
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScreenshotLayer create(Bitmap bitmap) {
|
||||||
|
IntSize size = new IntSize(bitmap.getWidth(), bitmap.getHeight());
|
||||||
|
// allocate a buffer that can hold our max screenshot size
|
||||||
|
ByteBuffer buffer = GeckoAppShell.allocateDirectBuffer(SCREENSHOT_SIZE_LIMIT * 2);
|
||||||
|
// construct the screenshot layer
|
||||||
|
ScreenshotLayer sl = new ScreenshotLayer(new ScreenshotImage(buffer, size.width, size.height, CairoImage.FORMAT_RGB16_565), size);
|
||||||
|
// paint the passed in bitmap into the buffer
|
||||||
|
sl.setBitmap(bitmap);
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScreenshotLayer(ScreenshotImage image, IntSize size) {
|
||||||
|
super(image, TileLayer.PaintMode.STRETCH);
|
||||||
|
mBufferSize = size;
|
||||||
|
mImage = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(RenderContext context) {
|
||||||
|
// mTextureIDs may be null here during startup if Layer.java's draw method
|
||||||
|
// failed to acquire the transaction lock and call performUpdates.
|
||||||
|
if (!initialized())
|
||||||
|
return;
|
||||||
|
|
||||||
|
float txl, txr, txb, txt;
|
||||||
|
if (mIsSingleColor) {
|
||||||
|
txt = 1.0f;
|
||||||
|
txr = 0.5f / mBufferSize.width;;
|
||||||
|
txb = 1.0f - 0.5f / mBufferSize.height;
|
||||||
|
txl = 0.0f;
|
||||||
|
} else {
|
||||||
|
Rect position = getPosition();
|
||||||
|
|
||||||
|
float bw = mBufferSize.width;
|
||||||
|
float bh = mBufferSize.height;
|
||||||
|
float iw = mImageSize.width;
|
||||||
|
float ih = mImageSize.height;
|
||||||
|
|
||||||
|
float pw = context.pageSize.width;
|
||||||
|
float ph = context.pageSize.height;
|
||||||
|
|
||||||
|
float vl = context.viewport.left;
|
||||||
|
float vr = context.viewport.right;
|
||||||
|
float vt = context.viewport.top;
|
||||||
|
float vb = context.viewport.bottom;
|
||||||
|
|
||||||
|
float vw = vr - vl;
|
||||||
|
float vh = vb - vt;
|
||||||
|
|
||||||
|
txl = (iw/bw) * (vl / pw);
|
||||||
|
txr = (iw/bw) * (vr / pw);
|
||||||
|
txt = 1.0f - ((ih/bh) * (vt / ph));
|
||||||
|
txb = 1.0f - ((ih/bh) * (vb / ph));
|
||||||
|
}
|
||||||
|
float[] coords = {
|
||||||
|
0.0f, 0.0f, 0.0f, txl, txb,
|
||||||
|
0.0f, 1.0f, 0.0f, txl, txt,
|
||||||
|
1.0f, 0.0f, 0.0f, txr, txb,
|
||||||
|
1.0f, 1.0f, 0.0f, txr, txt,
|
||||||
|
};
|
||||||
|
|
||||||
|
FloatBuffer coordBuffer = context.coordBuffer;
|
||||||
|
int positionHandle = context.positionHandle;
|
||||||
|
int textureHandle = context.textureHandle;
|
||||||
|
|
||||||
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureID());
|
||||||
|
|
||||||
|
// Make sure we are at position zero in the buffer
|
||||||
|
coordBuffer.position(0);
|
||||||
|
coordBuffer.put(coords);
|
||||||
|
|
||||||
|
// Vertex coordinates are x,y,z starting at position 0 into the buffer.
|
||||||
|
coordBuffer.position(0);
|
||||||
|
GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20, coordBuffer);
|
||||||
|
|
||||||
|
// Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
|
||||||
|
coordBuffer.position(3);
|
||||||
|
GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20, coordBuffer);
|
||||||
|
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean updateBackground(boolean showChecks, int color) {
|
||||||
|
if (!showChecks) {
|
||||||
|
mIsSingleColor = true;
|
||||||
|
mForceSingleColor = true;
|
||||||
|
} else {
|
||||||
|
mForceSingleColor = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mIsSingleColor || color == mCurrentBackgroundColor)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mCurrentBackgroundColor = color;
|
||||||
|
|
||||||
|
/* mask each component of the 8888 color and bit shift to least
|
||||||
|
* sigificant. Then for red and blue multiply by (2^5 -1) and (2^6 - 1)
|
||||||
|
* for green. Finally, divide by (2^8 - 1) for all color values. This
|
||||||
|
* scales the 8 bit color values to 5 or 6 bits
|
||||||
|
*/
|
||||||
|
int red = ((color & 0x00FF0000 >> 16)* 31 / 255);
|
||||||
|
int green = ((color & 0x0000FF00 >> 8) * 63 / 255);
|
||||||
|
int blue = (color & 0x000000FF) * 31 / 255;
|
||||||
|
/* For the first byte left shift red by 3 positions such that it is the
|
||||||
|
* top 5 bits, right shift green by 3 so its 3 most significant are the
|
||||||
|
* 3 least significant. For the second byte, left shift green by 3 so
|
||||||
|
* its 3 least significant bits are the 3 most significant bits of the
|
||||||
|
* byte. Finally, set the 5 least significant bits to blue's value.
|
||||||
|
*/
|
||||||
|
byte byte1 = (byte)((red << 3 | green >> 3) & 0x0000FFFF);
|
||||||
|
byte byte2 = (byte)((green << 5 | blue) & 0x0000FFFF);
|
||||||
|
mImage.mBuffer.put(1, byte1);
|
||||||
|
mImage.mBuffer.put(0, byte2);
|
||||||
|
mImage.mBuffer.put(3, byte1);
|
||||||
|
mImage.mBuffer.put(2, byte2);
|
||||||
|
mImage.mBuffer.put(5, byte1);
|
||||||
|
mImage.mBuffer.put(4, byte2);
|
||||||
|
mImage.mBuffer.put(mImageSize.width + 1, byte1);
|
||||||
|
mImage.mBuffer.put(mImageSize.width + 0, byte2);
|
||||||
|
mImage.mBuffer.put(mImageSize.width + 3, byte1);
|
||||||
|
mImage.mBuffer.put(mImageSize.width + 2, byte2);
|
||||||
|
mImage.mBuffer.put(mImageSize.width + 5, byte1);
|
||||||
|
mImage.mBuffer.put(mImageSize.width + 4, byte2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A Cairo image that simply saves a buffer of pixel data. */
|
||||||
|
static class ScreenshotImage extends CairoImage {
|
||||||
|
ByteBuffer mBuffer;
|
||||||
|
private IntSize mSize;
|
||||||
|
private int mFormat;
|
||||||
|
|
||||||
|
/** Creates a buffered Cairo image from a byte buffer. */
|
||||||
|
public ScreenshotImage(ByteBuffer inBuffer, int inWidth, int inHeight, int inFormat) {
|
||||||
|
mBuffer = inBuffer; mSize = new IntSize(inWidth, inHeight); mFormat = inFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
try {
|
||||||
|
if (mBuffer != null)
|
||||||
|
GeckoAppShell.freeDirectBuffer(mBuffer);
|
||||||
|
} finally {
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBitmap(Bitmap bitmap, int width, int height, int format) {
|
||||||
|
Bitmap tmp;
|
||||||
|
mSize = new IntSize(width, height);
|
||||||
|
mFormat = format;
|
||||||
|
if (width == bitmap.getWidth() && height == bitmap.getHeight()) {
|
||||||
|
tmp = bitmap;
|
||||||
|
} else {
|
||||||
|
tmp = Bitmap.createBitmap(width, height, CairoUtils.cairoFormatTobitmapConfig(mFormat));
|
||||||
|
new Canvas(tmp).drawBitmap(bitmap, 0.0f, 0.0f, new Paint());
|
||||||
|
}
|
||||||
|
tmp.copyPixelsToBuffer(mBuffer.asIntBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateBitmap(Bitmap bitmap, float x, float y, float width, float height) {
|
||||||
|
Bitmap tmp = Bitmap.createBitmap(mSize.width, mSize.height, CairoUtils.cairoFormatTobitmapConfig(mFormat));
|
||||||
|
tmp.copyPixelsFromBuffer(mBuffer.asIntBuffer());
|
||||||
|
Canvas c = new Canvas(tmp);
|
||||||
|
c.drawBitmap(bitmap, x, y, new Paint());
|
||||||
|
tmp.copyPixelsToBuffer(mBuffer.asIntBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer getBuffer() { return mBuffer; }
|
||||||
|
@Override
|
||||||
|
public IntSize getSize() { return mSize; }
|
||||||
|
@Override
|
||||||
|
public int getFormat() { return mFormat; }
|
||||||
|
}
|
||||||
|
}
|
@ -141,7 +141,7 @@ public class ScrollbarLayer extends TileLayer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private ScrollbarLayer(LayerRenderer renderer, CairoImage image, boolean vertical, ByteBuffer buffer) {
|
private ScrollbarLayer(LayerRenderer renderer, CairoImage image, boolean vertical, ByteBuffer buffer) {
|
||||||
super(false, image);
|
super(image, TileLayer.PaintMode.NORMAL);
|
||||||
mVertical = vertical;
|
mVertical = vertical;
|
||||||
mBuffer = buffer;
|
mBuffer = buffer;
|
||||||
mRenderer = renderer;
|
mRenderer = renderer;
|
||||||
|
@ -65,7 +65,11 @@ public class SingleTileLayer extends TileLayer {
|
|||||||
public SingleTileLayer(CairoImage image) { this(false, image); }
|
public SingleTileLayer(CairoImage image) { this(false, image); }
|
||||||
|
|
||||||
public SingleTileLayer(boolean repeat, CairoImage image) {
|
public SingleTileLayer(boolean repeat, CairoImage image) {
|
||||||
super(repeat, image);
|
super(image, repeat ? TileLayer.PaintMode.REPEAT : TileLayer.PaintMode.NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SingleTileLayer(CairoImage image, TileLayer.PaintMode paintMode) {
|
||||||
|
super(image, paintMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,7 +90,7 @@ public class SingleTileLayer extends TileLayer {
|
|||||||
Rect position = getPosition();
|
Rect position = getPosition();
|
||||||
RectF viewport = context.viewport;
|
RectF viewport = context.viewport;
|
||||||
|
|
||||||
if (repeats()) {
|
if (repeats() || stretches()) {
|
||||||
bounds = new RectF(0.0f, 0.0f, viewport.width(), viewport.height());
|
bounds = new RectF(0.0f, 0.0f, viewport.width(), viewport.height());
|
||||||
int width = Math.round(viewport.width());
|
int width = Math.round(viewport.width());
|
||||||
int height = Math.round(viewport.height());
|
int height = Math.round(viewport.height());
|
||||||
|
@ -58,20 +58,23 @@ public abstract class TileLayer extends Layer {
|
|||||||
|
|
||||||
private final Rect mDirtyRect;
|
private final Rect mDirtyRect;
|
||||||
private final CairoImage mImage;
|
private final CairoImage mImage;
|
||||||
private final boolean mRepeat;
|
|
||||||
private IntSize mSize;
|
private IntSize mSize;
|
||||||
private int[] mTextureIDs;
|
private int[] mTextureIDs;
|
||||||
|
|
||||||
public TileLayer(boolean repeat, CairoImage image) {
|
public enum PaintMode { NORMAL, REPEAT, STRETCH };
|
||||||
|
private PaintMode mPaintMode;
|
||||||
|
|
||||||
|
public TileLayer(CairoImage image, PaintMode paintMode) {
|
||||||
super(image.getSize());
|
super(image.getSize());
|
||||||
|
|
||||||
mRepeat = repeat;
|
mPaintMode = paintMode;
|
||||||
mImage = image;
|
mImage = image;
|
||||||
mSize = new IntSize(0, 0);
|
mSize = new IntSize(0, 0);
|
||||||
mDirtyRect = new Rect();
|
mDirtyRect = new Rect();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean repeats() { return mRepeat; }
|
protected boolean repeats() { return mPaintMode == PaintMode.REPEAT; }
|
||||||
|
protected boolean stretches() { return mPaintMode == PaintMode.STRETCH; }
|
||||||
protected int getTextureID() { return mTextureIDs[0]; }
|
protected int getTextureID() { return mTextureIDs[0]; }
|
||||||
protected boolean initialized() { return mImage != null && mTextureIDs != null; }
|
protected boolean initialized() { return mImage != null && mTextureIDs != null; }
|
||||||
|
|
||||||
@ -186,7 +189,7 @@ public abstract class TileLayer extends Layer {
|
|||||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
|
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
|
||||||
GLES20.GL_LINEAR);
|
GLES20.GL_LINEAR);
|
||||||
|
|
||||||
int repeatMode = mRepeat ? GLES20.GL_REPEAT : GLES20.GL_CLAMP_TO_EDGE;
|
int repeatMode = repeats() ? GLES20.GL_REPEAT : GLES20.GL_CLAMP_TO_EDGE;
|
||||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, repeatMode);
|
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, repeatMode);
|
||||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, repeatMode);
|
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, repeatMode);
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
|||||||
jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V");
|
jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V");
|
||||||
jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;Z)V");
|
jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;Z)V");
|
||||||
jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
|
jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
|
||||||
jNotifyScreenShot = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyScreenShot", "(Ljava/nio/ByteBuffer;III)V");
|
jNotifyScreenShot = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyScreenShot", "(Ljava/nio/ByteBuffer;IIIIII)V");
|
||||||
jAcknowledgeEventSync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEventSync", "()V");
|
jAcknowledgeEventSync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEventSync", "()V");
|
||||||
|
|
||||||
jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
|
jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
|
||||||
@ -166,6 +166,7 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
|||||||
jDisableBatteryNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableBatteryNotifications", "()V");
|
jDisableBatteryNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableBatteryNotifications", "()V");
|
||||||
jGetCurrentBatteryInformation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getCurrentBatteryInformation", "()[D");
|
jGetCurrentBatteryInformation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getCurrentBatteryInformation", "()[D");
|
||||||
jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;)V");
|
jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;)V");
|
||||||
|
jNotifyPaintedRect = jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyPaintedRect", "(FFFF)V");
|
||||||
|
|
||||||
jHandleGeckoMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "handleGeckoMessage", "(Ljava/lang/String;)Ljava/lang/String;");
|
jHandleGeckoMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "handleGeckoMessage", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||||
jCheckUriVisited = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "checkUriVisited", "(Ljava/lang/String;)V");
|
jCheckUriVisited = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "checkUriVisited", "(Ljava/lang/String;)V");
|
||||||
@ -2135,7 +2136,7 @@ jobject JNICALL
|
|||||||
Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *jenv, jclass, jlong size);
|
Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *jenv, jclass, jlong size);
|
||||||
|
|
||||||
|
|
||||||
nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId, float scale)
|
nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId, float scale, PRInt32 token)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(window);
|
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(window);
|
||||||
if (!win)
|
if (!win)
|
||||||
@ -2175,6 +2176,15 @@ nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt
|
|||||||
nsresult rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
|
nsresult rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
AndroidBridge::AutoLocalJNIFrame jniFrame(jenv, 1);
|
AndroidBridge::AutoLocalJNIFrame jniFrame(jenv, 1);
|
||||||
jenv->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyScreenShot, buffer, tabId, dstW, dstH);
|
jenv->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyScreenShot, buffer, tabId, srcX * dstW / srcW , srcY * dstH / srcH, dstW, dstH, token);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AndroidBridge::NotifyPaintedRect(float top, float left, float bottom, float right)
|
||||||
|
{
|
||||||
|
JNIEnv* jenv = AndroidBridge::GetJNIEnv();
|
||||||
|
if (!jenv)
|
||||||
|
return;
|
||||||
|
jenv->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyPaintedRect, top, left, bottom, right);
|
||||||
|
}
|
||||||
|
@ -183,7 +183,9 @@ public:
|
|||||||
|
|
||||||
static void RemovePluginView(void* surface);
|
static void RemovePluginView(void* surface);
|
||||||
|
|
||||||
nsresult TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId, float scale);
|
nsresult TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId, float scale, PRInt32 token);
|
||||||
|
|
||||||
|
static void NotifyPaintedRect(float top, float left, float bottom, float right);
|
||||||
|
|
||||||
void AcknowledgeEventSync();
|
void AcknowledgeEventSync();
|
||||||
|
|
||||||
@ -524,6 +526,7 @@ protected:
|
|||||||
jmethodID jCheckUriVisited;
|
jmethodID jCheckUriVisited;
|
||||||
jmethodID jMarkUriVisited;
|
jmethodID jMarkUriVisited;
|
||||||
jmethodID jRemovePluginView;
|
jmethodID jRemovePluginView;
|
||||||
|
jmethodID jNotifyPaintedRect;
|
||||||
|
|
||||||
jmethodID jNumberOfMessages;
|
jmethodID jNumberOfMessages;
|
||||||
jmethodID jSendMessage;
|
jmethodID jSendMessage;
|
||||||
|
@ -520,7 +520,13 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
|
|||||||
|
|
||||||
case SCREENSHOT: {
|
case SCREENSHOT: {
|
||||||
mMetaState = jenv->GetIntField(jobj, jMetaStateField);
|
mMetaState = jenv->GetIntField(jobj, jMetaStateField);
|
||||||
ReadPointArray(mPoints, jenv, jPoints, 2);
|
mFlags = jenv->GetIntField(jobj, jFlagsField);
|
||||||
|
ReadPointArray(mPoints, jenv, jPoints, 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PAINT_LISTEN_START_EVENT: {
|
||||||
|
mMetaState = jenv->GetIntField(jobj, jMetaStateField);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,6 +719,7 @@ public:
|
|||||||
SCREENORIENTATION_CHANGED = 27,
|
SCREENORIENTATION_CHANGED = 27,
|
||||||
COMPOSITOR_PAUSE = 28,
|
COMPOSITOR_PAUSE = 28,
|
||||||
COMPOSITOR_RESUME = 29,
|
COMPOSITOR_RESUME = 29,
|
||||||
|
PAINT_LISTEN_START_EVENT = 30,
|
||||||
dummy_java_enum_list_end
|
dummy_java_enum_list_end
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,6 +49,10 @@
|
|||||||
#include "nsIAppStartup.h"
|
#include "nsIAppStartup.h"
|
||||||
#include "nsIGeolocationProvider.h"
|
#include "nsIGeolocationProvider.h"
|
||||||
#include "nsCacheService.h"
|
#include "nsCacheService.h"
|
||||||
|
#include "nsIDOMEventListener.h"
|
||||||
|
#include "nsDOMNotifyPaintEvent.h"
|
||||||
|
#include "nsIDOMClientRectList.h"
|
||||||
|
#include "nsIDOMClientRect.h"
|
||||||
|
|
||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
@ -92,6 +96,64 @@ nsAppShell *nsAppShell::gAppShell = nsnull;
|
|||||||
|
|
||||||
NS_IMPL_ISUPPORTS_INHERITED1(nsAppShell, nsBaseAppShell, nsIObserver)
|
NS_IMPL_ISUPPORTS_INHERITED1(nsAppShell, nsBaseAppShell, nsIObserver)
|
||||||
|
|
||||||
|
class AfterPaintListener : public nsIDOMEventListener {
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
void Register(nsIDOMWindow* window) {
|
||||||
|
if (mEventTarget)
|
||||||
|
Unregister();
|
||||||
|
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(window);
|
||||||
|
if (!win)
|
||||||
|
return;
|
||||||
|
mEventTarget = win->GetChromeEventHandler();
|
||||||
|
if (mEventTarget)
|
||||||
|
mEventTarget->AddEventListener(NS_LITERAL_STRING("MozAfterPaint"), this, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unregister() {
|
||||||
|
if (mEventTarget)
|
||||||
|
mEventTarget->RemoveEventListener(NS_LITERAL_STRING("MozAfterPaint"), this, false);
|
||||||
|
mEventTarget = nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual nsresult HandleEvent(nsIDOMEvent* aEvent) {
|
||||||
|
nsCOMPtr<nsIDOMNotifyPaintEvent> paintEvent = do_QueryInterface(aEvent);
|
||||||
|
if (!paintEvent)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMClientRectList> rects;
|
||||||
|
paintEvent->GetClientRects(getter_AddRefs(rects));
|
||||||
|
if (!rects)
|
||||||
|
return NS_OK;
|
||||||
|
PRUint32 length;
|
||||||
|
rects->GetLength(&length);
|
||||||
|
for (PRUint32 i = 0; i < length; ++i) {
|
||||||
|
float top, left, bottom, right;
|
||||||
|
nsCOMPtr<nsIDOMClientRect> rect = rects->GetItemAt(i);
|
||||||
|
if (!rect)
|
||||||
|
continue;
|
||||||
|
rect->GetTop(&top);
|
||||||
|
rect->GetLeft(&left);
|
||||||
|
rect->GetRight(&right);
|
||||||
|
rect->GetBottom(&bottom);
|
||||||
|
AndroidBridge::NotifyPaintedRect(top, left, bottom, right);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
~AfterPaintListener() {
|
||||||
|
if (mEventTarget)
|
||||||
|
Unregister();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsCOMPtr<nsIDOMEventTarget> mEventTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS1(AfterPaintListener, nsIDOMEventListener)
|
||||||
|
nsCOMPtr<AfterPaintListener> sAfterPaintListener = nsnull;
|
||||||
|
|
||||||
nsAppShell::nsAppShell()
|
nsAppShell::nsAppShell()
|
||||||
: mQueueLock("nsAppShell.mQueueLock"),
|
: mQueueLock("nsAppShell.mQueueLock"),
|
||||||
mCondLock("nsAppShell.mCondLock"),
|
mCondLock("nsAppShell.mCondLock"),
|
||||||
@ -101,11 +163,13 @@ nsAppShell::nsAppShell()
|
|||||||
mAllowCoalescingNextDraw(false)
|
mAllowCoalescingNextDraw(false)
|
||||||
{
|
{
|
||||||
gAppShell = this;
|
gAppShell = this;
|
||||||
|
sAfterPaintListener = new AfterPaintListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAppShell::~nsAppShell()
|
nsAppShell::~nsAppShell()
|
||||||
{
|
{
|
||||||
gAppShell = nsnull;
|
gAppShell = nsnull;
|
||||||
|
delete sAfterPaintListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -369,6 +433,21 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AndroidGeckoEvent::PAINT_LISTEN_START_EVENT: {
|
||||||
|
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||||
|
nsCOMPtr<nsIBrowserTab> tab;
|
||||||
|
mBrowserApp->GetBrowserTab(curEvent->MetaState(), getter_AddRefs(tab));
|
||||||
|
if (!tab)
|
||||||
|
break;
|
||||||
|
|
||||||
|
tab->GetWindow(getter_AddRefs(domWindow));
|
||||||
|
if (!domWindow)
|
||||||
|
break;
|
||||||
|
|
||||||
|
sAfterPaintListener->Register(domWindow);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case AndroidGeckoEvent::SCREENSHOT: {
|
case AndroidGeckoEvent::SCREENSHOT: {
|
||||||
if (!mBrowserApp)
|
if (!mBrowserApp)
|
||||||
break;
|
break;
|
||||||
@ -392,8 +471,8 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
nsTArray<nsIntPoint> points = curEvent->Points();
|
nsTArray<nsIntPoint> points = curEvent->Points();
|
||||||
NS_ASSERTION(points.Length() == 2, "Screenshot event does not have enough coordinates");
|
NS_ASSERTION(points.Length() == 4, "Screenshot event does not have enough coordinates");
|
||||||
bridge->TakeScreenshot(domWindow, 0, 0, points[0].x, points[0].y, points[1].x, points[1].y, curEvent->MetaState(), scale);
|
bridge->TakeScreenshot(domWindow, points[0].x, points[0].y, points[1].x, points[1].y, points[3].x, points[3].y, curEvent->MetaState(), scale, curEvent->Flags());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user