summaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/java/Android.bp1
-rw-r--r--graphics/java/android/framework_graphics.aconfig13
-rw-r--r--graphics/java/android/graphics/BaseCanvas.java5
-rw-r--r--graphics/java/android/graphics/BaseRecordingCanvas.java5
-rw-r--r--graphics/java/android/graphics/Bitmap.java96
-rw-r--r--graphics/java/android/graphics/Canvas.java17
-rw-r--r--graphics/java/android/graphics/FontFamily.java24
-rw-r--r--graphics/java/android/graphics/HardwareRenderer.java14
-rw-r--r--graphics/java/android/graphics/Interpolator.java3
-rw-r--r--graphics/java/android/graphics/Matrix.java58
-rw-r--r--graphics/java/android/graphics/Matrix44.java14
-rw-r--r--graphics/java/android/graphics/Path.java17
-rw-r--r--graphics/java/android/graphics/RecordingCanvas.java4
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java13
-rw-r--r--graphics/java/android/graphics/drawable/Icon.java21
-rw-r--r--graphics/java/android/graphics/fonts/Font.java20
-rw-r--r--graphics/java/android/graphics/fonts/FontFamily.java16
-rw-r--r--graphics/java/android/graphics/pdf/PdfEditor.java32
-rw-r--r--graphics/java/android/graphics/pdf/PdfRenderer.java502
-rw-r--r--graphics/java/android/graphics/text/LineBreaker.java10
-rw-r--r--graphics/java/android/graphics/text/MeasuredText.java50
-rw-r--r--graphics/java/android/graphics/text/PositionedGlyphs.java10
22 files changed, 350 insertions, 595 deletions
diff --git a/graphics/java/Android.bp b/graphics/java/Android.bp
index ece453d1a70e..f4abd0ab582c 100644
--- a/graphics/java/Android.bp
+++ b/graphics/java/Android.bp
@@ -11,6 +11,7 @@ package {
aconfig_declarations {
name: "framework_graphics_flags",
package: "com.android.graphics.flags",
+ container: "system",
srcs: ["android/framework_graphics.aconfig"],
}
diff --git a/graphics/java/android/framework_graphics.aconfig b/graphics/java/android/framework_graphics.aconfig
index 6c81a608241c..0b9e72d6ffdd 100644
--- a/graphics/java/android/framework_graphics.aconfig
+++ b/graphics/java/android/framework_graphics.aconfig
@@ -1,7 +1,9 @@
package: "com.android.graphics.flags"
+container: "system"
flag {
name: "exact_compute_bounds"
+ is_exported: true
namespace: "core_graphics"
description: "Add a function without unused exact param for computeBounds."
bug: "304478551"
@@ -9,7 +11,16 @@ flag {
flag {
name: "yuv_image_compress_to_ultra_hdr"
+ is_exported: true
namespace: "core_graphics"
description: "Feature flag for YUV image compress to Ultra HDR."
bug: "308978825"
-} \ No newline at end of file
+}
+
+flag {
+ name: "icon_load_drawable_return_null_when_uri_decode_fails"
+ is_exported: true
+ namespace: "core_graphics"
+ description: "Return null when decode from URI fails in Icon.loadDrawable()"
+ bug: "335878768"
+}
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index a7acaf924c15..a2a0f4936888 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -333,6 +333,11 @@ public abstract class BaseCanvas {
nDrawPath(mNativeCanvasWrapper, path.readOnlyNI(), paint.getNativeInstance());
}
+ public void drawRegion(@NonNull Region region, @NonNull Paint paint) {
+ throwIfHasHwFeaturesInSwMode(paint);
+ nDrawRegion(mNativeCanvasWrapper, region.mNativeRegion, paint.getNativeInstance());
+ }
+
public void drawPoint(float x, float y, @NonNull Paint paint) {
throwIfHasHwFeaturesInSwMode(paint);
nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance());
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index 4e88b0efd3e5..5b1fa7b15e6d 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -290,6 +290,11 @@ public class BaseRecordingCanvas extends Canvas {
}
@Override
+ public void drawRegion(@NonNull Region region, @NonNull Paint paint) {
+ nDrawRegion(mNativeCanvasWrapper, region.mNativeRegion, paint.getNativeInstance());
+ }
+
+ @Override
public final void drawPicture(@NonNull Picture picture) {
picture.endRecording();
int restoreCount = save();
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 250362b1e1e3..6d31578ac020 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -41,12 +41,15 @@ import dalvik.annotation.optimization.CriticalNative;
import libcore.util.NativeAllocationRegistry;
import java.io.IOException;
+import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
+import java.util.ArrayList;
+import java.util.WeakHashMap;
public final class Bitmap implements Parcelable {
private static final String TAG = "Bitmap";
@@ -120,6 +123,11 @@ public final class Bitmap implements Parcelable {
}
/**
+ * @hide
+ */
+ private static final WeakHashMap<Bitmap, Void> sAllBitmaps = new WeakHashMap<>();
+
+ /**
* Private constructor that must receive an already allocated native bitmap
* int (pointer).
*/
@@ -162,6 +170,9 @@ public final class Bitmap implements Parcelable {
Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
}
registry.registerNativeAllocation(this, nativeBitmap);
+ synchronized (Bitmap.class) {
+ sAllBitmaps.put(this, null);
+ }
}
/**
@@ -454,6 +465,11 @@ public final class Bitmap implements Parcelable {
* how pixels are stored. This affects the quality (color depth) as
* well as the ability to display transparent/translucent colors.
*/
+ // It's touched by Graphics.cpp, so we need to make this enum usable on Ravenwood.
+ // Otherwise, all the ctors would throw, which would make the class unloadable
+ // because the static initializer needs the enum members because of `sConfigs`.
+ // TODO: Remove it once we expose the outer class.
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public enum Config {
// these native values must match up with the enum in SkBitmap.h
@@ -1510,6 +1526,86 @@ public final class Bitmap implements Parcelable {
}
/**
+ * @hide
+ */
+ private static final class DumpData {
+ private int count;
+ private int format;
+ private long[] natives;
+ private byte[][] buffers;
+ private int max;
+
+ public DumpData(@NonNull CompressFormat format, int max) {
+ this.max = max;
+ this.format = format.nativeInt;
+ this.natives = new long[max];
+ this.buffers = new byte[max][];
+ this.count = 0;
+ }
+
+ public void add(long nativePtr, byte[] buffer) {
+ natives[count] = nativePtr;
+ buffers[count] = buffer;
+ count = (count >= max) ? max : count + 1;
+ }
+
+ public int size() {
+ return count;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ private static DumpData dumpData = null;
+
+
+ /**
+ * @hide
+ *
+ * Dump all the bitmaps with their contents compressed into dumpData
+ *
+ * @param format format of the compressed image, null to clear dump data
+ */
+ public static void dumpAll(@Nullable String format) {
+ if (format == null) {
+ /* release the dump data */
+ dumpData = null;
+ return;
+ }
+ final CompressFormat fmt;
+ if (format.equals("jpg") || format.equals("jpeg")) {
+ fmt = CompressFormat.JPEG;
+ } else if (format.equals("png")) {
+ fmt = CompressFormat.PNG;
+ } else if (format.equals("webp")) {
+ fmt = CompressFormat.WEBP_LOSSLESS;
+ } else {
+ Log.w(TAG, "No bitmaps dumped: unrecognized format " + format);
+ return;
+ }
+
+ final ArrayList<Bitmap> allBitmaps;
+ synchronized (Bitmap.class) {
+ allBitmaps = new ArrayList<>(sAllBitmaps.size());
+ for (Bitmap bitmap : sAllBitmaps.keySet()) {
+ if (bitmap != null && !bitmap.isRecycled()) {
+ allBitmaps.add(bitmap);
+ }
+ }
+ }
+
+ dumpData = new DumpData(fmt, allBitmaps.size());
+ for (Bitmap bitmap : allBitmaps) {
+ ByteArrayOutputStream bas = new ByteArrayOutputStream();
+ if (bitmap.compress(fmt, 90, bas)) {
+ dumpData.add(bitmap.getNativeInstance(), bas.toByteArray());
+ }
+ }
+ Log.i(TAG, dumpData.size() + "/" + allBitmaps.size() + " bitmaps dumped");
+ }
+
+ /**
* Number of bytes of temp storage we use for communicating between the
* native compressor and the java OutputStream.
*/
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index b6ce9b64323b..e03a1daf7202 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -789,10 +789,8 @@ public class Canvas extends BaseCanvas {
* @param m The 4x4 matrix to preconcatenate with the current matrix
*/
@FlaggedApi(Flags.FLAG_MATRIX_44)
- public void concat44(@Nullable Matrix44 m) {
- if (m != null) {
- nConcat(mNativeCanvasWrapper, m.mBackingArray);
- }
+ public void concat(@Nullable Matrix44 m) {
+ if (m != null) nConcat(mNativeCanvasWrapper, m.mBackingArray);
}
/**
@@ -1933,6 +1931,17 @@ public class Canvas extends BaseCanvas {
}
/**
+ * Draws the given region using the given paint.
+ *
+ * @param region The region to be drawn
+ * @param paint The paint used to draw the region
+ */
+ @FlaggedApi(Flags.FLAG_DRAW_REGION)
+ public void drawRegion(@NonNull Region region, @NonNull Paint paint) {
+ super.drawRegion(region, paint);
+ }
+
+ /**
* Helper for drawPoints() for drawing a single point.
*/
public void drawPoint(float x, float y, @NonNull Paint paint) {
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index f50de1665453..c86b744dbafa 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -45,15 +45,17 @@ public class FontFamily {
private static String TAG = "FontFamily";
- private static final NativeAllocationRegistry sBuilderRegistry =
- NativeAllocationRegistry.createMalloced(
- FontFamily.class.getClassLoader(), nGetBuilderReleaseFunc());
-
private @Nullable Runnable mNativeBuilderCleaner;
- private static final NativeAllocationRegistry sFamilyRegistry =
- NativeAllocationRegistry.createMalloced(
- FontFamily.class.getClassLoader(), nGetFamilyReleaseFunc());
+ private static class NoImagePreloadHolder {
+ private static final NativeAllocationRegistry sBuilderRegistry =
+ NativeAllocationRegistry.createMalloced(
+ FontFamily.class.getClassLoader(), nGetBuilderReleaseFunc());
+
+ private static final NativeAllocationRegistry sFamilyRegistry =
+ NativeAllocationRegistry.createMalloced(
+ FontFamily.class.getClassLoader(), nGetFamilyReleaseFunc());
+ }
/**
* @hide
@@ -74,7 +76,8 @@ public class FontFamily {
publicAlternatives = "Use {@link android.graphics.fonts.FontFamily} instead.")
public FontFamily() {
mBuilderPtr = nInitBuilder(null, 0);
- mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr);
+ mNativeBuilderCleaner = NoImagePreloadHolder.sBuilderRegistry.registerNativeAllocation(this,
+ mBuilderPtr);
}
/**
@@ -92,7 +95,8 @@ public class FontFamily {
langsString = TextUtils.join(",", langs);
}
mBuilderPtr = nInitBuilder(langsString, variant);
- mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr);
+ mNativeBuilderCleaner = NoImagePreloadHolder.sBuilderRegistry.registerNativeAllocation(this,
+ mBuilderPtr);
}
/**
@@ -113,7 +117,7 @@ public class FontFamily {
mNativeBuilderCleaner.run();
mBuilderPtr = 0;
if (mNativePtr != 0) {
- sFamilyRegistry.registerNativeAllocation(this, mNativePtr);
+ NoImagePreloadHolder.sFamilyRegistry.registerNativeAllocation(this, mNativePtr);
}
return mNativePtr != 0;
}
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 20e393eaee6d..940cd93c53f2 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -25,6 +25,8 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.hardware.DataSpace;
+import android.hardware.HardwareBuffer;
import android.hardware.OverlayProperties;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
@@ -1417,7 +1419,14 @@ public class HardwareRenderer {
nInitDisplayInfo(largestWidth, largestHeight, defaultDisplay.getRefreshRate(),
wideColorDataspace, defaultDisplay.getAppVsyncOffsetNanos(),
defaultDisplay.getPresentationDeadlineNanos(),
- overlayProperties.isFp16SupportedForHdr(),
+ overlayProperties.isCombinationSupported(
+ DataSpace.DATASPACE_SCRGB, HardwareBuffer.RGBA_FP16),
+ overlayProperties.isCombinationSupported(
+ DataSpace.pack(
+ DataSpace.STANDARD_DCI_P3,
+ DataSpace.TRANSFER_SRGB,
+ DataSpace.RANGE_EXTENDED),
+ HardwareBuffer.RGBA_10101010),
overlayProperties.isMixedColorSpacesSupported());
mDisplayInitialized = true;
@@ -1603,7 +1612,8 @@ public class HardwareRenderer {
private static native void nInitDisplayInfo(int width, int height, float refreshRate,
int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos,
- boolean supportsFp16ForHdr, boolean nInitDisplayInfo);
+ boolean supportsFp16ForHdr, boolean isRgba10101010SupportedForHdr,
+ boolean nSupportMixedColorSpaces);
private static native void nSetDrawingEnabled(boolean drawingEnabled);
diff --git a/graphics/java/android/graphics/Interpolator.java b/graphics/java/android/graphics/Interpolator.java
index 104546454fa9..994fb2dc31bc 100644
--- a/graphics/java/android/graphics/Interpolator.java
+++ b/graphics/java/android/graphics/Interpolator.java
@@ -18,6 +18,9 @@ package android.graphics;
import android.os.SystemClock;
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+ android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
public class Interpolator {
public Interpolator(int valueCount) {
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index bc58febc388b..fbb690c0b012 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -28,6 +28,9 @@ import java.io.PrintWriter;
/**
* The Matrix class holds a 3x3 matrix for transforming coordinates.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+ android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
public class Matrix {
public static final int MSCALE_X = 0; //!< use with getValues/setValues
@@ -229,7 +232,7 @@ public class Matrix {
private static class NoImagePreloadHolder {
public static final NativeAllocationRegistry sRegistry =
NativeAllocationRegistry.createMalloced(
- Matrix.class.getClassLoader(), nGetNativeFinalizer());
+ Matrix.class.getClassLoader(), nGetNativeFinalizerWrapper());
}
private final long native_instance;
@@ -238,7 +241,7 @@ public class Matrix {
* Create an identity matrix
*/
public Matrix() {
- native_instance = nCreate(0);
+ native_instance = nCreateWrapper(0);
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
}
@@ -248,7 +251,7 @@ public class Matrix {
* @param src The matrix to copy into this matrix
*/
public Matrix(Matrix src) {
- native_instance = nCreate(src != null ? src.native_instance : 0);
+ native_instance = nCreateWrapper(src != null ? src.native_instance : 0);
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
}
@@ -846,6 +849,34 @@ public class Matrix {
return native_instance;
}
+ /**
+ * Wrapper method we use to switch to ExtraNatives.nCreate(src) only on Ravenwood.
+ *
+ * @see ExtraNatives
+ */
+ @android.ravenwood.annotation.RavenwoodReplace
+ private static long nCreateWrapper(long src) {
+ return nCreate(src);
+ }
+
+ private static long nCreateWrapper$ravenwood(long src) {
+ return ExtraNatives.nCreate(src);
+ }
+
+ /**
+ * Wrapper method we use to switch to ExtraNatives.nGetNativeFinalizer(src) only on Ravenwood.
+ *
+ * @see ExtraNatives
+ */
+ @android.ravenwood.annotation.RavenwoodReplace
+ private static long nGetNativeFinalizerWrapper() {
+ return nGetNativeFinalizer();
+ }
+
+ private static long nGetNativeFinalizerWrapper$ravenwood() {
+ return ExtraNatives.nGetNativeFinalizer();
+ }
+
// ------------------ Regular JNI ------------------------
private static native long nCreate(long nSrc_or_zero);
@@ -943,4 +974,25 @@ public class Matrix {
private static native float nMapRadius(long nObject, float radius);
@CriticalNative
private static native boolean nEquals(long nA, long nB);
+
+ /**
+ * Due to b/337329128, native methods that are called by the static initializers cannot be
+ * in the same class when running on a host side JVM (such as on Ravenwood and Android Studio).
+ *
+ * There are two methods that are called by the static initializers (either directly or
+ * indirectly) in this class, namely nCreate() and nGetNativeFinalizer(). On Ravenwood
+ * these methods can't be on the Matrix class itself, so we use a nested class to host them.
+ *
+ * We still keep the original nCreate() method and call it on non-ravenwood environment,
+ * in order to avoid problems in downstream (such as Android Studio).
+ *
+ * @see #nCreateWrapper(long)
+ * @see #nGetNativeFinalizerWrapper()
+ *
+ * TODO(b/337110712) Clean it up somehow. (remove the original nCreate() and unify the code?)
+ */
+ private static class ExtraNatives {
+ static native long nCreate(long nSrc_or_zero);
+ static native long nGetNativeFinalizer();
+ }
}
diff --git a/graphics/java/android/graphics/Matrix44.java b/graphics/java/android/graphics/Matrix44.java
index 7cc0eb7a6728..a99e20101c3b 100644
--- a/graphics/java/android/graphics/Matrix44.java
+++ b/graphics/java/android/graphics/Matrix44.java
@@ -17,6 +17,7 @@
package android.graphics;
import android.annotation.FlaggedApi;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import com.android.graphics.hwui.flags.Flags;
@@ -98,11 +99,11 @@ public class Matrix44 {
/**
* Gets the value at the matrix's row and column.
*
- * @param row An integer from 0 to 4 indicating the row of the value to get
- * @param col An integer from 0 to 4 indicating the column of the value to get
+ * @param row An integer from 0 to 3 indicating the row of the value to get
+ * @param col An integer from 0 to 3 indicating the column of the value to get
*/
@FlaggedApi(Flags.FLAG_MATRIX_44)
- public float get(int row, int col) {
+ public float get(@IntRange(from = 0, to = 3) int row, @IntRange(from = 0, to = 3) int col) {
if (row >= 0 && row < 4 && col >= 0 && col < 4) {
return mBackingArray[row * 4 + col];
}
@@ -112,12 +113,13 @@ public class Matrix44 {
/**
* Sets the value at the matrix's row and column to the provided value.
*
- * @param row An integer from 0 to 4 indicating the row of the value to change
- * @param col An integer from 0 to 4 indicating the column of the value to change
+ * @param row An integer from 0 to 3 indicating the row of the value to change
+ * @param col An integer from 0 to 3 indicating the column of the value to change
* @param val The value the element at the specified index will be set to
*/
@FlaggedApi(Flags.FLAG_MATRIX_44)
- public void set(int row, int col, float val) {
+ public void set(@IntRange(from = 0, to = 3) int row, @IntRange(from = 0, to = 3) int col,
+ float val) {
if (row >= 0 && row < 4 && col >= 0 && col < 4) {
mBackingArray[row * 4 + col] = val;
} else {
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index deb89faf3419..073307c7a2e8 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -36,11 +36,16 @@ import libcore.util.NativeAllocationRegistry;
* (based on the paint's Style), or it can be used for clipping or to draw
* text on a path.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+ android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
public class Path {
-
- private static final NativeAllocationRegistry sRegistry =
- NativeAllocationRegistry.createMalloced(
- Path.class.getClassLoader(), nGetFinalizer());
+ // See b/337329128 for why we need an inner class here.
+ private static class NoImagePreloadHolder {
+ static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(
+ Path.class.getClassLoader(), nGetFinalizer());
+ }
/**
* @hide
@@ -52,7 +57,7 @@ public class Path {
*/
public Path() {
mNativePath = nInit();
- sRegistry.registerNativeAllocation(this, mNativePath);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePath);
}
/**
@@ -62,7 +67,7 @@ public class Path {
*/
public Path(@Nullable Path src) {
mNativePath = nInit(src != null ? src.mNativePath : 0);
- sRegistry.registerNativeAllocation(this, mNativePath);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePath);
}
/**
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index 635e78e674be..cc5b3b94e0fa 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -40,7 +40,7 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
/** @hide */
private static int getPanelFrameSize() {
- final int DefaultSize = 100 * 1024 * 1024; // 100 MB;
+ final int DefaultSize = 150 * 1024 * 1024; // 150 MB;
return Math.max(SystemProperties.getInt("ro.hwui.max_texture_allocation_size", DefaultSize),
DefaultSize);
}
@@ -262,7 +262,7 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
protected void throwIfCannotDraw(Bitmap bitmap) {
super.throwIfCannotDraw(bitmap);
int bitmapSize = bitmap.getByteCount();
- if (bitmapSize > MAX_BITMAP_SIZE) {
+ if (bitmap.getConfig() != Bitmap.Config.HARDWARE && bitmapSize > MAX_BITMAP_SIZE) {
throw new RuntimeException(
"Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap.");
}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index b291f930da37..579ac60d5a86 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -43,6 +43,7 @@ import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.LayoutDirection;
+import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
@@ -138,6 +139,9 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(Bitmap bitmap) {
+ if (bitmap == null) {
+ Log.w(TAG, "BitmapDrawable created with null Bitmap");
+ }
init(new BitmapState(bitmap), null);
}
@@ -146,6 +150,9 @@ public class BitmapDrawable extends Drawable {
* the display metrics of the resources.
*/
public BitmapDrawable(Resources res, Bitmap bitmap) {
+ if (bitmap == null) {
+ Log.w(TAG, "BitmapDrawable created with null Bitmap");
+ }
init(new BitmapState(bitmap), res);
}
@@ -177,7 +184,7 @@ public class BitmapDrawable extends Drawable {
} finally {
init(new BitmapState(bitmap), res);
if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ Log.w(TAG, "BitmapDrawable cannot decode " + filepath);
}
}
}
@@ -210,7 +217,7 @@ public class BitmapDrawable extends Drawable {
} finally {
init(new BitmapState(bitmap), res);
if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ Log.w(TAG, "BitmapDrawable cannot decode " + is);
}
}
}
@@ -1073,4 +1080,6 @@ public class BitmapDrawable extends Drawable {
mBitmapState.mBlendMode);
computeBitmapSize();
}
+
+ private static final String TAG = "BitmapDrawable";
}
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index f359025f4b46..c3aaf983711d 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -19,6 +19,8 @@ package android.graphics.drawable;
import static android.content.Context.CONTEXT_INCLUDE_CODE;
import static android.content.Context.CONTEXT_RESTRICTED;
+import static com.android.graphics.flags.Flags.iconLoadDrawableReturnNullWhenUriDecodeFails;
+
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
@@ -494,15 +496,28 @@ public final class Icon implements Parcelable {
case TYPE_URI:
InputStream is = getUriInputStream(context);
if (is != null) {
- return new BitmapDrawable(context.getResources(),
- fixMaxBitmapSize(BitmapFactory.decodeStream(is)));
+ final Bitmap bitmap = BitmapFactory.decodeStream(is);
+ if (bitmap == null) {
+ Log.w(TAG, "Unable to decode image from URI: " + getUriString());
+ if (iconLoadDrawableReturnNullWhenUriDecodeFails()) {
+ return null;
+ }
+ }
+ return new BitmapDrawable(context.getResources(), fixMaxBitmapSize(bitmap));
}
break;
case TYPE_URI_ADAPTIVE_BITMAP:
is = getUriInputStream(context);
if (is != null) {
+ final Bitmap bitmap = BitmapFactory.decodeStream(is);
+ if (bitmap == null) {
+ Log.w(TAG, "Unable to decode image from URI: " + getUriString());
+ if (iconLoadDrawableReturnNullWhenUriDecodeFails()) {
+ return null;
+ }
+ }
return new AdaptiveIconDrawable(null, new BitmapDrawable(context.getResources(),
- fixMaxBitmapSize(BitmapFactory.decodeStream(is))));
+ fixMaxBitmapSize(bitmap)));
}
break;
}
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 28cc05162cbb..318aadda63fe 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -61,13 +61,15 @@ public final class Font {
private static final int STYLE_ITALIC = 1;
private static final int STYLE_NORMAL = 0;
- private static final NativeAllocationRegistry BUFFER_REGISTRY =
- NativeAllocationRegistry.createMalloced(
- ByteBuffer.class.getClassLoader(), nGetReleaseNativeFont());
-
- private static final NativeAllocationRegistry FONT_REGISTRY =
- NativeAllocationRegistry.createMalloced(Font.class.getClassLoader(),
- nGetReleaseNativeFont());
+ private static class NoImagePreloadHolder {
+ private static final NativeAllocationRegistry BUFFER_REGISTRY =
+ NativeAllocationRegistry.createMalloced(
+ ByteBuffer.class.getClassLoader(), nGetReleaseNativeFont());
+
+ private static final NativeAllocationRegistry FONT_REGISTRY =
+ NativeAllocationRegistry.createMalloced(Font.class.getClassLoader(),
+ nGetReleaseNativeFont());
+ }
/**
* A builder class for creating new Font.
@@ -530,7 +532,7 @@ public final class Font {
public Font(long nativePtr) {
mNativePtr = nativePtr;
- FONT_REGISTRY.registerNativeAllocation(this, mNativePtr);
+ NoImagePreloadHolder.FONT_REGISTRY.registerNativeAllocation(this, mNativePtr);
}
/**
@@ -551,7 +553,7 @@ public final class Font {
ByteBuffer fromNative = nNewByteBuffer(mNativePtr);
// Bind ByteBuffer's lifecycle with underlying font object.
- BUFFER_REGISTRY.registerNativeAllocation(fromNative, ref);
+ NoImagePreloadHolder.BUFFER_REGISTRY.registerNativeAllocation(fromNative, ref);
// JNI NewDirectBuffer creates writable ByteBuffer even if it is mmaped readonly.
mBuffer = fromNative.asReadOnlyBuffer();
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 685fd825d43e..bd1327657fb0 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -73,9 +73,11 @@ public final class FontFamily {
* A builder class for creating new FontFamily.
*/
public static final class Builder {
- private static final NativeAllocationRegistry sFamilyRegistory =
- NativeAllocationRegistry.createMalloced(FontFamily.class.getClassLoader(),
- nGetReleaseNativeFamily());
+ private static class NoImagePreloadHolder {
+ private static final NativeAllocationRegistry sFamilyRegistry =
+ NativeAllocationRegistry.createMalloced(FontFamily.class.getClassLoader(),
+ nGetReleaseNativeFamily());
+ }
private final ArrayList<Font> mFonts = new ArrayList<>();
// Most FontFamily only has regular, bold, italic, bold-italic. Thus 4 should be good for
@@ -140,7 +142,11 @@ public final class FontFamily {
* value of the supported `wght`axis, the maximum supported `wght` value is used. The weight
* value of the font is ignored.
*
- * If none of the above conditions are met, this function return {@code null}.
+ * If none of the above conditions are met, the provided font files cannot be used for
+ * variable font family and this function returns {@code null}. Even if this function
+ * returns {@code null}, you can still use {@link #build()} method for creating FontFamily
+ * instance with manually specifying variation settings by using
+ * {@link Font.Builder#setFontVariationSettings(String)}.
*
* @return A variable font family. null if a variable font cannot be built from the given
* fonts.
@@ -179,7 +185,7 @@ public final class FontFamily {
final long ptr = nBuild(builderPtr, langTags, variant, isCustomFallback,
isDefaultFallback, variableFamilyType);
final FontFamily family = new FontFamily(ptr);
- sFamilyRegistory.registerNativeAllocation(family, ptr);
+ NoImagePreloadHolder.sFamilyRegistry.registerNativeAllocation(family, ptr);
return family;
}
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 3cd709ea10e5..69e19824da26 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -25,7 +25,9 @@ import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
+
import dalvik.system.CloseGuard;
+
import libcore.io.IoUtils;
import java.io.IOException;
@@ -37,6 +39,12 @@ import java.io.IOException;
*/
public final class PdfEditor {
+ /**
+ * Any call the native pdfium code has to be single threaded as the library does not support
+ * parallel use.
+ */
+ private static final Object sPdfiumLock = new Object();
+
private final CloseGuard mCloseGuard = CloseGuard.get();
private long mNativeDocument;
@@ -79,7 +87,7 @@ public final class PdfEditor {
}
mInput = input;
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
mNativeDocument = nativeOpen(mInput.getFd(), size);
try {
mPageCount = nativeGetPageCount(mNativeDocument);
@@ -112,7 +120,7 @@ public final class PdfEditor {
throwIfClosed();
throwIfPageNotInDocument(pageIndex);
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
}
}
@@ -138,12 +146,12 @@ public final class PdfEditor {
Point size = new Point();
getPageSize(pageIndex, size);
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.ni(),
0, 0, size.x, size.y);
}
} else {
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.ni(),
clip.left, clip.top, clip.right, clip.bottom);
}
@@ -161,7 +169,7 @@ public final class PdfEditor {
throwIfOutSizeNull(outSize);
throwIfPageNotInDocument(pageIndex);
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
nativeGetPageSize(mNativeDocument, pageIndex, outSize);
}
}
@@ -177,7 +185,7 @@ public final class PdfEditor {
throwIfOutMediaBoxNull(outMediaBox);
throwIfPageNotInDocument(pageIndex);
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
}
}
@@ -193,7 +201,7 @@ public final class PdfEditor {
throwIfMediaBoxNull(mediaBox);
throwIfPageNotInDocument(pageIndex);
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
}
}
@@ -209,7 +217,7 @@ public final class PdfEditor {
throwIfOutCropBoxNull(outCropBox);
throwIfPageNotInDocument(pageIndex);
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
}
}
@@ -225,7 +233,7 @@ public final class PdfEditor {
throwIfCropBoxNull(cropBox);
throwIfPageNotInDocument(pageIndex);
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
}
}
@@ -238,7 +246,7 @@ public final class PdfEditor {
public boolean shouldScaleForPrinting() {
throwIfClosed();
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
return nativeScaleForPrinting(mNativeDocument);
}
}
@@ -255,7 +263,7 @@ public final class PdfEditor {
try {
throwIfClosed();
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
nativeWrite(mNativeDocument, output.getFd());
}
} finally {
@@ -287,7 +295,7 @@ public final class PdfEditor {
private void doClose() {
if (mNativeDocument != 0) {
- synchronized (PdfRenderer.sPdfiumLock) {
+ synchronized (sPdfiumLock) {
nativeClose(mNativeDocument);
}
mNativeDocument = 0;
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
deleted file mode 100644
index 4666963b5dd4..000000000000
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * Copyright (C) 2014 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.pdf;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Matrix;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.ParcelFileDescriptor;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-
-import com.android.internal.util.Preconditions;
-
-import dalvik.system.CloseGuard;
-
-import libcore.io.IoUtils;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * <p>
- * This class enables rendering a PDF document. This class is not thread safe.
- * </p>
- * <p>
- * If you want to render a PDF, you create a renderer and for every page you want
- * to render, you open the page, render it, and close the page. After you are done
- * with rendering, you close the renderer. After the renderer is closed it should not
- * be used anymore. Note that the pages are rendered one by one, i.e. you can have
- * only a single page opened at any given time.
- * </p>
- * <p>
- * A typical use of the APIs to render a PDF looks like this:
- * </p>
- * <pre>
- * // create a new renderer
- * PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
- *
- * // let us just render all pages
- * final int pageCount = renderer.getPageCount();
- * for (int i = 0; i < pageCount; i++) {
- * Page page = renderer.openPage(i);
- *
- * // say we render for showing on the screen
- * page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY);
- *
- * // do stuff with the bitmap
- *
- * // close the page
- * page.close();
- * }
- *
- * // close the renderer
- * renderer.close();
- * </pre>
- *
- * <h3>Print preview and print output</h3>
- * <p>
- * If you are using this class to rasterize a PDF for printing or show a print
- * preview, it is recommended that you respect the following contract in order
- * to provide a consistent user experience when seeing a preview and printing,
- * i.e. the user sees a preview that is the same as the printout.
- * </p>
- * <ul>
- * <li>
- * Respect the property whether the document would like to be scaled for printing
- * as per {@link #shouldScaleForPrinting()}.
- * </li>
- * <li>
- * When scaling a document for printing the aspect ratio should be preserved.
- * </li>
- * <li>
- * Do not inset the content with any margins from the {@link android.print.PrintAttributes}
- * as the application is responsible to render it such that the margins are respected.
- * </li>
- * <li>
- * If document page size is greater than the printed media size the content should
- * be anchored to the upper left corner of the page for left-to-right locales and
- * top right corner for right-to-left locales.
- * </li>
- * </ul>
- *
- * @see #close()
- */
-public final class PdfRenderer implements AutoCloseable {
- /**
- * Any call the native pdfium code has to be single threaded as the library does not support
- * parallel use.
- */
- final static Object sPdfiumLock = new Object();
-
- private final CloseGuard mCloseGuard = CloseGuard.get();
-
- private final Point mTempPoint = new Point();
-
- private long mNativeDocument;
-
- private final int mPageCount;
-
- private ParcelFileDescriptor mInput;
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private Page mCurrentPage;
-
- /** @hide */
- @IntDef({
- Page.RENDER_MODE_FOR_DISPLAY,
- Page.RENDER_MODE_FOR_PRINT
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface RenderMode {}
-
- /**
- * Creates a new instance.
- * <p>
- * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
- * i.e. its data being randomly accessed, e.g. pointing to a file.
- * </p>
- * <p>
- * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
- * and is responsible for closing it when the renderer is closed.
- * </p>
- * <p>
- * If the file is from an untrusted source it is recommended to run the renderer in a separate,
- * isolated process with minimal permissions to limit the impact of security exploits.
- * </p>
- *
- * @param input Seekable file descriptor to read from.
- *
- * @throws java.io.IOException If an error occurs while reading the file.
- * @throws java.lang.SecurityException If the file requires a password or
- * the security scheme is not supported.
- */
- public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
- if (input == null) {
- throw new NullPointerException("input cannot be null");
- }
-
- final long size;
- try {
- Os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
- size = Os.fstat(input.getFileDescriptor()).st_size;
- } catch (ErrnoException ee) {
- throw new IllegalArgumentException("file descriptor not seekable");
- }
- mInput = input;
-
- synchronized (sPdfiumLock) {
- mNativeDocument = nativeCreate(mInput.getFd(), size);
- try {
- mPageCount = nativeGetPageCount(mNativeDocument);
- } catch (Throwable t) {
- nativeClose(mNativeDocument);
- mNativeDocument = 0;
- throw t;
- }
- }
-
- mCloseGuard.open("close");
- }
-
- /**
- * Closes this renderer. You should not use this instance
- * after this method is called.
- */
- public void close() {
- throwIfClosed();
- throwIfPageOpened();
- doClose();
- }
-
- /**
- * Gets the number of pages in the document.
- *
- * @return The page count.
- */
- public int getPageCount() {
- throwIfClosed();
- return mPageCount;
- }
-
- /**
- * Gets whether the document prefers to be scaled for printing.
- * You should take this info account if the document is rendered
- * for printing and the target media size differs from the page
- * size.
- *
- * @return If to scale the document.
- */
- public boolean shouldScaleForPrinting() {
- throwIfClosed();
-
- synchronized (sPdfiumLock) {
- return nativeScaleForPrinting(mNativeDocument);
- }
- }
-
- /**
- * Opens a page for rendering.
- *
- * @param index The page index.
- * @return A page that can be rendered.
- *
- * @see android.graphics.pdf.PdfRenderer.Page#close() PdfRenderer.Page.close()
- */
- public Page openPage(int index) {
- throwIfClosed();
- throwIfPageOpened();
- throwIfPageNotInDocument(index);
- mCurrentPage = new Page(index);
- return mCurrentPage;
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
-
- doClose();
- } finally {
- super.finalize();
- }
- }
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private void doClose() {
- if (mCurrentPage != null) {
- mCurrentPage.close();
- mCurrentPage = null;
- }
-
- if (mNativeDocument != 0) {
- synchronized (sPdfiumLock) {
- nativeClose(mNativeDocument);
- }
- mNativeDocument = 0;
- }
-
- if (mInput != null) {
- IoUtils.closeQuietly(mInput);
- mInput = null;
- }
- mCloseGuard.close();
- }
-
- private void throwIfClosed() {
- if (mInput == null) {
- throw new IllegalStateException("Already closed");
- }
- }
-
- private void throwIfPageOpened() {
- if (mCurrentPage != null) {
- throw new IllegalStateException("Current page not closed");
- }
- }
-
- private void throwIfPageNotInDocument(int pageIndex) {
- if (pageIndex < 0 || pageIndex >= mPageCount) {
- throw new IllegalArgumentException("Invalid page index");
- }
- }
-
- /**
- * This class represents a PDF document page for rendering.
- */
- public final class Page implements AutoCloseable {
-
- private final CloseGuard mCloseGuard = CloseGuard.get();
-
- /**
- * Mode to render the content for display on a screen.
- */
- public static final int RENDER_MODE_FOR_DISPLAY = 1;
-
- /**
- * Mode to render the content for printing.
- */
- public static final int RENDER_MODE_FOR_PRINT = 2;
-
- private final int mIndex;
- private final int mWidth;
- private final int mHeight;
-
- private long mNativePage;
-
- private Page(int index) {
- Point size = mTempPoint;
- synchronized (sPdfiumLock) {
- mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
- }
- mIndex = index;
- mWidth = size.x;
- mHeight = size.y;
- mCloseGuard.open("close");
- }
-
- /**
- * Gets the page index.
- *
- * @return The index.
- */
- public int getIndex() {
- return mIndex;
- }
-
- /**
- * Gets the page width in points (1/72").
- *
- * @return The width in points.
- */
- public int getWidth() {
- return mWidth;
- }
-
- /**
- * Gets the page height in points (1/72").
- *
- * @return The height in points.
- */
- public int getHeight() {
- return mHeight;
- }
-
- /**
- * Renders a page to a bitmap.
- * <p>
- * You may optionally specify a rectangular clip in the bitmap bounds. No rendering
- * outside the clip will be performed, hence it is your responsibility to initialize
- * the bitmap outside the clip.
- * </p>
- * <p>
- * You may optionally specify a matrix to transform the content from page coordinates
- * which are in points (1/72") to bitmap coordinates which are in pixels. If this
- * matrix is not provided this method will apply a transformation that will fit the
- * whole page to the destination clip if provided or the destination bitmap if no
- * clip is provided.
- * </p>
- * <p>
- * The clip and transformation are useful for implementing tile rendering where the
- * destination bitmap contains a portion of the image, for example when zooming.
- * Another useful application is for printing where the size of the bitmap holding
- * the page is too large and a client can render the page in stripes.
- * </p>
- * <p>
- * <strong>Note: </strong> The destination bitmap format must be
- * {@link Config#ARGB_8888 ARGB}.
- * </p>
- * <p>
- * <strong>Note: </strong> The optional transformation matrix must be affine as per
- * {@link android.graphics.Matrix#isAffine() Matrix.isAffine()}. Hence, you can specify
- * rotation, scaling, translation but not a perspective transformation.
- * </p>
- *
- * @param destination Destination bitmap to which to render.
- * @param destClip Optional clip in the bitmap bounds.
- * @param transform Optional transformation to apply when rendering.
- * @param renderMode The render mode.
- *
- * @see #RENDER_MODE_FOR_DISPLAY
- * @see #RENDER_MODE_FOR_PRINT
- */
- public void render(@NonNull Bitmap destination, @Nullable Rect destClip,
- @Nullable Matrix transform, @RenderMode int renderMode) {
- if (mNativePage == 0) {
- throw new NullPointerException();
- }
-
- destination = Preconditions.checkNotNull(destination, "bitmap null");
-
- if (destination.getConfig() != Config.ARGB_8888) {
- throw new IllegalArgumentException("Unsupported pixel format");
- }
-
- if (destClip != null) {
- if (destClip.left < 0 || destClip.top < 0
- || destClip.right > destination.getWidth()
- || destClip.bottom > destination.getHeight()) {
- throw new IllegalArgumentException("destBounds not in destination");
- }
- }
-
- if (transform != null && !transform.isAffine()) {
- throw new IllegalArgumentException("transform not affine");
- }
-
- if (renderMode != RENDER_MODE_FOR_PRINT && renderMode != RENDER_MODE_FOR_DISPLAY) {
- throw new IllegalArgumentException("Unsupported render mode");
- }
-
- if (renderMode == RENDER_MODE_FOR_PRINT && renderMode == RENDER_MODE_FOR_DISPLAY) {
- throw new IllegalArgumentException("Only single render mode supported");
- }
-
- final int contentLeft = (destClip != null) ? destClip.left : 0;
- final int contentTop = (destClip != null) ? destClip.top : 0;
- final int contentRight = (destClip != null) ? destClip.right
- : destination.getWidth();
- final int contentBottom = (destClip != null) ? destClip.bottom
- : destination.getHeight();
-
- // If transform is not set, stretch page to whole clipped area
- if (transform == null) {
- int clipWidth = contentRight - contentLeft;
- int clipHeight = contentBottom - contentTop;
-
- transform = new Matrix();
- transform.postScale((float)clipWidth / getWidth(),
- (float)clipHeight / getHeight());
- transform.postTranslate(contentLeft, contentTop);
- }
-
- // FIXME: This code is planned to be outside the UI rendering module, so it should not
- // be able to access native instances from Bitmap, Matrix, etc.
- final long transformPtr = transform.ni();
-
- synchronized (sPdfiumLock) {
- nativeRenderPage(mNativeDocument, mNativePage, destination.getNativeInstance(),
- contentLeft, contentTop, contentRight, contentBottom, transformPtr,
- renderMode);
- }
- }
-
- /**
- * Closes this page.
- *
- * @see android.graphics.pdf.PdfRenderer#openPage(int)
- */
- @Override
- public void close() {
- throwIfClosed();
- doClose();
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
-
- doClose();
- } finally {
- super.finalize();
- }
- }
-
- private void doClose() {
- if (mNativePage != 0) {
- synchronized (sPdfiumLock) {
- nativeClosePage(mNativePage);
- }
- mNativePage = 0;
- }
-
- mCloseGuard.close();
- mCurrentPage = null;
- }
-
- private void throwIfClosed() {
- if (mNativePage == 0) {
- throw new IllegalStateException("Already closed");
- }
- }
- }
-
- private static native long nativeCreate(int fd, long size);
- private static native void nativeClose(long documentPtr);
- private static native int nativeGetPageCount(long documentPtr);
- private static native boolean nativeScaleForPrinting(long documentPtr);
- private static native void nativeRenderPage(long documentPtr, long pagePtr, long bitmapHandle,
- int clipLeft, int clipTop, int clipRight, int clipBottom, long transformPtr,
- int renderMode);
- private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
- Point outSize);
- private static native void nativeClosePage(long pagePtr);
-}
diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java
index 0e9f29db8cb5..0c6d4bd5da48 100644
--- a/graphics/java/android/graphics/text/LineBreaker.java
+++ b/graphics/java/android/graphics/text/LineBreaker.java
@@ -480,9 +480,11 @@ public class LineBreaker {
}
}
- private static final NativeAllocationRegistry sRegistry =
- NativeAllocationRegistry.createMalloced(
- LineBreaker.class.getClassLoader(), nGetReleaseFunc());
+ private static class NoImagePreloadHolder {
+ private static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(
+ LineBreaker.class.getClassLoader(), nGetReleaseFunc());
+ }
private final long mNativePtr;
@@ -494,7 +496,7 @@ public class LineBreaker {
@Nullable int[] indents, boolean useBoundsForWidth) {
mNativePtr = nInit(breakStrategy, hyphenationFrequency,
justify == JUSTIFICATION_MODE_INTER_WORD, indents, useBoundsForWidth);
- sRegistry.registerNativeAllocation(this, mNativePtr);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePtr);
}
/**
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 6da07198c3ad..884268a4b85c 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -29,11 +29,13 @@ import android.util.Log;
import com.android.internal.util.Preconditions;
import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.NeverInline;
import libcore.util.NativeAllocationRegistry;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Locale;
import java.util.Objects;
/**
@@ -85,6 +87,30 @@ public class MeasuredText {
return mChars;
}
+ private void rangeCheck(int start, int end) {
+ if (start < 0 || start > end || end > mChars.length) {
+ throwRangeError(start, end);
+ }
+ }
+
+ @NeverInline
+ private void throwRangeError(int start, int end) {
+ throw new IllegalArgumentException(String.format(Locale.US,
+ "start(%d) end(%d) length(%d) out of bounds", start, end, mChars.length));
+ }
+
+ private void offsetCheck(int offset) {
+ if (offset < 0 || offset >= mChars.length) {
+ throwOffsetError(offset);
+ }
+ }
+
+ @NeverInline
+ private void throwOffsetError(int offset) {
+ throw new IllegalArgumentException(String.format(Locale.US,
+ "offset (%d) length(%d) out of bounds", offset, mChars.length));
+ }
+
/**
* Returns the width of a given range.
*
@@ -93,12 +119,7 @@ public class MeasuredText {
*/
public @FloatRange(from = 0.0) @Px float getWidth(
@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
- Preconditions.checkArgument(0 <= start && start <= mChars.length,
- "start(%d) must be 0 <= start <= %d", start, mChars.length);
- Preconditions.checkArgument(0 <= end && end <= mChars.length,
- "end(%d) must be 0 <= end <= %d", end, mChars.length);
- Preconditions.checkArgument(start <= end,
- "start(%d) is larger than end(%d)", start, end);
+ rangeCheck(start, end);
return nGetWidth(mNativePtr, start, end);
}
@@ -120,12 +141,7 @@ public class MeasuredText {
*/
public void getBounds(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
@NonNull Rect rect) {
- Preconditions.checkArgument(0 <= start && start <= mChars.length,
- "start(%d) must be 0 <= start <= %d", start, mChars.length);
- Preconditions.checkArgument(0 <= end && end <= mChars.length,
- "end(%d) must be 0 <= end <= %d", end, mChars.length);
- Preconditions.checkArgument(start <= end,
- "start(%d) is larger than end(%d)", start, end);
+ rangeCheck(start, end);
Preconditions.checkNotNull(rect);
nGetBounds(mNativePtr, mChars, start, end, rect);
}
@@ -139,12 +155,7 @@ public class MeasuredText {
*/
public void getFontMetricsInt(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
@NonNull Paint.FontMetricsInt outMetrics) {
- Preconditions.checkArgument(0 <= start && start <= mChars.length,
- "start(%d) must be 0 <= start <= %d", start, mChars.length);
- Preconditions.checkArgument(0 <= end && end <= mChars.length,
- "end(%d) must be 0 <= end <= %d", end, mChars.length);
- Preconditions.checkArgument(start <= end,
- "start(%d) is larger than end(%d)", start, end);
+ rangeCheck(start, end);
Objects.requireNonNull(outMetrics);
long packed = nGetExtent(mNativePtr, mChars, start, end);
@@ -160,8 +171,7 @@ public class MeasuredText {
* @param offset an offset of the character.
*/
public @FloatRange(from = 0.0f) @Px float getCharWidthAt(@IntRange(from = 0) int offset) {
- Preconditions.checkArgument(0 <= offset && offset < mChars.length,
- "offset(%d) is larger than text length %d" + offset, mChars.length);
+ offsetCheck(offset);
return nGetCharWidthAt(mNativePtr, offset);
}
diff --git a/graphics/java/android/graphics/text/PositionedGlyphs.java b/graphics/java/android/graphics/text/PositionedGlyphs.java
index 7932e3334063..f8328b13ca1f 100644
--- a/graphics/java/android/graphics/text/PositionedGlyphs.java
+++ b/graphics/java/android/graphics/text/PositionedGlyphs.java
@@ -46,9 +46,11 @@ import java.util.Objects;
* @see TextRunShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
*/
public final class PositionedGlyphs {
- private static final NativeAllocationRegistry REGISTRY =
- NativeAllocationRegistry.createMalloced(
- Typeface.class.getClassLoader(), nReleaseFunc());
+ private static class NoImagePreloadHolder {
+ private static final NativeAllocationRegistry REGISTRY =
+ NativeAllocationRegistry.createMalloced(
+ Typeface.class.getClassLoader(), nReleaseFunc());
+ }
private final long mLayoutPtr;
private final float mXOffset;
@@ -259,7 +261,7 @@ public final class PositionedGlyphs {
mFonts.add(prevFont);
}
- REGISTRY.registerNativeAllocation(this, layoutPtr);
+ NoImagePreloadHolder.REGISTRY.registerNativeAllocation(this, layoutPtr);
}
@CriticalNative