Bug: 121304803 Test: Infeasible Previously, the NativeAllocationRegistry needed to report how much native memory was being held onto by the Java class in order to get a more accurate count of how much memory was in use. But recent changes allow the system to have an even more accurate view of the native memory with mallinfo(). Further, the AOSP change Idccb8b50d26c8c3e93cc34040d784f74dfcdbf51 introduces new APIs that allow distinguishing between large native malloc allocations, which should cause more frequent mallinfo() checks, and whose sizes need be available to ahat etc, and smaller native malloc allocations. Bitmap and AnimatedImageDrawable use the version for large native malloc allocations. The rest pass an implied size of 0. Note that many of the old Registries used somewhat arbitrary sizes, reinforcing the fact that the new way of keeping track of this is better. Add Bitmap::pixelStorageType to differentiate between types of memory that should be accounted for by the Registry. Update Bitmap::getAllocationByteCount to report the actual size of ashmem allocation. Fix a typo in LineBreaker.java, discovered while looking to find existing callers of Bitmap's constructor. Change-Id: I57c407258450aeaf08b47df32432466639d9faed
226 lines
6.7 KiB
Java
226 lines
6.7 KiB
Java
/*
|
|
* Copyright (C) 2006 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 android.graphics;
|
|
|
|
import android.annotation.ColorInt;
|
|
import android.annotation.ColorLong;
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.annotation.UnsupportedAppUsage;
|
|
|
|
import libcore.util.NativeAllocationRegistry;
|
|
|
|
/**
|
|
* Shader is the based class for objects that return horizontal spans of colors
|
|
* during drawing. A subclass of Shader is installed in a Paint calling
|
|
* paint.setShader(shader). After that any object (other than a bitmap) that is
|
|
* drawn with that paint will get its color(s) from the shader.
|
|
*/
|
|
public class Shader {
|
|
|
|
private static class NoImagePreloadHolder {
|
|
public static final NativeAllocationRegistry sRegistry =
|
|
NativeAllocationRegistry.createMalloced(
|
|
Shader.class.getClassLoader(), nativeGetFinalizer());
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use subclass constructors directly instead.
|
|
*/
|
|
@Deprecated
|
|
public Shader() {
|
|
mColorSpace = null;
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public Shader(ColorSpace colorSpace) {
|
|
mColorSpace = colorSpace;
|
|
if (colorSpace == null) {
|
|
throw new IllegalArgumentException(
|
|
"Use Shader() to create a Shader with no ColorSpace");
|
|
}
|
|
|
|
// This just ensures that if the ColorSpace is invalid, the Exception will be thrown now.
|
|
mColorSpace.getNativeInstance();
|
|
}
|
|
|
|
private final ColorSpace mColorSpace;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
protected ColorSpace colorSpace() {
|
|
return mColorSpace;
|
|
}
|
|
|
|
/**
|
|
* Current native shader instance. Created and updated lazily when {@link #getNativeInstance()}
|
|
* is called - otherwise may be out of date with java setters/properties.
|
|
*/
|
|
private long mNativeInstance;
|
|
// Runnable to do immediate destruction
|
|
private Runnable mCleaner;
|
|
|
|
/**
|
|
* Current matrix - always set to null if local matrix is identity.
|
|
*/
|
|
private Matrix mLocalMatrix;
|
|
|
|
public enum TileMode {
|
|
/**
|
|
* replicate the edge color if the shader draws outside of its
|
|
* original bounds
|
|
*/
|
|
CLAMP (0),
|
|
/**
|
|
* repeat the shader's image horizontally and vertically
|
|
*/
|
|
REPEAT (1),
|
|
/**
|
|
* repeat the shader's image horizontally and vertically, alternating
|
|
* mirror images so that adjacent images always seam
|
|
*/
|
|
MIRROR (2);
|
|
|
|
TileMode(int nativeInt) {
|
|
this.nativeInt = nativeInt;
|
|
}
|
|
@UnsupportedAppUsage
|
|
final int nativeInt;
|
|
}
|
|
|
|
/**
|
|
* Return true if the shader has a non-identity local matrix.
|
|
* @param localM Set to the local matrix of the shader, if the shader's matrix is non-null.
|
|
* @return true if the shader has a non-identity local matrix
|
|
*/
|
|
public boolean getLocalMatrix(@NonNull Matrix localM) {
|
|
if (mLocalMatrix != null) {
|
|
localM.set(mLocalMatrix);
|
|
return true; // presence of mLocalMatrix means it's not identity
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Set the shader's local matrix. Passing null will reset the shader's
|
|
* matrix to identity. If the matrix has scale value as 0, the drawing
|
|
* result is undefined.
|
|
*
|
|
* @param localM The shader's new local matrix, or null to specify identity
|
|
*/
|
|
public void setLocalMatrix(@Nullable Matrix localM) {
|
|
if (localM == null || localM.isIdentity()) {
|
|
if (mLocalMatrix != null) {
|
|
mLocalMatrix = null;
|
|
discardNativeInstance();
|
|
}
|
|
} else {
|
|
if (mLocalMatrix == null) {
|
|
mLocalMatrix = new Matrix(localM);
|
|
discardNativeInstance();
|
|
} else if (!mLocalMatrix.equals(localM)) {
|
|
mLocalMatrix.set(localM);
|
|
discardNativeInstance();
|
|
}
|
|
}
|
|
}
|
|
|
|
long createNativeInstance(long nativeMatrix) {
|
|
return 0;
|
|
}
|
|
|
|
/** @hide */
|
|
protected final void discardNativeInstance() {
|
|
if (mNativeInstance != 0) {
|
|
mCleaner.run();
|
|
mCleaner = null;
|
|
mNativeInstance = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Callback for subclasses to call {@link #discardNativeInstance()} if the most recently
|
|
* constructed native instance is no longer valid.
|
|
* @hide
|
|
*/
|
|
protected void verifyNativeInstance() {
|
|
}
|
|
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public final long getNativeInstance() {
|
|
// verify mNativeInstance is valid
|
|
verifyNativeInstance();
|
|
|
|
if (mNativeInstance == 0) {
|
|
mNativeInstance = createNativeInstance(mLocalMatrix == null
|
|
? 0 : mLocalMatrix.native_instance);
|
|
if (mNativeInstance != 0) {
|
|
mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
|
|
this, mNativeInstance);
|
|
}
|
|
}
|
|
return mNativeInstance;
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public static @ColorLong long[] convertColors(@NonNull @ColorInt int[] colors) {
|
|
if (colors.length < 2) {
|
|
throw new IllegalArgumentException("needs >= 2 number of colors");
|
|
}
|
|
|
|
long[] colorLongs = new long[colors.length];
|
|
for (int i = 0; i < colors.length; ++i) {
|
|
colorLongs[i] = Color.pack(colors[i]);
|
|
}
|
|
|
|
return colorLongs;
|
|
}
|
|
|
|
/**
|
|
* Detect the ColorSpace that the {@code colors} share.
|
|
*
|
|
* @throws IllegalArgumentException if the colors do not all share the same,
|
|
* valid ColorSpace, or if there are less than 2 colors.
|
|
*
|
|
* @hide
|
|
*/
|
|
public static ColorSpace detectColorSpace(@NonNull @ColorLong long[] colors) {
|
|
if (colors.length < 2) {
|
|
throw new IllegalArgumentException("needs >= 2 number of colors");
|
|
}
|
|
final ColorSpace colorSpace = Color.colorSpace(colors[0]);
|
|
for (int i = 1; i < colors.length; ++i) {
|
|
if (Color.colorSpace(colors[i]) != colorSpace) {
|
|
throw new IllegalArgumentException("All colors must be in the same ColorSpace!");
|
|
}
|
|
}
|
|
return colorSpace;
|
|
}
|
|
|
|
private static native long nativeGetFinalizer();
|
|
|
|
}
|
|
|