diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java | 190 |
1 files changed, 121 insertions, 69 deletions
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java index 27268fc..5c2c7cd 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java @@ -52,13 +52,17 @@ import java.util.ArrayList; * This allows for drawing through {@link #draw(Drawable, Paint_Delegate)} and * {@link #draw(Drawable, Paint_Delegate)} * + * Handling of layers (created with {@link Canvas#saveLayer(RectF, Paint, int)}) is handled through + * a list of Graphics2D for each layers. The class actually maintains a list of {@link Layer} + * for each layer. Doing a save() will duplicate this list so that each graphics2D object + * ({@link Layer#getGraphics()}) is configured only for the new snapshot. */ public class GcSnapshot { private final GcSnapshot mPrevious; private final int mFlags; - /** list of layers. */ + /** list of layers. The first item in the list is always the */ private final ArrayList<Layer> mLayers = new ArrayList<Layer>(); /** temp transform in case transformation are set before a Graphics2D exists */ @@ -67,25 +71,39 @@ public class GcSnapshot { private Area mClip = null; // local layer data + /** a local layer created with {@link Canvas#saveLayer(RectF, Paint, int)}. + * If this is null, this does not mean there's no layer, just that the snapshot is not the + * one that created the layer. + * @see #getLayerSnapshot() + */ private final Layer mLocalLayer; private final Paint_Delegate mLocalLayerPaint; - private Rect mLocalLayerRegion; + private final Rect mLayerBounds; public interface Drawable { void draw(Graphics2D graphics, Paint_Delegate paint); } /** - * class containing information about a layer. + * Class containing information about a layer. + * + * This contains graphics, bitmap and layer information. */ private static class Layer { private final Graphics2D mGraphics; private final Bitmap_Delegate mBitmap; private final BufferedImage mImage; + /** the flags that were used to configure the layer. This is never changed, and passed + * as is when {@link #makeCopy()} is called */ + private final int mFlags; + /** the original content of the layer when the next object was created. This is not + * passed in {@link #makeCopy()} and instead is recreated when a new layer is added + * (depending on its flags) */ private BufferedImage mOriginalCopy; /** - * Creates a layer with a graphics and a bitmap. + * Creates a layer with a graphics and a bitmap. This is only used to create + * the base layer. * * @param graphics the graphics * @param bitmap the bitmap @@ -94,20 +112,23 @@ public class GcSnapshot { mGraphics = graphics; mBitmap = bitmap; mImage = mBitmap.getImage(); + mFlags = 0; } /** * Creates a layer with a graphics and an image. If the image belongs to a - * {@link Bitmap_Delegate}, then {@link Layer#Layer(Graphics2D, Bitmap_Delegate)} should - * be used. + * {@link Bitmap_Delegate} (case of the base layer), then + * {@link Layer#Layer(Graphics2D, Bitmap_Delegate)} should be used. * - * @param graphics the graphics - * @param image the image + * @param graphics the graphics the new graphics for this layer + * @param image the image the image from which the graphics came + * @param flags the flags that were used to save this layer */ - Layer(Graphics2D graphics, BufferedImage image) { + Layer(Graphics2D graphics, BufferedImage image, int flags) { mGraphics = graphics; mBitmap = null; mImage = image; + mFlags = flags; } /** The Graphics2D, guaranteed to be non null */ @@ -120,12 +141,21 @@ public class GcSnapshot { return mImage; } + /** Returns the layer save flags. This is only valid for additional layers. + * For the base layer this will always return 0; + * For a given layer, all further copies of this {@link Layer} object in new snapshots + * will always return the same value. + */ + int getFlags() { + return mFlags; + } + Layer makeCopy() { if (mBitmap != null) { return new Layer((Graphics2D) mGraphics.create(), mBitmap); } - return new Layer((Graphics2D) mGraphics.create(), mImage); + return new Layer((Graphics2D) mGraphics.create(), mImage, mFlags); } /** sets an optional copy of the original content to be used during restore */ @@ -203,6 +233,7 @@ public class GcSnapshot { mFlags = 0; mLocalLayer = null; mLocalLayerPaint = null; + mLayerBounds = null; } /** @@ -233,11 +264,11 @@ public class GcSnapshot { // get the current transform AffineTransform matrix = mLayers.get(0).getGraphics().getTransform(); - // transform the layerBounds and puts it into a int rect + // transform the layerBounds with the current transform and stores it into a int rect RectF rect2 = new RectF(); mapRect(matrix, rect2, layerBounds); - mLocalLayerRegion = new Rect(); - rect2.round(mLocalLayerRegion); + mLayerBounds = new Rect(); + rect2.round(mLayerBounds); // get the base layer (always at index 0) Layer baseLayer = mLayers.get(0); @@ -246,7 +277,9 @@ public class GcSnapshot { BufferedImage layerImage = new BufferedImage( baseLayer.getImage().getWidth(), baseLayer.getImage().getHeight(), - BufferedImage.TYPE_INT_ARGB); + (mFlags & Canvas.HAS_ALPHA_LAYER_SAVE_FLAG) != 0 ? + BufferedImage.TYPE_INT_ARGB : + BufferedImage.TYPE_INT_RGB); // create a graphics for it so that drawing can be done. Graphics2D layerGraphics = layerImage.createGraphics(); @@ -260,7 +293,7 @@ public class GcSnapshot { layerGraphics.setClip(currentClip); // create a new layer for this new layer and add it to the list at the end. - mLayers.add(mLocalLayer = new Layer(layerGraphics, layerImage)); + mLayers.add(mLocalLayer = new Layer(layerGraphics, layerImage, flags)); // if the drawing is not clipped to the local layer only, we save the current content // of all other layers. We are only interested in the part that will actually @@ -268,16 +301,16 @@ public class GcSnapshot { // This is so that we can erase the drawing that goes in the layers below that will // be coming from the layer itself. if ((mFlags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0) { - int w = mLocalLayerRegion.width(); - int h = mLocalLayerRegion.height(); + int w = mLayerBounds.width(); + int h = mLayerBounds.height(); for (int i = 0 ; i < mLayers.size() - 1 ; i++) { Layer layer = mLayers.get(i); BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = image.createGraphics(); graphics.drawImage(layer.getImage(), 0, 0, w, h, - mLocalLayerRegion.left, mLocalLayerRegion.top, - mLocalLayerRegion.right, mLocalLayerRegion.bottom, + mLayerBounds.left, mLayerBounds.top, + mLayerBounds.right, mLayerBounds.bottom, null); graphics.dispose(); layer.setOriginalCopy(image); @@ -285,6 +318,7 @@ public class GcSnapshot { } } else { mLocalLayer = null; + mLayerBounds = null; } mLocalLayerPaint = paint; @@ -529,14 +563,28 @@ public class GcSnapshot { */ public void draw(Drawable drawable, Paint_Delegate paint, boolean compositeOnly, boolean forceSrcMode) { - // if we clip to the layer, then we only draw in the layer - if (mLocalLayer != null && (mFlags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) != 0) { - drawInLayer(mLocalLayer, drawable, paint, compositeOnly, forceSrcMode); + // the current snapshot may not have a mLocalLayer (ie it was created on save() instead + // of saveLayer(), but that doesn't mean there's no layer. + // mLayers however saves all the information we need (flags). + if (mLayers.size() == 1) { + // no layer, only base layer. easy case. + drawInLayer(mLayers.get(0), drawable, paint, compositeOnly, forceSrcMode); } else { - // draw in all the layers - for (Layer layer : mLayers) { + // draw in all the layers until the layer save flags tells us to stop (ie drawing + // in that layer is limited to the layer itself. + int flags; + int i = mLayers.size() - 1; + + do { + Layer layer = mLayers.get(i); + drawInLayer(layer, drawable, paint, compositeOnly, forceSrcMode); - } + + // then go to previous layer, only if there are any left, and its flags + // doesn't restrict drawing to the layer itself. + i--; + flags = layer.getFlags(); + } while (i >= 0 && (flags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0); } } @@ -560,56 +608,26 @@ public class GcSnapshot { private GcSnapshot doRestore() { if (mPrevious != null) { - boolean forceAllSave = false; if (mLocalLayer != null) { - forceAllSave = true; // layers always save both clip and transform - - // prepare to draw the current layer in the previous layers, ie all layers but - // the last one, since the last one is the local layer - for (int i = 0 ; i < mLayers.size() - 1 ; i++) { - Layer layer = mLayers.get(i); - - Graphics2D baseGfx = layer.getImage().createGraphics(); - - // if the layer contains an original copy this means the flags - // didn't restrict drawing to the local layer and we need to make sure the - // layer bounds in the layer beneath didn't receive any drawing. - // so we use the originalCopy to erase the new drawings in there. - BufferedImage originalCopy = layer.getOriginalCopy(); - if (originalCopy != null) { - Graphics2D g = (Graphics2D) baseGfx.create(); - g.setComposite(AlphaComposite.Src); - - g.drawImage(originalCopy, - mLocalLayerRegion.left, mLocalLayerRegion.top, - mLocalLayerRegion.right, mLocalLayerRegion.bottom, - 0, 0, mLocalLayerRegion.width(), mLocalLayerRegion.height(), - null); - g.dispose(); - } - - // now draw put the content of the local layer onto the layer, using the paint - // information - Graphics2D g = createCustomGraphics(baseGfx, mLocalLayerPaint, - true /*alphaOnly*/, false /*forceSrcMode*/); - - g.drawImage(mLocalLayer.getImage(), - mLocalLayerRegion.left, mLocalLayerRegion.top, - mLocalLayerRegion.right, mLocalLayerRegion.bottom, - mLocalLayerRegion.left, mLocalLayerRegion.top, - mLocalLayerRegion.right, mLocalLayerRegion.bottom, - null); - g.dispose(); - - baseGfx.dispose(); - } + // prepare to blit the layers in which we have draw, in the layer beneath + // them, starting with the top one (which is the current local layer). + int i = mLayers.size() - 1; + int flags; + do { + Layer dstLayer = mLayers.get(i - 1); + + restoreLayer(dstLayer); + + flags = dstLayer.getFlags(); + i--; + } while (i > 0 && (flags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0); } // if this snapshot does not save everything, then set the previous snapshot // to this snapshot content // didn't save the matrix? set the current matrix on the previous snapshot - if (forceAllSave == false && (mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) { + if ((mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) { AffineTransform mtx = getTransform(); for (Layer layer : mPrevious.mLayers) { layer.getGraphics().setTransform(mtx); @@ -617,7 +635,7 @@ public class GcSnapshot { } // didn't save the clip? set the current clip on the previous snapshot - if (forceAllSave == false && (mFlags & Canvas.CLIP_SAVE_FLAG) == 0) { + if ((mFlags & Canvas.CLIP_SAVE_FLAG) == 0) { Shape clip = getClip(); for (Layer layer : mPrevious.mLayers) { layer.getGraphics().setClip(clip); @@ -632,6 +650,40 @@ public class GcSnapshot { return mPrevious; } + private void restoreLayer(Layer dstLayer) { + + Graphics2D baseGfx = dstLayer.getImage().createGraphics(); + + // if the layer contains an original copy this means the flags + // didn't restrict drawing to the local layer and we need to make sure the + // layer bounds in the layer beneath didn't receive any drawing. + // so we use the originalCopy to erase the new drawings in there. + BufferedImage originalCopy = dstLayer.getOriginalCopy(); + if (originalCopy != null) { + Graphics2D g = (Graphics2D) baseGfx.create(); + g.setComposite(AlphaComposite.Src); + + g.drawImage(originalCopy, + mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom, + 0, 0, mLayerBounds.width(), mLayerBounds.height(), + null); + g.dispose(); + } + + // now draw put the content of the local layer onto the layer, + // using the paint information + Graphics2D g = createCustomGraphics(baseGfx, mLocalLayerPaint, + true /*alphaOnly*/, false /*forceSrcMode*/); + + g.drawImage(mLocalLayer.getImage(), + mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom, + mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom, + null); + g.dispose(); + + baseGfx.dispose(); + } + /** * Creates a new {@link Graphics2D} based on the {@link Paint} parameters. * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used. |