packages/apps/Gallery2
修订版 | 0461b1058ff1b3bb9933a6e912851eda0bddf46c (tree) |
---|---|
时间 | 2011-09-23 13:48:14 |
作者 | Chih-Chung Chang <chihchung@goog...> |
Commiter | Android (Google) Code Review |
Merge "Fix 5223982: Adding one pixel transparent border around the texture."
@@ -357,7 +357,7 @@ public class AlbumSetSlidingWindow implements AlbumSetView.ModelListener { | ||
357 | 357 | if (mActiveRequestCount == 0) requestNonactiveImages(); |
358 | 358 | } |
359 | 359 | if (bitmap != null) { |
360 | - BitmapTexture texture = new BitmapTexture(bitmap); | |
360 | + BitmapTexture texture = new BitmapTexture(bitmap, true); | |
361 | 361 | texture.setThrottled(true); |
362 | 362 | updateContent(texture); |
363 | 363 | if (mListener != null) mListener.onContentInvalidated(); |
@@ -304,7 +304,7 @@ public class AlbumSlidingWindow implements AlbumView.ModelListener { | ||
304 | 304 | if (mActiveRequestCount == 0) requestNonactiveImages(); |
305 | 305 | } |
306 | 306 | if (bitmap != null) { |
307 | - BitmapTexture texture = new BitmapTexture(bitmap); | |
307 | + BitmapTexture texture = new BitmapTexture(bitmap, true); | |
308 | 308 | texture.setThrottled(true); |
309 | 309 | updateContent(texture); |
310 | 310 | if (mListener != null && isActiveSlot) { |
@@ -43,6 +43,8 @@ abstract class BasicTexture implements Texture { | ||
43 | 43 | private int mTextureWidth; |
44 | 44 | private int mTextureHeight; |
45 | 45 | |
46 | + private boolean mHasBorder; | |
47 | + | |
46 | 48 | protected WeakReference<GLCanvas> mCanvasRef = null; |
47 | 49 | private static WeakHashMap<BasicTexture, Object> sAllTextures |
48 | 50 | = new WeakHashMap<BasicTexture, Object>(); |
@@ -100,6 +102,25 @@ abstract class BasicTexture implements Texture { | ||
100 | 102 | return mTextureHeight; |
101 | 103 | } |
102 | 104 | |
105 | + // Returns true if the texture has one pixel transparent border around the | |
106 | + // actual content. This is used to avoid jigged edges. | |
107 | + // | |
108 | + // The jigged edges appear because we use GL_CLAMP_TO_EDGE for texture wrap | |
109 | + // mode (GL_CLAMP is not available in OpenGL ES), so a pixel partially | |
110 | + // covered by the texture will use the color of the edge texel. If we add | |
111 | + // the transparent border, the color of the edge texel will be mixed with | |
112 | + // appropriate amount of transparent. | |
113 | + // | |
114 | + // Currently our background is black, so we can draw the thumbnails without | |
115 | + // enabling blending. | |
116 | + public boolean hasBorder() { | |
117 | + return mHasBorder; | |
118 | + } | |
119 | + | |
120 | + protected void setBorder(boolean hasBorder) { | |
121 | + mHasBorder = hasBorder; | |
122 | + } | |
123 | + | |
103 | 124 | public void draw(GLCanvas canvas, int x, int y) { |
104 | 125 | canvas.drawTexture(this, x, y, getWidth(), getHeight()); |
105 | 126 | } |
@@ -29,6 +29,11 @@ public class BitmapTexture extends UploadedTexture { | ||
29 | 29 | protected Bitmap mContentBitmap; |
30 | 30 | |
31 | 31 | public BitmapTexture(Bitmap bitmap) { |
32 | + this(bitmap, false); | |
33 | + } | |
34 | + | |
35 | + public BitmapTexture(Bitmap bitmap, boolean hasBorder) { | |
36 | + super(hasBorder); | |
32 | 37 | Utils.assertTrue(bitmap != null && !bitmap.isRecycled()); |
33 | 38 | mContentBitmap = bitmap; |
34 | 39 | } |
@@ -341,9 +341,17 @@ public class GLCanvasImpl implements GLCanvas { | ||
341 | 341 | // Test whether it has been rotated or flipped, if so, glDrawTexiOES |
342 | 342 | // won't work |
343 | 343 | if (isMatrixRotatedOrFlipped(mMatrixValues)) { |
344 | - setTextureCoords(0, 0, | |
345 | - (float) texture.getWidth() / texture.getTextureWidth(), | |
346 | - (float) texture.getHeight() / texture.getTextureHeight()); | |
344 | + if (texture.hasBorder()) { | |
345 | + setTextureCoords( | |
346 | + 1.0f / texture.getTextureWidth(), | |
347 | + 1.0f / texture.getTextureHeight(), | |
348 | + (texture.getWidth() - 1.0f) / texture.getTextureWidth(), | |
349 | + (texture.getHeight() - 1.0f) / texture.getTextureHeight()); | |
350 | + } else { | |
351 | + setTextureCoords(0, 0, | |
352 | + (float) texture.getWidth() / texture.getTextureWidth(), | |
353 | + (float) texture.getHeight() / texture.getTextureHeight()); | |
354 | + } | |
347 | 355 | textureRect(x, y, width, height); |
348 | 356 | } else { |
349 | 357 | // draw the rect from bottom-left to top-right |
@@ -24,7 +24,6 @@ import android.graphics.Color; | ||
24 | 24 | import android.text.Layout; |
25 | 25 | |
26 | 26 | public class GridDrawer extends IconDrawer { |
27 | - private final NinePatchTexture mFrameSelected; | |
28 | 27 | private Texture mImportLabel; |
29 | 28 | private int mGridWidth; |
30 | 29 | private final SelectionManager mSelectionManager; |
@@ -37,7 +36,6 @@ public class GridDrawer extends IconDrawer { | ||
37 | 36 | public GridDrawer(Context context, SelectionManager selectionManager) { |
38 | 37 | super(context); |
39 | 38 | mContext = context; |
40 | - mFrameSelected = new NinePatchTexture(context, R.drawable.grid_selected); | |
41 | 39 | mSelectionManager = selectionManager; |
42 | 40 | } |
43 | 41 |
@@ -80,7 +78,7 @@ public class GridDrawer extends IconDrawer { | ||
80 | 78 | if (mSelectionManager.isPressedPath(path)) { |
81 | 79 | drawPressedFrame(canvas, x, y, width, height); |
82 | 80 | } else if (mSelectionMode && mSelectionManager.isItemSelected(path)) { |
83 | - drawFrame(canvas, mFrameSelected, x, y, width, height); | |
81 | + drawSelectedFrame(canvas, x, y, width, height); | |
84 | 82 | } |
85 | 83 | } |
86 | 84 |
@@ -21,13 +21,11 @@ import com.android.gallery3d.data.Path; | ||
21 | 21 | import android.content.Context; |
22 | 22 | |
23 | 23 | public class HighlightDrawer extends IconDrawer { |
24 | - private final NinePatchTexture mFrameSelected; | |
25 | 24 | private SelectionManager mSelectionManager; |
26 | 25 | private Path mHighlightItem; |
27 | 26 | |
28 | 27 | public HighlightDrawer(Context context, SelectionManager selectionManager) { |
29 | 28 | super(context); |
30 | - mFrameSelected = new NinePatchTexture(context, R.drawable.grid_selected); | |
31 | 29 | mSelectionManager = selectionManager; |
32 | 30 | } |
33 | 31 |
@@ -64,8 +62,8 @@ public class HighlightDrawer extends IconDrawer { | ||
64 | 62 | |
65 | 63 | if (mSelectionManager.isPressedPath(path)) { |
66 | 64 | drawPressedFrame(canvas, x, y, width, height); |
67 | - } else if (path == mHighlightItem) { | |
68 | - drawFrame(canvas, mFrameSelected, x, y, width, height); | |
65 | + } else if (path == mHighlightItem) { | |
66 | + drawSelectedFrame(canvas, x, y, width, height); | |
69 | 67 | } |
70 | 68 | } |
71 | 69 | } |
@@ -29,6 +29,8 @@ public abstract class IconDrawer extends SelectionDrawer { | ||
29 | 29 | private final ResourceTexture mPicasaIcon; |
30 | 30 | private final ResourceTexture mMtpIcon; |
31 | 31 | private final NinePatchTexture mFramePressed; |
32 | + private final NinePatchTexture mFrameSelected; | |
33 | + private final NinePatchTexture mDarkStrip; | |
32 | 34 | private final ResourceTexture mPanoramaBorder; |
33 | 35 | private final Texture mVideoOverlay; |
34 | 36 | private final Texture mVideoPlayIcon; |
@@ -50,6 +52,8 @@ public abstract class IconDrawer extends SelectionDrawer { | ||
50 | 52 | mVideoPlayIcon = new ResourceTexture(context, R.drawable.ic_gallery_play); |
51 | 53 | mPanoramaBorder = new ResourceTexture(context, R.drawable.ic_pan_thumb); |
52 | 54 | mFramePressed = new NinePatchTexture(context, R.drawable.grid_pressed); |
55 | + mFrameSelected = new NinePatchTexture(context, R.drawable.grid_selected); | |
56 | + mDarkStrip = new NinePatchTexture(context, R.drawable.dark_strip); | |
53 | 57 | mIconSize = context.getResources().getDimensionPixelSize( |
54 | 58 | R.dimen.albumset_icon_size); |
55 | 59 | } |
@@ -144,7 +148,7 @@ public abstract class IconDrawer extends SelectionDrawer { | ||
144 | 148 | int drawLabelBackground) { |
145 | 149 | int x = -width / 2; |
146 | 150 | int y = (height + 1) / 2 - drawLabelBackground; |
147 | - canvas.fillRect(x, y, width, drawLabelBackground, LABEL_BACKGROUND_COLOR); | |
151 | + drawFrame(canvas, mDarkStrip, x, y, width, drawLabelBackground); | |
148 | 152 | } |
149 | 153 | |
150 | 154 | protected void drawPressedFrame(GLCanvas canvas, int x, int y, int width, |
@@ -152,6 +156,11 @@ public abstract class IconDrawer extends SelectionDrawer { | ||
152 | 156 | drawFrame(canvas, mFramePressed, x, y, width, height); |
153 | 157 | } |
154 | 158 | |
159 | + protected void drawSelectedFrame(GLCanvas canvas, int x, int y, int width, | |
160 | + int height) { | |
161 | + drawFrame(canvas, mFrameSelected, x, y, width, height); | |
162 | + } | |
163 | + | |
155 | 164 | @Override |
156 | 165 | public void drawFocus(GLCanvas canvas, int width, int height) { |
157 | 166 | } |
@@ -238,8 +238,6 @@ public class SlotView extends GLView { | ||
238 | 238 | |
239 | 239 | @Override |
240 | 240 | protected void render(GLCanvas canvas) { |
241 | - canvas.save(GLCanvas.SAVE_FLAG_CLIP); | |
242 | - canvas.clipRect(0, 0, getWidth(), getHeight()); | |
243 | 241 | super.render(canvas); |
244 | 242 | |
245 | 243 | long currentTimeMillis = canvas.currentAnimationTimeMillis(); |
@@ -296,7 +294,6 @@ public class SlotView extends GLView { | ||
296 | 294 | mUIListener.onUserInteractionEnd(); |
297 | 295 | } |
298 | 296 | mMoreAnimation = more; |
299 | - canvas.restore(); | |
300 | 297 | } |
301 | 298 | |
302 | 299 | private boolean renderItem(GLCanvas canvas, ItemEntry entry, |
@@ -57,9 +57,18 @@ abstract class UploadedTexture extends BasicTexture { | ||
57 | 57 | private static final int UPLOAD_LIMIT = 100; |
58 | 58 | |
59 | 59 | protected Bitmap mBitmap; |
60 | + private int mBorder; | |
60 | 61 | |
61 | 62 | protected UploadedTexture() { |
63 | + this(false); | |
64 | + } | |
65 | + | |
66 | + protected UploadedTexture(boolean hasBorder) { | |
62 | 67 | super(null, 0, STATE_UNLOADED); |
68 | + if (hasBorder) { | |
69 | + setBorder(true); | |
70 | + mBorder = 1; | |
71 | + } | |
63 | 72 | } |
64 | 73 | |
65 | 74 | private static class BorderKey implements Cloneable { |
@@ -114,14 +123,14 @@ abstract class UploadedTexture extends BasicTexture { | ||
114 | 123 | private Bitmap getBitmap() { |
115 | 124 | if (mBitmap == null) { |
116 | 125 | mBitmap = onGetBitmap(); |
126 | + int w = mBitmap.getWidth() + mBorder * 2; | |
127 | + int h = mBitmap.getHeight() + mBorder * 2; | |
117 | 128 | if (mWidth == UNSPECIFIED) { |
118 | - setSize(mBitmap.getWidth(), mBitmap.getHeight()); | |
119 | - } else if (mWidth != mBitmap.getWidth() | |
120 | - || mHeight != mBitmap.getHeight()) { | |
129 | + setSize(w, h); | |
130 | + } else if (mWidth != w || mHeight != h) { | |
121 | 131 | throw new IllegalStateException(String.format( |
122 | 132 | "cannot change size: this = %s, orig = %sx%s, new = %sx%s", |
123 | - toString(), mWidth, mHeight, mBitmap.getWidth(), | |
124 | - mBitmap.getHeight())); | |
133 | + toString(), mWidth, mHeight, w, h)); | |
125 | 134 | } |
126 | 135 | } |
127 | 136 | return mBitmap; |
@@ -176,8 +185,8 @@ abstract class UploadedTexture extends BasicTexture { | ||
176 | 185 | int format = GLUtils.getInternalFormat(bitmap); |
177 | 186 | int type = GLUtils.getType(bitmap); |
178 | 187 | canvas.getGLInstance().glBindTexture(GL11.GL_TEXTURE_2D, mId); |
179 | - GLUtils.texSubImage2D( | |
180 | - GL11.GL_TEXTURE_2D, 0, 0, 0, bitmap, format, type); | |
188 | + GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, mBorder, mBorder, | |
189 | + bitmap, format, type); | |
181 | 190 | freeBitmap(); |
182 | 191 | mContentValid = true; |
183 | 192 | } |
@@ -200,14 +209,20 @@ abstract class UploadedTexture extends BasicTexture { | ||
200 | 209 | Bitmap bitmap = getBitmap(); |
201 | 210 | if (bitmap != null) { |
202 | 211 | try { |
212 | + int bWidth = bitmap.getWidth(); | |
213 | + int bHeight = bitmap.getHeight(); | |
214 | + int width = bWidth + mBorder * 2; | |
215 | + int height = bHeight + mBorder * 2; | |
216 | + int texWidth = getTextureWidth(); | |
217 | + int texHeight = getTextureHeight(); | |
203 | 218 | // Define a vertically flipped crop rectangle for |
204 | 219 | // OES_draw_texture. |
205 | - int width = bitmap.getWidth(); | |
206 | - int height = bitmap.getHeight(); | |
207 | - sCropRect[0] = 0; | |
208 | - sCropRect[1] = height; | |
209 | - sCropRect[2] = width; | |
210 | - sCropRect[3] = -height; | |
220 | + // The four values in sCropRect are: left, bottom, width, and | |
221 | + // height. Negative value of width or height means flip. | |
222 | + sCropRect[0] = mBorder; | |
223 | + sCropRect[1] = mBorder + bHeight; | |
224 | + sCropRect[2] = bWidth; | |
225 | + sCropRect[3] = -bHeight; | |
211 | 226 | |
212 | 227 | // Upload the bitmap to a new texture. |
213 | 228 | gl.glGenTextures(1, sTextureId, 0); |
@@ -223,7 +238,7 @@ abstract class UploadedTexture extends BasicTexture { | ||
223 | 238 | gl.glTexParameterf(GL11.GL_TEXTURE_2D, |
224 | 239 | GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); |
225 | 240 | |
226 | - if (width == getTextureWidth() && height == getTextureHeight()) { | |
241 | + if (bWidth == texWidth && bHeight == texHeight) { | |
227 | 242 | GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0); |
228 | 243 | } else { |
229 | 244 | int format = GLUtils.getInternalFormat(bitmap); |
@@ -231,23 +246,35 @@ abstract class UploadedTexture extends BasicTexture { | ||
231 | 246 | Config config = bitmap.getConfig(); |
232 | 247 | |
233 | 248 | gl.glTexImage2D(GL11.GL_TEXTURE_2D, 0, format, |
234 | - getTextureWidth(), getTextureHeight(), | |
235 | - 0, format, type, null); | |
236 | - GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, bitmap, | |
237 | - format, type); | |
238 | - | |
239 | - if (width != getTextureWidth()) { | |
240 | - Bitmap line = getBorderLine(true, config, getTextureHeight()); | |
241 | - GLUtils.texSubImage2D( | |
242 | - GL11.GL_TEXTURE_2D, 0, width, 0, line, format, type); | |
249 | + texWidth, texHeight, 0, format, type, null); | |
250 | + GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, | |
251 | + mBorder, mBorder, bitmap, format, type); | |
252 | + | |
253 | + if (mBorder > 0) { | |
254 | + // Left border | |
255 | + Bitmap line = getBorderLine(true, config, texHeight); | |
256 | + GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, | |
257 | + 0, 0, line, format, type); | |
258 | + | |
259 | + // Top border | |
260 | + line = getBorderLine(false, config, texWidth); | |
261 | + GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, | |
262 | + 0, 0, line, format, type); | |
243 | 263 | } |
244 | 264 | |
245 | - if (height != getTextureHeight()) { | |
246 | - Bitmap line = getBorderLine(false, config, getTextureWidth()); | |
247 | - GLUtils.texSubImage2D( | |
248 | - GL11.GL_TEXTURE_2D, 0, 0, height, line, format, type); | |
265 | + // Right border | |
266 | + if (mBorder + bWidth < texWidth) { | |
267 | + Bitmap line = getBorderLine(true, config, texHeight); | |
268 | + GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, | |
269 | + mBorder + bWidth, 0, line, format, type); | |
249 | 270 | } |
250 | 271 | |
272 | + // Bottom border | |
273 | + if (mBorder + bHeight < texHeight) { | |
274 | + Bitmap line = getBorderLine(false, config, texWidth); | |
275 | + GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, | |
276 | + 0, mBorder + bHeight, line, format, type); | |
277 | + } | |
251 | 278 | } |
252 | 279 | } finally { |
253 | 280 | freeBitmap(); |