HolographicOutlineHelper.java revision 7da1025bd7f15b04cf55c79b73e94e5e1bc959d9
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.launcher2; 18 19import android.graphics.Bitmap; 20import android.graphics.BlurMaskFilter; 21import android.graphics.Canvas; 22import android.graphics.MaskFilter; 23import android.graphics.Paint; 24import android.graphics.PorterDuff; 25import android.graphics.PorterDuffXfermode; 26import android.graphics.TableMaskFilter; 27 28public class HolographicOutlineHelper { 29 private final Paint mHolographicPaint = new Paint(); 30 private final Paint mBlurPaint = new Paint(); 31 private final Paint mErasePaint = new Paint(); 32 33 public static final int OUTER_BLUR_RADIUS; 34 35 private static final BlurMaskFilter sThickOuterBlurMaskFilter; 36 private static final BlurMaskFilter sMediumOuterBlurMaskFilter; 37 private static final BlurMaskFilter sThinOuterBlurMaskFilter; 38 private static final BlurMaskFilter sThickInnerBlurMaskFilter; 39 40 static { 41 final float scale = LauncherApplication.getScreenDensity(); 42 43 OUTER_BLUR_RADIUS = (int) (scale * 6.0f); 44 45 sThickOuterBlurMaskFilter = new BlurMaskFilter(OUTER_BLUR_RADIUS, 46 BlurMaskFilter.Blur.OUTER); 47 sMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER); 48 sThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER); 49 sThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL); 50 } 51 52 private static final MaskFilter sFineClipTable = TableMaskFilter.CreateClipTable(0, 20); 53 private static final MaskFilter sCoarseClipTable = TableMaskFilter.CreateClipTable(0, 200); 54 55 private int[] mTempOffset = new int[2]; 56 57 HolographicOutlineHelper() { 58 mHolographicPaint.setFilterBitmap(true); 59 mHolographicPaint.setAntiAlias(true); 60 mBlurPaint.setFilterBitmap(true); 61 mBlurPaint.setAntiAlias(true); 62 mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 63 mErasePaint.setFilterBitmap(true); 64 mErasePaint.setAntiAlias(true); 65 } 66 67 /** 68 * Returns the interpolated holographic highlight alpha for the effect we want when scrolling 69 * pages. 70 */ 71 public float highlightAlphaInterpolator(float r) { 72 float maxAlpha = 0.8f; 73 return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f); 74 } 75 76 /** 77 * Returns the interpolated view alpha for the effect we want when scrolling pages. 78 */ 79 public float viewAlphaInterpolator(float r) { 80 final float pivot = 0.95f; 81 if (r < pivot) { 82 return (float) Math.pow(r / pivot, 1.5f); 83 } else { 84 return 1.0f; 85 } 86 } 87 88 /** 89 * Apply an outer blur to the given bitmap. 90 * You should use OUTER_BLUR_RADIUS to ensure that the bitmap is big enough to draw 91 * the blur without clipping. 92 */ 93 void applyOuterBlur(Bitmap bitmap, Canvas canvas, int color) { 94 mBlurPaint.setMaskFilter(sThickOuterBlurMaskFilter); 95 Bitmap glow = bitmap.extractAlpha(mBlurPaint, mTempOffset); 96 97 // Use the clip table to make the glow heavier closer to the outline 98 mHolographicPaint.setMaskFilter(sCoarseClipTable); 99 mHolographicPaint.setAlpha(150); 100 mHolographicPaint.setColor(color); 101 canvas.drawBitmap(glow, mTempOffset[0], mTempOffset[1], mHolographicPaint); 102 glow.recycle(); 103 } 104 105 /** 106 * Draws a solid outline around a bitmap, erasing the original pixels. 107 * 108 * @param bitmap The bitmap to modify 109 * @param canvas A canvas on the bitmap 110 * @param color The color to draw the outline and glow in 111 * @param removeOrig If true, punch out the original pixels to just leave the outline 112 */ 113 void applyExpensiveOuterOutline(Bitmap bitmap, Canvas canvas, int color, boolean removeOrig) { 114 Bitmap originalImage = null; 115 if (removeOrig) { 116 originalImage = bitmap.extractAlpha(); 117 } 118 119 // Compute an outer blur on the original bitmap 120 mBlurPaint.setMaskFilter(sMediumOuterBlurMaskFilter); 121 Bitmap outline = bitmap.extractAlpha(mBlurPaint, mTempOffset); 122 123 // Paint the blurred bitmap back into the canvas. Using the clip table causes any alpha 124 // pixels above a certain threshold to be rounded up to be fully opaque. This gives the 125 // effect of a thick outline, with a slight blur on the edge 126 mHolographicPaint.setColor(color); 127 mHolographicPaint.setMaskFilter(sFineClipTable); 128 canvas.drawBitmap(outline, mTempOffset[0], mTempOffset[1], mHolographicPaint); 129 outline.recycle(); 130 131 if (removeOrig) { 132 // Finally, punch out the original pixels, leaving just the outline 133 canvas.drawBitmap(originalImage, 0, 0, mErasePaint); 134 originalImage.recycle(); 135 } 136 } 137 138 /** 139 * Applies a more expensive and accurate outline to whatever is currently drawn in a specified 140 * bitmap. 141 */ 142 void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, 143 int outlineColor) { 144 // calculate the outer blur first 145 mBlurPaint.setMaskFilter(sThickOuterBlurMaskFilter); 146 int[] outerBlurOffset = new int[2]; 147 Bitmap thickOuterBlur = srcDst.extractAlpha(mBlurPaint, outerBlurOffset); 148 mBlurPaint.setMaskFilter(sThinOuterBlurMaskFilter); 149 int[] thinOuterBlurOffset = new int[2]; 150 Bitmap thinOuterBlur = srcDst.extractAlpha(mBlurPaint, thinOuterBlurOffset); 151 152 // calculate the inner blur 153 srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT); 154 mBlurPaint.setMaskFilter(sThickInnerBlurMaskFilter); 155 int[] thickInnerBlurOffset = new int[2]; 156 Bitmap thickInnerBlur = srcDst.extractAlpha(mBlurPaint, thickInnerBlurOffset); 157 158 // mask out the inner blur 159 srcDstCanvas.setBitmap(thickInnerBlur); 160 srcDstCanvas.drawBitmap(srcDst, -thickInnerBlurOffset[0], 161 -thickInnerBlurOffset[1], mErasePaint); 162 srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(), 163 mErasePaint); 164 srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1], 165 mErasePaint); 166 167 // draw the inner and outer blur 168 srcDstCanvas.setBitmap(srcDst); 169 srcDstCanvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); 170 mHolographicPaint.setColor(color); 171 srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1], 172 mHolographicPaint); 173 srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1], 174 mHolographicPaint); 175 176 // draw the bright outline 177 mHolographicPaint.setColor(outlineColor); 178 srcDstCanvas.drawBitmap(thinOuterBlur, thinOuterBlurOffset[0], thinOuterBlurOffset[1], 179 mHolographicPaint); 180 181 // cleanup 182 thinOuterBlur.recycle(); 183 thickOuterBlur.recycle(); 184 thickInnerBlur.recycle(); 185 } 186} 187