From 584907300993449f2ef0e27f4ace320817c667b8 Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Thu, 11 Oct 2012 15:08:50 +0800 Subject: Revert "Revert "Upload screennails in tiles to prevent jank"" This reverts commit ad7cf187bf0c11b05aa3eab7085148e0353f2af5. bug: 6399444 Change-Id: I94b286ab3e0db21c582cbfa9183489613da30edb --- .../android/gallery3d/app/PhotoDataAdapter.java | 41 ++- src/com/android/gallery3d/ui/BasicTexture.java | 4 +- src/com/android/gallery3d/ui/BitmapScreenNail.java | 49 ++-- src/com/android/gallery3d/ui/GLCanvas.java | 7 + src/com/android/gallery3d/ui/GLCanvasImpl.java | 82 ++++-- src/com/android/gallery3d/ui/TileImageView.java | 3 +- src/com/android/gallery3d/ui/TiledTexture.java | 298 +++++++++++++++++++++ .../src/com/android/gallery3d/ui/GLCanvasStub.java | 2 + 8 files changed, 430 insertions(+), 56 deletions(-) create mode 100644 src/com/android/gallery3d/ui/TiledTexture.java diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java index 66f2874f7..5ab022ac6 100644 --- a/src/com/android/gallery3d/app/PhotoDataAdapter.java +++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java @@ -35,6 +35,7 @@ import com.android.gallery3d.ui.PhotoView; import com.android.gallery3d.ui.ScreenNail; import com.android.gallery3d.ui.SynchronizedHandler; import com.android.gallery3d.ui.TileImageViewAdapter; +import com.android.gallery3d.ui.TiledTexture; import com.android.gallery3d.util.Future; import com.android.gallery3d.util.FutureListener; import com.android.gallery3d.util.MediaSetUtils; @@ -59,8 +60,8 @@ public class PhotoDataAdapter implements PhotoPage.Model { private static final int MSG_RUN_OBJECT = 3; private static final int MSG_UPDATE_IMAGE_REQUESTS = 4; - private static final int MIN_LOAD_COUNT = 8; - private static final int DATA_CACHE_SIZE = 32; + private static final int MIN_LOAD_COUNT = 16; + private static final int DATA_CACHE_SIZE = 256; private static final int SCREEN_NAIL_MAX = PhotoView.SCREEN_NAIL_MAX; private static final int IMAGE_CACHE_SIZE = 2 * SCREEN_NAIL_MAX + 1; @@ -162,6 +163,7 @@ public class PhotoDataAdapter implements PhotoPage.Model { private DataListener mDataListener; private final SourceListener mSourceListener = new SourceListener(); + private final TiledTexture.Uploader mUploader; // The path of the current viewing item will be stored in mItemPath. // If mItemPath is not null, mCurrentIndex is only a hint for where we @@ -183,6 +185,8 @@ public class PhotoDataAdapter implements PhotoPage.Model { Arrays.fill(mChanges, MediaObject.INVALID_DATA_VERSION); + mUploader = new TiledTexture.Uploader(activity.getGLRoot()); + mMainHandler = new SynchronizedHandler(activity.getGLRoot()) { @SuppressWarnings("unchecked") @Override @@ -321,6 +325,7 @@ public class PhotoDataAdapter implements PhotoPage.Model { } } updateImageRequests(); + updateScreenNailUploadQueue(); } private void updateFullImage(Path path, Future future) { @@ -345,6 +350,8 @@ public class PhotoDataAdapter implements PhotoPage.Model { @Override public void resume() { mIsActive = true; + TiledTexture.prepareResources(); + mSource.addContentListener(mSourceListener); updateImageCache(); updateImageRequests(); @@ -371,6 +378,9 @@ public class PhotoDataAdapter implements PhotoPage.Model { } mImageCache.clear(); mTileProvider.clear(); + + mUploader.clear(); + TiledTexture.freeResources(); } private MediaItem getItem(int index) { @@ -394,6 +404,7 @@ public class PhotoDataAdapter implements PhotoPage.Model { updateImageCache(); updateImageRequests(); updateTileProvider(); + updateScreenNailUploadQueue(); if (mDataListener != null) { mDataListener.onPhotoChanged(index, mItemPath); @@ -402,6 +413,32 @@ public class PhotoDataAdapter implements PhotoPage.Model { fireDataChange(); } + private void uploadScreenNail(int offset) { + int index = mCurrentIndex + offset; + if (index < mActiveStart || index >= mActiveEnd) return; + + MediaItem item = getItem(index); + if (item == null) return; + + ImageEntry e = mImageCache.get(item.getPath()); + if (e == null) return; + + ScreenNail s = e.screenNail; + if (s instanceof BitmapScreenNail) { + TiledTexture t = ((BitmapScreenNail) s).getTexture(); + if (t != null && !t.isReady()) mUploader.addTexture(t); + } + } + + private void updateScreenNailUploadQueue() { + mUploader.clear(); + uploadScreenNail(0); + for (int i = 1; i < IMAGE_CACHE_SIZE; ++i) { + uploadScreenNail(i); + uploadScreenNail(-i); + } + } + @Override public void moveTo(int index) { updateCurrentIndex(index); diff --git a/src/com/android/gallery3d/ui/BasicTexture.java b/src/com/android/gallery3d/ui/BasicTexture.java index 7b8e30de4..99cf0571c 100644 --- a/src/com/android/gallery3d/ui/BasicTexture.java +++ b/src/com/android/gallery3d/ui/BasicTexture.java @@ -42,8 +42,8 @@ abstract class BasicTexture implements Texture { protected int mWidth = UNSPECIFIED; protected int mHeight = UNSPECIFIED; - private int mTextureWidth; - private int mTextureHeight; + protected int mTextureWidth; + protected int mTextureHeight; private boolean mHasBorder; diff --git a/src/com/android/gallery3d/ui/BitmapScreenNail.java b/src/com/android/gallery3d/ui/BitmapScreenNail.java index bf31bcbdf..9b629160c 100644 --- a/src/com/android/gallery3d/ui/BitmapScreenNail.java +++ b/src/com/android/gallery3d/ui/BitmapScreenNail.java @@ -46,16 +46,16 @@ public class BitmapScreenNail implements ScreenNail { private int mWidth; private int mHeight; - private Bitmap mBitmap; - private BitmapTexture mTexture; private long mAnimationStartTime = ANIMATION_NOT_NEEDED; + private Bitmap mBitmap; + private TiledTexture mTexture; + public BitmapScreenNail(Bitmap bitmap) { mWidth = bitmap.getWidth(); mHeight = bitmap.getHeight(); mBitmap = bitmap; - // We create mTexture lazily, so we don't incur the cost if we don't - // actually need it. + mTexture = new TiledTexture(bitmap); } public BitmapScreenNail(int width, int height) { @@ -103,17 +103,14 @@ public class BitmapScreenNail implements ScreenNail { BitmapScreenNail newer = (BitmapScreenNail) other; mWidth = newer.mWidth; mHeight = newer.mHeight; - if (newer.mBitmap != null) { + if (newer.mTexture != null) { recycleBitmap(MediaItem.getThumbPool(), mBitmap); + if (mTexture != null) mTexture.recycle(); mBitmap = newer.mBitmap; + mTexture = newer.mTexture; newer.mBitmap = null; - - if (mTexture != null) { - mTexture.recycle(); - mTexture = null; - } + newer.mTexture = null; } - newer.recycle(); return this; } @@ -158,7 +155,7 @@ public class BitmapScreenNail implements ScreenNail { @Override public void draw(GLCanvas canvas, int x, int y, int width, int height) { - if (mBitmap == null) { + if (mTexture == null || !mTexture.isReady()) { if (mAnimationStartTime == ANIMATION_NOT_NEEDED) { mAnimationStartTime = ANIMATION_NEEDED; } @@ -168,16 +165,12 @@ public class BitmapScreenNail implements ScreenNail { return; } - if (mTexture == null) { - mTexture = new BitmapTexture(mBitmap); - } - if (mAnimationStartTime == ANIMATION_NEEDED) { - mAnimationStartTime = now(); + mAnimationStartTime = AnimationTime.get(); } if (isAnimating()) { - canvas.drawMixed(mTexture, mPlaceholderColor, getRatio(), x, y, + mTexture.drawMixed(canvas, mPlaceholderColor, getRatio(), x, y, width, height); } else { mTexture.draw(canvas, x, y, width, height); @@ -186,34 +179,26 @@ public class BitmapScreenNail implements ScreenNail { @Override public void draw(GLCanvas canvas, RectF source, RectF dest) { - if (mBitmap == null) { + if (mTexture == null || !mTexture.isReady()) { canvas.fillRect(dest.left, dest.top, dest.width(), dest.height(), mPlaceholderColor); return; } - if (mTexture == null) { - mTexture = new BitmapTexture(mBitmap); - } - - canvas.drawTexture(mTexture, source, dest); + mTexture.draw(canvas, source, dest); } public boolean isAnimating() { if (mAnimationStartTime < 0) return false; - if (now() - mAnimationStartTime >= DURATION) { + if (AnimationTime.get() - mAnimationStartTime >= DURATION) { mAnimationStartTime = ANIMATION_DONE; return false; } return true; } - private static long now() { - return AnimationTime.get(); - } - private float getRatio() { - float r = (float)(now() - mAnimationStartTime) / DURATION; + float r = (float) (AnimationTime.get() - mAnimationStartTime) / DURATION; return Utils.clamp(1.0f - r, 0.0f, 1.0f); } @@ -221,6 +206,10 @@ public class BitmapScreenNail implements ScreenNail { return (mBitmap == null) || isAnimating(); } + public TiledTexture getTexture() { + return mTexture; + } + public static void setMaxSide(int size) { sMaxSide = size; } diff --git a/src/com/android/gallery3d/ui/GLCanvas.java b/src/com/android/gallery3d/ui/GLCanvas.java index e3a32ef08..6f8baef7e 100644 --- a/src/com/android/gallery3d/ui/GLCanvas.java +++ b/src/com/android/gallery3d/ui/GLCanvas.java @@ -99,6 +99,13 @@ public interface GLCanvas { public void drawMixed(BasicTexture from, int toColor, float ratio, int x, int y, int w, int h); + // Draw a region of a texture and a specified color to the specified + // rectangle. The actual color used is from * (1 - ratio) + to * ratio. + // The region of the texture is defined by parameter "src". The target + // rectangle is specified by parameter "target". + public void drawMixed(BasicTexture from, int toColor, + float ratio, RectF src, RectF target); + // Gets the underlying GL instance. This is used only when direct access to // GL is needed. public GL11 getGLInstance(); diff --git a/src/com/android/gallery3d/ui/GLCanvasImpl.java b/src/com/android/gallery3d/ui/GLCanvasImpl.java index d83daf3e4..45903b3cd 100644 --- a/src/com/android/gallery3d/ui/GLCanvasImpl.java +++ b/src/com/android/gallery3d/ui/GLCanvasImpl.java @@ -415,7 +415,7 @@ public class GLCanvasImpl implements GLCanvas { // This function changes the source coordinate to the texture coordinates. // It also clips the source and target coordinates if it is beyond the // bound of the texture. - private void convertCoordinate(RectF source, RectF target, + private static void convertCoordinate(RectF source, RectF target, BasicTexture texture) { int width = texture.getWidth(); @@ -465,23 +465,7 @@ public class GLCanvasImpl implements GLCanvas { color[3] = alpha; } - private void drawMixed(BasicTexture from, int toColor, - float ratio, int x, int y, int width, int height, float alpha) { - // change from 0 to 0.01f to prevent getting divided by zero below - if (ratio <= 0.01f) { - drawTexture(from, x, y, width, height, alpha); - return; - } else if (ratio >= 1) { - fillRect(x, y, width, height, toColor); - return; - } - - mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque() - || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA)); - - final GL11 gl = mGL; - if (!bindTexture(from)) return; - + private void setMixedColor(int toColor, float ratio, float alpha) { // // The formula we want: // alpha * ((1 - ratio) * from + ratio * to) @@ -495,9 +479,6 @@ public class GLCanvasImpl implements GLCanvas { float combo = alpha * (1 - ratio); float scale = alpha * ratio / (1 - combo); - // Interpolate the RGB and alpha values between both textures. - mGLState.setTexEnvMode(GL11.GL_COMBINE); - // Specify the interpolation factor via the alpha component of // GL_TEXTURE_ENV_COLORs. // RGB component are get from toColor and will used as SRC1 @@ -505,6 +486,7 @@ public class GLCanvasImpl implements GLCanvas { setTextureColor(((toColor >>> 16) & 0xff) * colorScale, ((toColor >>> 8) & 0xff) * colorScale, (toColor & 0xff) * colorScale, combo); + GL11 gl = mGL; gl.glTexEnvfv(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_COLOR, mTextureColor, 0); gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_RGB, GL11.GL_INTERPOLATE); @@ -522,6 +504,64 @@ public class GLCanvasImpl implements GLCanvas { gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC2_ALPHA, GL11.GL_CONSTANT); gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND2_ALPHA, GL11.GL_SRC_ALPHA); + } + + @Override + public void drawMixed(BasicTexture from, int toColor, float ratio, + RectF source, RectF target) { + if (target.width() <= 0 || target.height() <= 0) return; + + if (ratio <= 0.01f) { + drawTexture(from, source, target); + return; + } else if (ratio >= 1) { + fillRect(target.left, target.top, target.width(), target.height(), toColor); + return; + } + + float alpha = mAlpha; + + // Copy the input to avoid changing it. + mDrawTextureSourceRect.set(source); + mDrawTextureTargetRect.set(target); + source = mDrawTextureSourceRect; + target = mDrawTextureTargetRect; + + mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque() + || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA)); + + if (!bindTexture(from)) return; + + // Interpolate the RGB and alpha values between both textures. + mGLState.setTexEnvMode(GL11.GL_COMBINE); + setMixedColor(toColor, ratio, alpha); + convertCoordinate(source, target, from); + setTextureCoords(source); + textureRect(target.left, target.top, target.width(), target.height()); + mGLState.setTexEnvMode(GL11.GL_REPLACE); + } + + private void drawMixed(BasicTexture from, int toColor, + float ratio, int x, int y, int width, int height, float alpha) { + // change from 0 to 0.01f to prevent getting divided by zero below + if (ratio <= 0.01f) { + drawTexture(from, x, y, width, height, alpha); + return; + } else if (ratio >= 1) { + fillRect(x, y, width, height, toColor); + return; + } + + mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque() + || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA)); + + final GL11 gl = mGL; + if (!bindTexture(from)) return; + + // Interpolate the RGB and alpha values between both textures. + mGLState.setTexEnvMode(GL11.GL_COMBINE); + setMixedColor(toColor, ratio, alpha); + drawBoundTexture(from, x, y, width, height); mGLState.setTexEnvMode(GL11.GL_REPLACE); } diff --git a/src/com/android/gallery3d/ui/TileImageView.java b/src/com/android/gallery3d/ui/TileImageView.java index 5ce06bec4..18a7af849 100644 --- a/src/com/android/gallery3d/ui/TileImageView.java +++ b/src/com/android/gallery3d/ui/TileImageView.java @@ -575,8 +575,10 @@ public class TileImageView extends GLView { } if (tile == null) break; if (!tile.isContentValid()) { + boolean hasBeenLoaded = tile.isLoaded(); Utils.assertTrue(tile.mTileState == STATE_DECODED); tile.updateContent(canvas); + if (!hasBeenLoaded) tile.draw(canvas, 0, 0); --quota; } } @@ -621,7 +623,6 @@ public class TileImageView extends GLView { } } - // TODO: avoid drawing the unused part of the textures. static boolean drawTile( Tile tile, GLCanvas canvas, RectF source, RectF target) { while (true) { diff --git a/src/com/android/gallery3d/ui/TiledTexture.java b/src/com/android/gallery3d/ui/TiledTexture.java new file mode 100644 index 000000000..6e9ad9ea8 --- /dev/null +++ b/src/com/android/gallery3d/ui/TiledTexture.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.ui; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff.Mode; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; + +import com.android.gallery3d.ui.GLRoot.OnGLIdleListener; + +import java.util.ArrayDeque; +import java.util.ArrayList; + +// This class is similar to BitmapTexture, except the bitmap is +// split into tiles. By doing so, we may increase the time required to +// upload the whole bitmap but we reduce the time of uploading each tile +// so it make the animation more smooth and prevents jank. +public class TiledTexture { + private static final int CONTENT_SIZE = 254; + private static final int BORDER_SIZE = 1; + private static final int TILE_SIZE = CONTENT_SIZE + 2 * BORDER_SIZE; + private static final int INIT_CAPACITY = 8; + + private static Tile sFreeTileHead = null; + private static final Object sFreeTileLock = new Object(); + + private static Bitmap sUploadBitmap; + private static Canvas sCanvas; + private static Paint sPaint; + + private int mUploadIndex = 0; + + private final Tile[] mTiles; + private final int mWidth; + private final int mHeight; + private final RectF mSrcRect = new RectF(); + private final RectF mDestRect = new RectF(); + + public static class Uploader implements OnGLIdleListener { + private final ArrayDeque mTextures = + new ArrayDeque(INIT_CAPACITY); + + private final GLRoot mGlRoot; + private boolean mIsQueued = false; + + public Uploader(GLRoot glRoot) { + mGlRoot = glRoot; + } + + public synchronized void clear() { + mTextures.clear(); + } + + public synchronized void addTexture(TiledTexture t) { + if (t.isReady()) return; + mTextures.addLast(t); + + if (mIsQueued) return; + mIsQueued = true; + mGlRoot.addOnGLIdleListener(this); + } + + + @Override + public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) { + ArrayDeque deque = mTextures; + synchronized (this) { + if (!deque.isEmpty()) { + TiledTexture t = deque.peekFirst(); + if (t.uploadNextTile(canvas)) { + deque.removeFirst(); + mGlRoot.requestRender(); + } + } + mIsQueued = !mTextures.isEmpty(); + + // return true to keep this listener in the queue + return mIsQueued; + } + } + } + + private static class Tile extends UploadedTexture { + public int offsetX; + public int offsetY; + public Bitmap bitmap; + public Tile nextFreeTile; + public int contentWidth; + public int contentHeight; + + @Override + public void setSize(int width, int height) { + contentWidth = width; + contentHeight = height; + mWidth = width + 2 * BORDER_SIZE; + mHeight = height + 2 * BORDER_SIZE; + mTextureWidth = TILE_SIZE; + mTextureHeight = TILE_SIZE; + } + + @Override + protected Bitmap onGetBitmap() { + int x = BORDER_SIZE - offsetX; + int y = BORDER_SIZE - offsetY; + int r = bitmap.getWidth() - x; + int b = bitmap.getHeight() - y ; + sCanvas.drawBitmap(bitmap, x, y, null); + bitmap = null; + + // draw borders if need + if (x > 0) sCanvas.drawLine(x - 1, 0, x - 1, TILE_SIZE, sPaint); + if (y > 0) sCanvas.drawLine(0, y - 1, TILE_SIZE, y - 1, sPaint); + if (r < CONTENT_SIZE) sCanvas.drawLine(r, 0, r, TILE_SIZE, sPaint); + if (b < CONTENT_SIZE) sCanvas.drawLine(0, b, TILE_SIZE, b, sPaint); + + return sUploadBitmap; + } + + @Override + protected void onFreeBitmap(Bitmap bitmap) { + // do nothing + } + } + + private static void freeTile(Tile tile) { + tile.invalidateContent(); + tile.bitmap = null; + synchronized (sFreeTileLock) { + tile.nextFreeTile = sFreeTileHead; + sFreeTileHead = tile; + } + } + + private static Tile obtainTile() { + synchronized (sFreeTileLock) { + Tile result = sFreeTileHead; + if (result == null) return new Tile(); + sFreeTileHead = result.nextFreeTile; + result.nextFreeTile = null; + return result; + } + } + + private boolean uploadNextTile(GLCanvas canvas) { + if (mUploadIndex == mTiles.length) return true; + Tile next = mTiles[mUploadIndex++]; + boolean hasBeenLoad = next.isLoaded(); + next.updateContent(canvas); + + // It will take some time for a texture to be drawn for the first + // time. When scrolling, we need to draw several tiles on the screen + // at the same time. It may cause a UI jank even these textures has + // been uploaded. + if (!hasBeenLoad) next.draw(canvas, 0, 0); + return mUploadIndex == mTiles.length; + } + + public TiledTexture(Bitmap bitmap) { + mWidth = bitmap.getWidth(); + mHeight = bitmap.getHeight(); + ArrayList list = new ArrayList(); + + for (int x = 0, w = mWidth; x < w; x += CONTENT_SIZE) { + for (int y = 0, h = mHeight; y < h; y += CONTENT_SIZE) { + Tile tile = obtainTile(); + tile.offsetX = x; + tile.offsetY = y; + tile.bitmap = bitmap; + tile.setSize( + Math.min(CONTENT_SIZE, mWidth - x), + Math.min(CONTENT_SIZE, mHeight - y)); + list.add(tile); + } + } + mTiles = list.toArray(new Tile[list.size()]); + } + + public boolean isReady() { + return mUploadIndex == mTiles.length; + } + + public void recycle() { + for (int i = 0, n = mTiles.length; i < n; ++i) { + freeTile(mTiles[i]); + } + } + + public static void freeResources() { + sUploadBitmap = null; + sCanvas = null; + sPaint = null; + } + + public static void prepareResources() { + sUploadBitmap = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE, Config.ARGB_8888); + sCanvas = new Canvas(sUploadBitmap); + sPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + sPaint.setColor(Color.TRANSPARENT); + sPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); + } + + // We want to draw the "source" on the "target". + // This method is to find the "output" rectangle which is + // the corresponding area of the "src". + // (x,y) target + // (x0,y0) source +---------------+ + // +----------+ | | + // | src | | output | + // | +--+ | linear map | +----+ | + // | +--+ | ----------> | | | | + // | | by (scaleX, scaleY) | +----+ | + // +----------+ | | + // Texture +---------------+ + // Canvas + private static void mapRect(RectF output, + RectF src, float x0, float y0, float x, float y, float scaleX, + float scaleY) { + output.set(x + (src.left - x0) * scaleX, + y + (src.top - y0) * scaleY, + x + (src.right - x0) * scaleX, + y + (src.bottom - y0) * scaleY); + } + + // Draws a mixed color of this texture and a specified color onto the + // a rectangle. The used color is: from * (1 - ratio) + to * ratio. + public void drawMixed(GLCanvas canvas, int color, float ratio, + int x, int y, int width, int height) { + RectF src = mSrcRect; + RectF dest = mDestRect; + float scaleX = (float) width / mWidth ; + float scaleY = (float) height / mHeight; + for (int i = 0, n = mTiles.length; i < n; ++i) { + Tile t = mTiles[i]; + src.set(0, 0, t.contentWidth, t.contentHeight); + src.offset(t.offsetX, t.offsetY); + mapRect(dest, src, 0, 0, x, y, scaleX, scaleY); + src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); + canvas.drawMixed(t, color, ratio, mSrcRect, mDestRect); + } + } + + // Draws the texture on to the specified rectangle. + public void draw(GLCanvas canvas, int x, int y, int width, int height) { + RectF src = mSrcRect; + RectF dest = mDestRect; + float scaleX = (float) width / mWidth ; + float scaleY = (float) height / mHeight; + for (int i = 0, n = mTiles.length; i < n; ++i) { + Tile t = mTiles[i]; + src.set(0, 0, t.contentWidth, t.contentHeight); + src.offset(t.offsetX, t.offsetY); + mapRect(dest, src, 0, 0, x, y, scaleX, scaleY); + src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); + canvas.drawTexture(t, mSrcRect, mDestRect); + } + } + + // Draws a sub region of this texture on to the specified rectangle. + public void draw(GLCanvas canvas, RectF source, RectF target) { + RectF src = mSrcRect; + RectF dest = mDestRect; + float x0 = source.left; + float y0 = source.top; + float x = target.left; + float y = target.top; + float scaleX = target.width() / source.width(); + float scaleY = target.height() / source.height(); + + for (int i = 0, n = mTiles.length; i < n; ++i) { + Tile t = mTiles[i]; + src.set(0, 0, t.contentWidth, t.contentHeight); + src.offset(t.offsetX, t.offsetY); + if (!src.intersect(source)) continue; + mapRect(dest, src, x0, y0, x, y, scaleX, scaleY); + src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); + canvas.drawTexture(t, src, dest); + } + } +} diff --git a/tests/src/com/android/gallery3d/ui/GLCanvasStub.java b/tests/src/com/android/gallery3d/ui/GLCanvasStub.java index 2f2d753e0..5a08b8599 100644 --- a/tests/src/com/android/gallery3d/ui/GLCanvasStub.java +++ b/tests/src/com/android/gallery3d/ui/GLCanvasStub.java @@ -83,4 +83,6 @@ public class GLCanvasStub implements GLCanvas { public void dumpStatisticsAndClear() {} public void beginRenderTarget(RawTexture texture) {} public void endRenderTarget() {} + public void drawMixed(BasicTexture from, int toColor, + float ratio, RectF src, RectF target) {} } -- cgit v1.2.3