diff options
| author | 2024-05-24 08:27:25 -0700 | |
|---|---|---|
| committer | 2024-05-24 11:35:17 -0700 | |
| commit | fe285426c4f9149537bdd7cb351b02ec102e6082 (patch) | |
| tree | a50559e0969480b7f613fc086e380a290ee3d6b1 /graphics/java/android | |
| parent | e2447a31771717fe6259043760ba02484f09d4da (diff) | |
| parent | ed6f98ac9f4049f370e1db86e1b4e141bb83f5cc (diff) | |
Merge Android 24Q2 Release (ab/11526283) to aosp-main-future
Bug: 337098550
Merged-In: Ie71e752f0224aa239ba1350d50996ce4b510949a
Change-Id: Ib25c1abf055b0114e0494088df5585f65df27595
Diffstat (limited to 'graphics/java/android')
| -rw-r--r-- | graphics/java/android/framework_graphics.aconfig | 2 | ||||
| -rw-r--r-- | graphics/java/android/graphics/BaseRecordingCanvas.java | 3 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Canvas.java | 60 | ||||
| -rw-r--r-- | graphics/java/android/graphics/FontListParser.java | 62 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Matrix44.java | 472 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Paint.java | 214 | ||||
| -rw-r--r-- | graphics/java/android/graphics/SurfaceTexture.java | 2 | ||||
| -rw-r--r-- | graphics/java/android/graphics/drawable/Icon.java | 58 | ||||
| -rw-r--r-- | graphics/java/android/graphics/fonts/SystemFonts.java | 72 | ||||
| -rw-r--r-- | graphics/java/android/graphics/pdf/TEST_MAPPING | 7 | ||||
| -rw-r--r-- | graphics/java/android/graphics/text/LineBreakConfig.java | 57 | ||||
| -rw-r--r-- | graphics/java/android/graphics/text/LineBreaker.java | 10 | ||||
| -rw-r--r-- | graphics/java/android/graphics/text/MeasuredText.java | 4 |
13 files changed, 900 insertions, 123 deletions
diff --git a/graphics/java/android/framework_graphics.aconfig b/graphics/java/android/framework_graphics.aconfig index f13f3698f9f6..251eade5d4a2 100644 --- a/graphics/java/android/framework_graphics.aconfig +++ b/graphics/java/android/framework_graphics.aconfig @@ -13,4 +13,4 @@ flag { namespace: "core_graphics" description: "Feature flag for YUV image compress to Ultra HDR." bug: "308978825" -}
\ No newline at end of file +} diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java index d659ddd75f72..4e88b0efd3e5 100644 --- a/graphics/java/android/graphics/BaseRecordingCanvas.java +++ b/graphics/java/android/graphics/BaseRecordingCanvas.java @@ -607,7 +607,8 @@ public class BaseRecordingCanvas extends Canvas { } @Override - public final void drawMesh(@NonNull Mesh mesh, BlendMode blendMode, @NonNull Paint paint) { + public final void drawMesh(@NonNull Mesh mesh, @Nullable BlendMode blendMode, + @NonNull Paint paint) { if (blendMode == null) { blendMode = BlendMode.MODULATE; } diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 5291f7b4c16c..b60f84d919f7 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -18,6 +18,7 @@ package android.graphics; import android.annotation.ColorInt; import android.annotation.ColorLong; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -30,6 +31,8 @@ import android.graphics.text.TextRunShaper; import android.os.Build; import android.text.TextShaper; +import com.android.graphics.hwui.flags.Flags; + import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; @@ -150,6 +153,18 @@ public class Canvas extends BaseCanvas { } /** + * Indicates whether this Canvas is drawing high contrast text. + * + * @see android.view.accessibility.AccessibilityManager#isHighTextContrastEnabled() + * @return True if high contrast text is enabled, false otherwise. + * + * @hide + */ + public boolean isHighContrastTextEnabled() { + return nIsHighContrastText(mNativeCanvasWrapper); + } + + /** * Specify a bitmap for the canvas to draw into. All canvas state such as * layers, filters, and the save/restore stack are reset. Additionally, * the canvas' target density is updated to match that of the bitmap. @@ -766,6 +781,21 @@ public class Canvas extends BaseCanvas { } /** + * Preconcat the current matrix with the specified matrix. If the specified + * matrix is null, this method does nothing. If the canvas's matrix is changed in the z-axis + * through this function, the deprecated {@link #getMatrix()} method will return a 3x3 with + * z-axis info stripped away. + * + * @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); + } + } + + /** * Completely replace the current matrix with the specified matrix. If the * matrix parameter is null, then the current matrix is reset to identity. * @@ -1110,6 +1140,30 @@ public class Canvas extends BaseCanvas { return false; } + /** + * Intersect the current clip with the specified shader. + * The shader will be treated as an alpha mask, taking the intersection of the two. + * + * @param shader The shader to intersect with the current clip + */ + @FlaggedApi(Flags.FLAG_CLIP_SHADER) + public void clipShader(@NonNull Shader shader) { + nClipShader(mNativeCanvasWrapper, shader.getNativeInstance(), + Region.Op.INTERSECT.nativeInt); + } + + /** + * Set the clip to the difference of the current clip and the shader. + * The shader will be treated as an alpha mask, taking the difference of the two. + * + * @param shader The shader to intersect with the current clip + */ + @FlaggedApi(Flags.FLAG_CLIP_SHADER) + public void clipOutShader(@NonNull Shader shader) { + nClipShader(mNativeCanvasWrapper, shader.getNativeInstance(), + Region.Op.DIFFERENCE.nativeInt); + } + public @Nullable DrawFilter getDrawFilter() { return mDrawFilter; } @@ -1410,6 +1464,8 @@ public class Canvas extends BaseCanvas { @CriticalNative private static native boolean nIsOpaque(long canvasHandle); @CriticalNative + private static native boolean nIsHighContrastText(long canvasHandle); + @CriticalNative private static native int nGetWidth(long canvasHandle); @CriticalNative private static native int nGetHeight(long canvasHandle); @@ -1444,6 +1500,8 @@ public class Canvas extends BaseCanvas { private static native void nSkew(long canvasHandle, float sx, float sy); @CriticalNative private static native void nConcat(long nativeCanvas, long nativeMatrix); + @FastNative + private static native void nConcat(long nativeCanvas, float[] mat); @CriticalNative private static native void nSetMatrix(long nativeCanvas, long nativeMatrix); @CriticalNative @@ -1452,6 +1510,8 @@ public class Canvas extends BaseCanvas { @CriticalNative private static native boolean nClipPath(long nativeCanvas, long nativePath, int regionOp); @CriticalNative + private static native void nClipShader(long nativeCanvas, long nativeShader, int regionOp); + @CriticalNative private static native void nSetDrawFilter(long nativeCanvas, long nativeFilter); @CriticalNative private static native void nGetMatrix(long nativeCanvas, long nativeMatrix); diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 2d3ffb5d31ff..13c4a94cb9b6 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -16,10 +16,6 @@ package android.graphics; -import static android.graphics.fonts.FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE; -import static android.graphics.fonts.FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ITAL; -import static android.graphics.fonts.FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ONLY; -import static android.graphics.fonts.FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_TWO_FONTS_WGHT; import static android.text.FontConfig.NamedFamilyList; import android.annotation.NonNull; @@ -32,7 +28,6 @@ import android.os.Build; import android.os.LocaleList; import android.text.FontConfig; import android.util.ArraySet; -import android.util.Log; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; @@ -65,6 +60,7 @@ public class FontListParser { private static final String VARIANT_ELEGANT = "elegant"; // XML constants for Font. + public static final String ATTR_SUPPORTED_AXES = "supportedAxes"; public static final String ATTR_INDEX = "index"; public static final String ATTR_WEIGHT = "weight"; public static final String ATTR_POSTSCRIPT_NAME = "postScriptName"; @@ -78,6 +74,10 @@ public class FontListParser { public static final String ATTR_TAG = "tag"; public static final String ATTR_STYLEVALUE = "stylevalue"; + // The tag string for variable font type resolution. + private static final String TAG_WGHT = "wght"; + private static final String TAG_ITAL = "ital"; + /* Parse fallback list (no names) */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException { @@ -263,7 +263,6 @@ public class FontListParser { final String lang = parser.getAttributeValue("", "lang"); final String variant = parser.getAttributeValue(null, "variant"); final String ignore = parser.getAttributeValue(null, "ignore"); - final String varFamilyTypeStr = parser.getAttributeValue(null, "varFamilyType"); final List<FontConfig.Font> fonts = new ArrayList<>(); while (keepReading(parser)) { if (parser.getEventType() != XmlPullParser.START_TAG) continue; @@ -286,45 +285,12 @@ public class FontListParser { intVariant = FontConfig.FontFamily.VARIANT_ELEGANT; } } - int varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE; - if (varFamilyTypeStr != null) { - varFamilyType = Integer.parseInt(varFamilyTypeStr); - if (varFamilyType <= -1 || varFamilyType > 3) { - Log.e(TAG, "Error: unexpected varFamilyType value: " + varFamilyTypeStr); - varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE; - } - - // validation but don't read font content for performance reasons. - switch (varFamilyType) { - case VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ONLY: - if (fonts.size() != 1) { - Log.e(TAG, "Error: Single font support wght axis, but two or more fonts are" - + " included in the font family."); - varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE; - } - break; - case VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ITAL: - if (fonts.size() != 1) { - Log.e(TAG, "Error: Single font support both ital and wght axes, but two or" - + " more fonts are included in the font family."); - varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE; - } - break; - case VARIABLE_FONT_FAMILY_TYPE_TWO_FONTS_WGHT: - if (fonts.size() != 2) { - Log.e(TAG, "Error: two fonts that support wght axis, but one or three or" - + " more fonts are included in the font family."); - varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE; - } - } - } boolean skip = (ignore != null && (ignore.equals("true") || ignore.equals("1"))); if (skip || fonts.isEmpty()) { return null; } - return new FontConfig.FontFamily(fonts, LocaleList.forLanguageTags(lang), intVariant, - varFamilyType); + return new FontConfig.FontFamily(fonts, LocaleList.forLanguageTags(lang), intVariant); } private static void throwIfAttributeExists(String attrName, XmlPullParser parser) { @@ -407,6 +373,7 @@ public class FontListParser { boolean isItalic = STYLE_ITALIC.equals(parser.getAttributeValue(null, ATTR_STYLE)); String fallbackFor = parser.getAttributeValue(null, ATTR_FALLBACK_FOR); String postScriptName = parser.getAttributeValue(null, ATTR_POSTSCRIPT_NAME); + final String supportedAxes = parser.getAttributeValue(null, ATTR_SUPPORTED_AXES); StringBuilder filename = new StringBuilder(); while (keepReading(parser)) { if (parser.getEventType() == XmlPullParser.TEXT) { @@ -422,6 +389,18 @@ public class FontListParser { } String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll(""); + int varTypeAxes = 0; + if (supportedAxes != null) { + for (String tag : supportedAxes.split(",")) { + String strippedTag = tag.strip(); + if (strippedTag.equals(TAG_WGHT)) { + varTypeAxes |= FontConfig.Font.VAR_TYPE_AXES_WGHT; + } else if (strippedTag.equals(TAG_ITAL)) { + varTypeAxes |= FontConfig.Font.VAR_TYPE_AXES_ITAL; + } + } + } + if (postScriptName == null) { // If post script name was not provided, assume the file name is same to PostScript // name. @@ -462,7 +441,8 @@ public class FontListParser { ), index, varSettings, - fallbackFor); + fallbackFor, + varTypeAxes); } private static String findUpdatedFontFile(String psName, diff --git a/graphics/java/android/graphics/Matrix44.java b/graphics/java/android/graphics/Matrix44.java new file mode 100644 index 000000000000..7cc0eb7a6728 --- /dev/null +++ b/graphics/java/android/graphics/Matrix44.java @@ -0,0 +1,472 @@ +/* + * Copyright 2023 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.FlaggedApi; +import android.annotation.NonNull; + +import com.android.graphics.hwui.flags.Flags; + +import java.util.Arrays; + +/** + * The Matrix44 class holds a 4x4 matrix for transforming coordinates. It is similar to + * {@link Matrix}, and should be used when you want to manipulate the canvas in 3D. Values are kept + * in row-major order. The values and operations are treated as column vectors. + */ +@FlaggedApi(Flags.FLAG_MATRIX_44) +public class Matrix44 { + final float[] mBackingArray; + /** + * The default Matrix44 constructor will instantiate an identity matrix. + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public Matrix44() { + mBackingArray = new float[]{1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + } + + /** + * Creates and returns a Matrix44 by taking the 3x3 Matrix and placing it on the 0 of the z-axis + * by setting row {@code 2} and column {@code 2} to the identity as seen in the following + * operation: + * <pre class="prettyprint"> + * [ a b c ] [ a b 0 c ] + * [ d e f ] -> [ d e 0 f ] + * [ g h i ] [ 0 0 1 0 ] + * [ g h 0 i ] + * </pre> + * + * @param mat A 3x3 Matrix to be converted (original Matrix will not be changed) + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public Matrix44(@NonNull Matrix mat) { + float[] m = new float[9]; + mat.getValues(m); + mBackingArray = new float[]{m[0], m[1], 0.0f, m[2], + m[3], m[4], 0.0f, m[5], + 0.0f, 0.0f, 1.0f, 0.0f, + m[6], m[7], 0.0f, m[8]}; + } + + /** + * Copies matrix values into the provided array in row-major order. + * + * @param dst The float array where values will be copied, must be of length 16 + * @throws IllegalArgumentException if the destination float array is not of length 16 + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public void getValues(@NonNull float [] dst) { + if (dst.length == 16) { + System.arraycopy(mBackingArray, 0, dst, 0, mBackingArray.length); + } else { + throw new IllegalArgumentException("Dst array must be of length 16"); + } + } + + /** + * Replaces the Matrix's values with the values in the provided array. + * + * @param src A float array of length 16. Floats are treated in row-major order + * @throws IllegalArgumentException if the destination float array is not of length 16 + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public void setValues(@NonNull float[] src) { + if (src.length == 16) { + System.arraycopy(src, 0, mBackingArray, 0, mBackingArray.length); + } else { + throw new IllegalArgumentException("Src array must be of length 16"); + } + } + + /** + * 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 + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public float get(int row, int col) { + if (row >= 0 && row < 4 && col >= 0 && col < 4) { + return mBackingArray[row * 4 + col]; + } + throw new IllegalArgumentException("invalid row and column values"); + } + + /** + * 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 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) { + if (row >= 0 && row < 4 && col >= 0 && col < 4) { + mBackingArray[row * 4 + col] = val; + } else { + throw new IllegalArgumentException("invalid row and column values"); + } + } + + /** + * Sets the Matrix44 to the identity matrix. + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public void reset() { + for (int i = 0; i < mBackingArray.length; i++) { + mBackingArray[i] = (i % 4 == i / 4) ? 1.0f : 0.0f; + } + } + + /** + * Inverts the Matrix44, then return true if successful, false if unable to invert. + * + * @return {@code true} on success, {@code false} otherwise + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public boolean invert() { + float a00 = mBackingArray[0]; + float a01 = mBackingArray[1]; + float a02 = mBackingArray[2]; + float a03 = mBackingArray[3]; + float a10 = mBackingArray[4]; + float a11 = mBackingArray[5]; + float a12 = mBackingArray[6]; + float a13 = mBackingArray[7]; + float a20 = mBackingArray[8]; + float a21 = mBackingArray[9]; + float a22 = mBackingArray[10]; + float a23 = mBackingArray[11]; + float a30 = mBackingArray[12]; + float a31 = mBackingArray[13]; + float a32 = mBackingArray[14]; + float a33 = mBackingArray[15]; + float b00 = a00 * a11 - a01 * a10; + float b01 = a00 * a12 - a02 * a10; + float b02 = a00 * a13 - a03 * a10; + float b03 = a01 * a12 - a02 * a11; + float b04 = a01 * a13 - a03 * a11; + float b05 = a02 * a13 - a03 * a12; + float b06 = a20 * a31 - a21 * a30; + float b07 = a20 * a32 - a22 * a30; + float b08 = a20 * a33 - a23 * a30; + float b09 = a21 * a32 - a22 * a31; + float b10 = a21 * a33 - a23 * a31; + float b11 = a22 * a33 - a23 * a32; + float det = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06); + if (det == 0.0f) { + return false; + } + float invDet = 1.0f / det; + mBackingArray[0] = ((a11 * b11 - a12 * b10 + a13 * b09) * invDet); + mBackingArray[1] = ((-a01 * b11 + a02 * b10 - a03 * b09) * invDet); + mBackingArray[2] = ((a31 * b05 - a32 * b04 + a33 * b03) * invDet); + mBackingArray[3] = ((-a21 * b05 + a22 * b04 - a23 * b03) * invDet); + mBackingArray[4] = ((-a10 * b11 + a12 * b08 - a13 * b07) * invDet); + mBackingArray[5] = ((a00 * b11 - a02 * b08 + a03 * b07) * invDet); + mBackingArray[6] = ((-a30 * b05 + a32 * b02 - a33 * b01) * invDet); + mBackingArray[7] = ((a20 * b05 - a22 * b02 + a23 * b01) * invDet); + mBackingArray[8] = ((a10 * b10 - a11 * b08 + a13 * b06) * invDet); + mBackingArray[9] = ((-a00 * b10 + a01 * b08 - a03 * b06) * invDet); + mBackingArray[10] = ((a30 * b04 - a31 * b02 + a33 * b00) * invDet); + mBackingArray[11] = ((-a20 * b04 + a21 * b02 - a23 * b00) * invDet); + mBackingArray[12] = ((-a10 * b09 + a11 * b07 - a12 * b06) * invDet); + mBackingArray[13] = ((a00 * b09 - a01 * b07 + a02 * b06) * invDet); + mBackingArray[14] = ((-a30 * b03 + a31 * b01 - a32 * b00) * invDet); + mBackingArray[15] = ((a20 * b03 - a21 * b01 + a22 * b00) * invDet); + return true; + } + + /** + * Returns true if Matrix44 is equal to identity matrix. + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public boolean isIdentity() { + for (int i = 0; i < mBackingArray.length; i++) { + float expected = (i % 4 == i / 4) ? 1.0f : 0.0f; + if (expected != mBackingArray[i]) return false; + } + return true; + } + + @FlaggedApi(Flags.FLAG_MATRIX_44) + private static float dot(Matrix44 a, Matrix44 b, int row, int col) { + return (a.get(row, 0) * b.get(0, col)) + + (a.get(row, 1) * b.get(1, col)) + + (a.get(row, 2) * b.get(2, col)) + + (a.get(row, 3) * b.get(3, col)); + } + + @FlaggedApi(Flags.FLAG_MATRIX_44) + private static float dot(float r0, float r1, float r2, float r3, + float c0, float c1, float c2, float c3) { + return (r0 * c0) + (r1 * c1) + (r2 * c2) + (r3 * c3); + } + + /** + * Multiplies (x, y, z, w) vector by the Matrix44, then returns the new (x, y, z, w). Users + * should set {@code w} to 1 to indicate the coordinates are normalized. + * + * @return An array of length 4 that represents the x, y, z, w (where w is perspective) value + * after multiplying x, y, z, 1 by the matrix + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public @NonNull float[] map(float x, float y, float z, float w) { + float[] dst = new float[4]; + this.map(x, y, z, w, dst); + return dst; + } + + /** + * Multiplies (x, y, z, w) vector by the Matrix44, then returns the new (x, y, z, w). Users + * should set {@code w} to 1 to indicate the coordinates are normalized. + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public void map(float x, float y, float z, float w, @NonNull float[] dst) { + if (dst.length != 4) { + throw new IllegalArgumentException("Dst array must be of length 4"); + } + dst[0] = x * mBackingArray[0] + y * mBackingArray[1] + + z * mBackingArray[2] + w * mBackingArray[3]; + dst[1] = x * mBackingArray[4] + y * mBackingArray[5] + + z * mBackingArray[6] + w * mBackingArray[7]; + dst[2] = x * mBackingArray[8] + y * mBackingArray[9] + + z * mBackingArray[10] + w * mBackingArray[11]; + dst[3] = x * mBackingArray[12] + y * mBackingArray[13] + + z * mBackingArray[14] + w * mBackingArray[15]; + } + + /** + * Multiplies `this` matrix (A) and provided Matrix (B) in the order of A * B. + * The result is saved in `this` Matrix. + * + * @param b The second Matrix in the concatenation operation + * @return A reference to this Matrix, which can be used to chain Matrix operations + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public @NonNull Matrix44 concat(@NonNull Matrix44 b) { + float val00 = dot(this, b, 0, 0); + float val01 = dot(this, b, 0, 1); + float val02 = dot(this, b, 0, 2); + float val03 = dot(this, b, 0, 3); + float val10 = dot(this, b, 1, 0); + float val11 = dot(this, b, 1, 1); + float val12 = dot(this, b, 1, 2); + float val13 = dot(this, b, 1, 3); + float val20 = dot(this, b, 2, 0); + float val21 = dot(this, b, 2, 1); + float val22 = dot(this, b, 2, 2); + float val23 = dot(this, b, 2, 3); + float val30 = dot(this, b, 3, 0); + float val31 = dot(this, b, 3, 1); + float val32 = dot(this, b, 3, 2); + float val33 = dot(this, b, 3, 3); + + mBackingArray[0] = val00; + mBackingArray[1] = val01; + mBackingArray[2] = val02; + mBackingArray[3] = val03; + mBackingArray[4] = val10; + mBackingArray[5] = val11; + mBackingArray[6] = val12; + mBackingArray[7] = val13; + mBackingArray[8] = val20; + mBackingArray[9] = val21; + mBackingArray[10] = val22; + mBackingArray[11] = val23; + mBackingArray[12] = val30; + mBackingArray[13] = val31; + mBackingArray[14] = val32; + mBackingArray[15] = val33; + + return this; + } + + /** + * Applies a rotation around a given axis, then returns self. + * {@code x}, {@code y}, {@code z} represent the axis by which to rotate around. + * For example, pass in {@code 1, 0, 0} to rotate around the x-axis. + * The axis provided will be normalized. + * + * @param deg Amount in degrees to rotate the matrix about the x-axis + * @param xComp X component of the rotation axis + * @param yComp Y component of the rotation axis + * @param zComp Z component of the rotation axis + * @return A reference to this Matrix, which can be used to chain Matrix operations + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public @NonNull Matrix44 rotate(float deg, float xComp, float yComp, float zComp) { + float sum = xComp + yComp + zComp; + float x = xComp / sum; + float y = yComp / sum; + float z = zComp / sum; + + float c = (float) Math.cos(deg * Math.PI / 180.0f); + float s = (float) Math.sin(deg * Math.PI / 180.0f); + float t = 1 - c; + + float rotVals00 = t * x * x + c; + float rotVals01 = t * x * y - s * z; + float rotVals02 = t * x * z + s * y; + float rotVals10 = t * x * y + s * z; + float rotVals11 = t * y * y + c; + float rotVals12 = t * y * z - s * x; + float rotVals20 = t * x * z - s * y; + float rotVals21 = t * y * z + s * x; + float rotVals22 = t * z * z + c; + + float v00 = dot(mBackingArray[0], mBackingArray[1], mBackingArray[2], mBackingArray[3], + rotVals00, rotVals10, rotVals20, 0); + float v01 = dot(mBackingArray[0], mBackingArray[1], mBackingArray[2], mBackingArray[3], + rotVals01, rotVals11, rotVals21, 0); + float v02 = dot(mBackingArray[0], mBackingArray[1], mBackingArray[2], mBackingArray[3], + rotVals02, rotVals12, rotVals22, 0); + float v03 = dot(mBackingArray[0], mBackingArray[1], mBackingArray[2], mBackingArray[3], + 0, 0, 0, 1); + float v10 = dot(mBackingArray[4], mBackingArray[5], mBackingArray[6], mBackingArray[7], + rotVals00, rotVals10, rotVals20, 0); + float v11 = dot(mBackingArray[4], mBackingArray[5], mBackingArray[6], mBackingArray[7], + rotVals01, rotVals11, rotVals21, 0); + float v12 = dot(mBackingArray[4], mBackingArray[5], mBackingArray[6], mBackingArray[7], + rotVals02, rotVals12, rotVals22, 0); + float v13 = dot(mBackingArray[4], mBackingArray[5], mBackingArray[6], mBackingArray[7], + 0, 0, 0, 1); + float v20 = dot(mBackingArray[8], mBackingArray[9], mBackingArray[10], mBackingArray[11], + rotVals00, rotVals10, rotVals20, 0); + float v21 = dot(mBackingArray[8], mBackingArray[9], mBackingArray[10], mBackingArray[11], + rotVals01, rotVals11, rotVals21, 0); + float v22 = dot(mBackingArray[8], mBackingArray[9], mBackingArray[10], mBackingArray[11], + rotVals02, rotVals12, rotVals22, 0); + float v23 = dot(mBackingArray[8], mBackingArray[9], mBackingArray[10], mBackingArray[11], + 0, 0, 0, 1); + float v30 = dot(mBackingArray[12], mBackingArray[13], mBackingArray[14], mBackingArray[15], + rotVals00, rotVals10, rotVals20, 0); + float v31 = dot(mBackingArray[12], mBackingArray[13], mBackingArray[14], mBackingArray[15], + rotVals01, rotVals11, rotVals21, 0); + float v32 = dot(mBackingArray[12], mBackingArray[13], mBackingArray[14], mBackingArray[15], + rotVals02, rotVals12, rotVals22, 0); + float v33 = dot(mBackingArray[12], mBackingArray[13], mBackingArray[14], mBackingArray[15], + 0, 0, 0, 1); + + mBackingArray[0] = v00; + mBackingArray[1] = v01; + mBackingArray[2] = v02; + mBackingArray[3] = v03; + mBackingArray[4] = v10; + mBackingArray[5] = v11; + mBackingArray[6] = v12; + mBackingArray[7] = v13; + mBackingArray[8] = v20; + mBackingArray[9] = v21; + mBackingArray[10] = v22; + mBackingArray[11] = v23; + mBackingArray[12] = v30; + mBackingArray[13] = v31; + mBackingArray[14] = v32; + mBackingArray[15] = v33; + + return this; + } + + /** + * Applies scaling factors to `this` Matrix44, then returns self. Pass 1s for no change. + * + * @param x Scaling factor for the x-axis + * @param y Scaling factor for the y-axis + * @param z Scaling factor for the z-axis + * @return A reference to this Matrix, which can be used to chain Matrix operations + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public @NonNull Matrix44 scale(float x, float y, float z) { + mBackingArray[0] *= x; + mBackingArray[4] *= x; + mBackingArray[8] *= x; + mBackingArray[12] *= x; + mBackingArray[1] *= y; + mBackingArray[5] *= y; + mBackingArray[9] *= y; + mBackingArray[13] *= y; + mBackingArray[2] *= z; + mBackingArray[6] *= z; + mBackingArray[10] *= z; + mBackingArray[14] *= z; + + return this; + } + + /** + * Applies a translation to `this` Matrix44, then returns self. + * + * @param x Translation for the x-axis + * @param y Translation for the y-axis + * @param z Translation for the z-axis + * @return A reference to this Matrix, which can be used to chain Matrix operations + */ + @FlaggedApi(Flags.FLAG_MATRIX_44) + public @NonNull Matrix44 translate(float x, float y, float z) { + float newX = x * mBackingArray[0] + y * mBackingArray[1] + + z * mBackingArray[2] + mBackingArray[3]; + float newY = x * mBackingArray[4] + y * mBackingArray[5] + + z * mBackingArray[6] + mBackingArray[7]; + float newZ = x * mBackingArray[8] + y * mBackingArray[9] + + z * mBackingArray[10] + mBackingArray[11]; + float newW = x * mBackingArray[12] + y * mBackingArray[13] + + z * mBackingArray[14] + mBackingArray[15]; + + mBackingArray[3] = newX; + mBackingArray[7] = newY; + mBackingArray[11] = newZ; + mBackingArray[15] = newW; + + return this; + } + + @Override + public String toString() { + return String.format(""" + | %f %f %f %f | + | %f %f %f %f | + | %f %f %f %f | + | %f %f %f %f | + """, mBackingArray[0], mBackingArray[1], mBackingArray[2], mBackingArray[3], + mBackingArray[4], mBackingArray[5], mBackingArray[6], mBackingArray[7], + mBackingArray[8], mBackingArray[9], mBackingArray[10], mBackingArray[11], + mBackingArray[12], mBackingArray[13], mBackingArray[14], mBackingArray[15]); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Matrix44) { + return Arrays.equals(mBackingArray, ((Matrix44) obj).mBackingArray); + } + return false; + } + + @Override + public int hashCode() { + return (int) mBackingArray[0] + (int) mBackingArray[1] + (int) mBackingArray[2] + + (int) mBackingArray[3] + (int) mBackingArray[4] + (int) mBackingArray[5] + + (int) mBackingArray[6] + (int) mBackingArray[7] + (int) mBackingArray[8] + + (int) mBackingArray[9] + (int) mBackingArray[10] + (int) mBackingArray[11] + + (int) mBackingArray[12] + (int) mBackingArray[13] + (int) mBackingArray[14] + + (int) mBackingArray[15]; + } + +} diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index f10cdb82022e..df95a91d72d7 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -17,6 +17,7 @@ package android.graphics; import static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE; +import static com.android.text.flags.Flags.FLAG_LETTER_SPACING_JUSTIFICATION; import android.annotation.ColorInt; import android.annotation.ColorLong; @@ -133,7 +134,9 @@ public class Paint { FAKE_BOLD_TEXT_FLAG, LINEAR_TEXT_FLAG, SUBPIXEL_TEXT_FLAG, - EMBEDDED_BITMAP_TEXT_FLAG + EMBEDDED_BITMAP_TEXT_FLAG, + TEXT_RUN_FLAG_LEFT_EDGE, + TEXT_RUN_FLAG_RIGHT_EDGE }) public @interface PaintFlag{} @@ -264,6 +267,66 @@ public class Paint { /** @hide bit mask for the flag enabling vertical rendering for text */ public static final int VERTICAL_TEXT_FLAG = 0x1000; + /** + * A text run flag that indicates the run is located the visually most left segment of the line. + * <p> + * This flag is used for telling the underlying text layout engine that the text is located at + * the most left of the line. This flag is used for controlling the amount letter spacing + * added. If the text is in the middle of the line, the text layout engine assigns additional + * letter spacing to the both side of each letter. On the other hand, the letter spacing should + * not be added to the visually most left and right of the line. By setting this flag, text + * layout engine calculates the layout as it is located at the most visually left of the line + * and doesn't add letter spacing to the left of this run. + * <p> + * Note that the caller must resolve BiDi runs and reorder them visually and set this flag only + * if the target run is located visually most left position. This left does not always mean the + * beginning of the text. + * <p> + * If the run covers entire line, caller should set {@link #TEXT_RUN_FLAG_RIGHT_EDGE} as well. + * <p> + * Note that this flag is only effective for run based APIs. For example, this flag works for + * {@link Canvas#drawTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)} + * and + * {@link Paint#getRunCharacterAdvance(char[], int, int, int, int, boolean, int, float[], int)}. + * However, this doesn't work for + * {@link Canvas#drawText(CharSequence, int, int, float, float, Paint)} or + * {@link Paint#measureText(CharSequence, int, int)}. The non-run based APIs works as both + * {@link #TEXT_RUN_FLAG_LEFT_EDGE} and {@link #TEXT_RUN_FLAG_RIGHT_EDGE} are specified. + */ + @FlaggedApi(FLAG_LETTER_SPACING_JUSTIFICATION) + public static final int TEXT_RUN_FLAG_LEFT_EDGE = 0x2000; + + + /** + * A text run flag that indicates the run is located the visually most right segment of the + * line. + * <p> + * This flag is used for telling the underlying text layout engine that the text is located at + * the most right of the line. This flag is used for controlling the amount letter spacing + * added. If the text is in the middle of the line, the text layout engine assigns additional + * letter spacing to the both side of each letter. On the other hand, the letter spacing should + * not be added to the visually most left and right of the line. By setting this flag, text + * layout engine calculates the layout as it is located at the most visually left of the line + * and doesn't add letter spacing to the left of this run. + * <p> + * Note that the caller must resolve BiDi runs and reorder them visually and set this flag only + * if the target run is located visually most right position. This right does not always mean + * the end of the text. + * <p> + * If the run covers entire line, caller should set {@link #TEXT_RUN_FLAG_LEFT_EDGE} as well. + * <p> + * Note that this flag is only effective for run based APIs. For example, this flag works for + * {@link Canvas#drawTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)} + * and + * {@link Paint#getRunCharacterAdvance(char[], int, int, int, int, boolean, int, float[], int)}. + * However, this doesn't work for + * {@link Canvas#drawText(CharSequence, int, int, float, float, Paint)} or + * {@link Paint#measureText(CharSequence, int, int)}. The non-run based APIs works as both + * {@link #TEXT_RUN_FLAG_LEFT_EDGE} and {@link #TEXT_RUN_FLAG_RIGHT_EDGE} are specified. + */ + @FlaggedApi(FLAG_LETTER_SPACING_JUSTIFICATION) + public static final int TEXT_RUN_FLAG_RIGHT_EDGE = 0x4000; + // These flags are always set on a new/reset paint, even if flags 0 is passed. static final int HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG | FILTER_BITMAP_FLAG; @@ -2474,6 +2537,19 @@ public class Paint { nGetFontMetricsInt(mNativePaint, metrics, true); } + /** @hide */ + public static final class RunInfo { + private int mClusterCount = 0; + + public int getClusterCount() { + return mClusterCount; + } + + public void setClusterCount(int clusterCount) { + mClusterCount = clusterCount; + } + } + /** * Return the recommend line spacing based on the current typeface and * text size. @@ -2507,17 +2583,24 @@ public class Paint { if (text.length == 0 || count == 0) { return 0f; } - if (!mHasCompatScaling) { - return (float) Math.ceil(nGetTextAdvances(mNativePaint, text, - index, count, index, count, mBidiFlags, null, 0)); - } + int oldFlag = getFlags(); + setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE)); + try { - final float oldSize = getTextSize(); - setTextSize(oldSize * mCompatScaling); - final float w = nGetTextAdvances(mNativePaint, text, index, count, index, count, - mBidiFlags, null, 0); - setTextSize(oldSize); - return (float) Math.ceil(w*mInvCompatScaling); + if (!mHasCompatScaling) { + return (float) Math.ceil(nGetTextAdvances(mNativePaint, text, + index, count, index, count, mBidiFlags, null, 0)); + } + + final float oldSize = getTextSize(); + setTextSize(oldSize * mCompatScaling); + final float w = nGetTextAdvances(mNativePaint, text, index, count, index, count, + mBidiFlags, null, 0); + setTextSize(oldSize); + return (float) Math.ceil(w * mInvCompatScaling); + } finally { + setFlags(oldFlag); + } } /** @@ -2539,16 +2622,22 @@ public class Paint { if (text.length() == 0 || start == end) { return 0f; } - if (!mHasCompatScaling) { - return (float) Math.ceil(nGetTextAdvances(mNativePaint, text, - start, end, start, end, mBidiFlags, null, 0)); + int oldFlag = getFlags(); + setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE)); + try { + if (!mHasCompatScaling) { + return (float) Math.ceil(nGetTextAdvances(mNativePaint, text, + start, end, start, end, mBidiFlags, null, 0)); + } + final float oldSize = getTextSize(); + setTextSize(oldSize * mCompatScaling); + final float w = nGetTextAdvances(mNativePaint, text, start, end, start, end, mBidiFlags, + null, 0); + setTextSize(oldSize); + return (float) Math.ceil(w * mInvCompatScaling); + } finally { + setFlags(oldFlag); } - final float oldSize = getTextSize(); - setTextSize(oldSize * mCompatScaling); - final float w = nGetTextAdvances(mNativePaint, text, start, end, start, end, mBidiFlags, - null, 0); - setTextSize(oldSize); - return (float) Math.ceil(w * mInvCompatScaling); } /** @@ -2753,19 +2842,26 @@ public class Paint { if (text.length == 0 || count == 0) { return 0; } - if (!mHasCompatScaling) { + int oldFlag = getFlags(); + setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE)); + try { + if (!mHasCompatScaling) { + nGetTextAdvances(mNativePaint, text, index, count, index, count, mBidiFlags, widths, + 0); + return count; + } + + final float oldSize = getTextSize(); + setTextSize(oldSize * mCompatScaling); nGetTextAdvances(mNativePaint, text, index, count, index, count, mBidiFlags, widths, 0); + setTextSize(oldSize); + for (int i = 0; i < count; i++) { + widths[i] *= mInvCompatScaling; + } return count; + } finally { + setFlags(oldFlag); } - - final float oldSize = getTextSize(); - setTextSize(oldSize * mCompatScaling); - nGetTextAdvances(mNativePaint, text, index, count, index, count, mBidiFlags, widths, 0); - setTextSize(oldSize); - for (int i = 0; i < count; i++) { - widths[i] *= mInvCompatScaling; - } - return count; } /** @@ -2836,19 +2932,25 @@ public class Paint { if (text.length() == 0 || start == end) { return 0; } - if (!mHasCompatScaling) { + int oldFlag = getFlags(); + setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE)); + try { + if (!mHasCompatScaling) { + nGetTextAdvances(mNativePaint, text, start, end, start, end, mBidiFlags, widths, 0); + return end - start; + } + + final float oldSize = getTextSize(); + setTextSize(oldSize * mCompatScaling); nGetTextAdvances(mNativePaint, text, start, end, start, end, mBidiFlags, widths, 0); + setTextSize(oldSize); + for (int i = 0; i < end - start; i++) { + widths[i] *= mInvCompatScaling; + } return end - start; + } finally { + setFlags(oldFlag); } - - final float oldSize = getTextSize(); - setTextSize(oldSize * mCompatScaling); - nGetTextAdvances(mNativePaint, text, start, end, start, end, mBidiFlags, widths, 0); - setTextSize(oldSize); - for (int i = 0; i < end - start; i++) { - widths[i] *= mInvCompatScaling; - } - return end - start; } /** @@ -3320,7 +3422,7 @@ public class Paint { int contextEnd, boolean isRtl, int offset, @Nullable float[] advances, int advancesIndex) { return getRunCharacterAdvance(text, start, end, contextStart, contextEnd, isRtl, offset, - advances, advancesIndex, null); + advances, advancesIndex, null, null); } /** @@ -3339,12 +3441,14 @@ public class Paint { * @param advances the array that receives the computed character advances * @param advancesIndex the start index from which the advances array is filled * @param drawBounds the output parameter for the bounding box of drawing text, optional + * @param runInfo the output parameter for storing run information. * @return width measurement between start and offset - * @hide + * @hide TODO: Reorganize APIs */ public float getRunCharacterAdvance(@NonNull char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, - @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds) { + @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds, + @Nullable RunInfo runInfo) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -3370,11 +3474,14 @@ public class Paint { } if (end == start) { + if (runInfo != null) { + runInfo.setClusterCount(0); + } return 0.0f; } return nGetRunCharacterAdvance(mNativePaint, text, start, end, contextStart, contextEnd, - isRtl, offset, advances, advancesIndex, drawBounds); + isRtl, offset, advances, advancesIndex, drawBounds, runInfo); } /** @@ -3402,7 +3509,7 @@ public class Paint { int contextStart, int contextEnd, boolean isRtl, int offset, @Nullable float[] advances, int advancesIndex) { return getRunCharacterAdvance(text, start, end, contextStart, contextEnd, isRtl, offset, - advances, advancesIndex, null); + advances, advancesIndex, null, null); } /** @@ -3418,12 +3525,14 @@ public class Paint { * @param advances the array that receives the computed character advances * @param advancesIndex the start index from which the advances array is filled * @param drawBounds the output parameter for the bounding box of drawing text, optional + * @param runInfo an optional output parameter for filling run information. * @return width measurement between start and offset - * @hide + * @hide TODO: Reorganize APIs */ public float getRunCharacterAdvance(@NonNull CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, - @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds) { + @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds, + @Nullable RunInfo runInfo) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -3456,7 +3565,7 @@ public class Paint { TextUtils.getChars(text, contextStart, contextEnd, buf, 0); final float result = getRunCharacterAdvance(buf, start - contextStart, end - contextStart, 0, contextEnd - contextStart, isRtl, offset - contextStart, - advances, advancesIndex, drawBounds); + advances, advancesIndex, drawBounds, runInfo); TemporaryBuffer.recycle(buf); return result; } @@ -3574,7 +3683,7 @@ public class Paint { int contextStart, int contextEnd, boolean isRtl, int offset); private static native float nGetRunCharacterAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, float[] advances, - int advancesIndex, RectF drawingBounds); + int advancesIndex, RectF drawingBounds, RunInfo runInfo); private static native int nGetOffsetForAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance); private static native void nGetFontMetricsIntForText(long paintPtr, char[] text, @@ -3729,4 +3838,11 @@ public class Paint { private static native void nSetTextSize(long paintPtr, float textSize); @CriticalNative private static native boolean nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr); + + + // Following Native methods are kept for old Robolectric JNI signature used by + // SystemUIGoogleRoboRNGTests + private static native float nGetRunCharacterAdvance(long paintPtr, char[] text, + int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, + float[] advances, int advancesIndex, RectF drawingBounds); } diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index c1b531fb2d9c..3256f31bdc93 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -489,7 +489,7 @@ public class SurfaceTexture { @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "postOnSetFrameRateEventFromNative"); try { - if (Flags.toolkitSetFrameRate()) { + if (Flags.toolkitSetFrameRateReadOnly()) { SurfaceTexture st = weakSelf.get(); if (st != null) { Handler handler = st.mOnSetFrameRateHandler; diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index 45e29a88c7db..f359025f4b46 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -154,6 +154,12 @@ public final class Icon implements Parcelable { // TYPE_DATA: data offset private int mInt2; + // TYPE_RESOURCE: use the monochrome drawable from an AdaptiveIconDrawable + private boolean mUseMonochrome = false; + + // TYPE_RESOURCE: wrap the monochrome drawable in an InsetDrawable with the specified inset + private float mInsetScale = 0.0f; + /** * Gets the type of the icon provided. * <p> @@ -368,10 +374,34 @@ public final class Icon implements Parcelable { result.setTintList(mTintList); result.setTintBlendMode(mBlendMode); } + + if (mUseMonochrome) { + return crateMonochromeDrawable(result, mInsetScale); + } + return result; } /** + * Gets the monochrome drawable from an {@link AdaptiveIconDrawable}. + * + * @param drawable An {@link AdaptiveIconDrawable} + * @return Adjusted (wrapped in {@link InsetDrawable}) monochrome drawable + * from an {@link AdaptiveIconDrawable}. + * Or the original drawable if no monochrome layer exists. + */ + private static Drawable crateMonochromeDrawable(Drawable drawable, float inset) { + if (drawable instanceof AdaptiveIconDrawable) { + Drawable monochromeDrawable = ((AdaptiveIconDrawable) drawable).getMonochrome(); + // wrap with negative inset => scale icon (inspired from BaseIconFactory) + if (monochromeDrawable != null) { + return new InsetDrawable(monochromeDrawable, inset); + } + } + return drawable; + } + + /** * Resizes image if size too large for Canvas to draw * @param bitmap Bitmap to be resized if size > {@link RecordingCanvas.MAX_BITMAP_SIZE} * @return resized bitmap @@ -693,7 +723,9 @@ public final class Icon implements Parcelable { && Arrays.equals(getDataBytes(), otherIcon.getDataBytes()); case TYPE_RESOURCE: return getResId() == otherIcon.getResId() - && Objects.equals(getResPackage(), otherIcon.getResPackage()); + && Objects.equals(getResPackage(), otherIcon.getResPackage()) + && mUseMonochrome == otherIcon.mUseMonochrome + && mInsetScale == otherIcon.mInsetScale; case TYPE_URI: case TYPE_URI_ADAPTIVE_BITMAP: return Objects.equals(getUriString(), otherIcon.getUriString()); @@ -748,6 +780,26 @@ public final class Icon implements Parcelable { } /** + * Create an Icon pointing to a drawable resource. + * @param resPackage Name of the package containing the resource in question + * @param resId ID of the drawable resource + * @param useMonochrome if this icon should use the monochrome res from the adaptive drawable + * @hide + */ + public static @NonNull Icon createWithResourceAdaptiveDrawable(@NonNull String resPackage, + @DrawableRes int resId, boolean useMonochrome, float inset) { + if (resPackage == null) { + throw new IllegalArgumentException("Resource package name must not be null."); + } + final Icon rep = new Icon(TYPE_RESOURCE); + rep.mInt1 = resId; + rep.mUseMonochrome = useMonochrome; + rep.mInsetScale = inset; + rep.mString1 = resPackage; + return rep; + } + + /** * Create an Icon pointing to a bitmap in memory. * @param bits A valid {@link android.graphics.Bitmap} object */ @@ -986,6 +1038,8 @@ public final class Icon implements Parcelable { final int resId = in.readInt(); mString1 = pkg; mInt1 = resId; + mUseMonochrome = in.readBoolean(); + mInsetScale = in.readFloat(); break; case TYPE_DATA: final int len = in.readInt(); @@ -1027,6 +1081,8 @@ public final class Icon implements Parcelable { case TYPE_RESOURCE: dest.writeString(getResPackage()); dest.writeInt(getResId()); + dest.writeBoolean(mUseMonochrome); + dest.writeFloat(mInsetScale); break; case TYPE_DATA: dest.writeInt(getDataLength()); diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 6e20034c838a..f727f5b076a1 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -100,6 +100,71 @@ public final class SystemFonts { } } + /** @hide */ + @VisibleForTesting + public static @FontFamily.Builder.VariableFontFamilyType int resolveVarFamilyType( + @NonNull FontConfig.FontFamily xmlFamily, + @Nullable String familyName) { + int wghtCount = 0; + int italCount = 0; + int targetFonts = 0; + boolean hasItalicFont = false; + + List<FontConfig.Font> fonts = xmlFamily.getFontList(); + for (int i = 0; i < fonts.size(); ++i) { + FontConfig.Font font = fonts.get(i); + + if (familyName == null) { // for default family + if (font.getFontFamilyName() != null) { + continue; // this font is not for the default family. + } + } else { // for the specific family + if (!familyName.equals(font.getFontFamilyName())) { + continue; // this font is not for given family. + } + } + + final int varTypeAxes = font.getVarTypeAxes(); + if (varTypeAxes == 0) { + // If we see static font, we can immediately return as VAR_TYPE_NONE. + return FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE; + } + + if ((varTypeAxes & FontConfig.Font.VAR_TYPE_AXES_WGHT) != 0) { + wghtCount++; + } + + if ((varTypeAxes & FontConfig.Font.VAR_TYPE_AXES_ITAL) != 0) { + italCount++; + } + + if (font.getStyle().getSlant() == FontStyle.FONT_SLANT_ITALIC) { + hasItalicFont = true; + } + targetFonts++; + } + + if (italCount == 0) { // No ital font. + if (targetFonts == 1 && wghtCount == 1) { + // If there is only single font that has wght, use it for regular style and + // use synthetic bolding for italic. + return FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ONLY; + } else if (targetFonts == 2 && wghtCount == 2 && hasItalicFont) { + // If there are two fonts and italic font is available, use them for regular and + // italic separately. (It is impossible to have two italic fonts. It will end up + // with Typeface creation failure.) + return FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_TWO_FONTS_WGHT; + } + } else if (italCount == 1) { + // If ital font is included, a single font should support both wght and ital. + if (wghtCount == 1 && targetFonts == 1) { + return FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ITAL; + } + } + // Otherwise, unsupported. + return FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE; + } + private static void pushFamilyToFallback(@NonNull FontConfig.FontFamily xmlFamily, @NonNull ArrayMap<String, NativeFamilyListSet> fallbackMap, @NonNull Map<String, ByteBuffer> cache) { @@ -126,7 +191,7 @@ public final class SystemFonts { } final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily( - defaultFonts, languageTags, variant, xmlFamily.getVariableFontFamilyType(), false, + defaultFonts, languageTags, variant, resolveVarFamilyType(xmlFamily, null), false, cache); // Insert family into fallback map. for (int i = 0; i < fallbackMap.size(); i++) { @@ -145,7 +210,7 @@ public final class SystemFonts { } } else { final FontFamily family = createFontFamily(fallback, languageTags, variant, - xmlFamily.getVariableFontFamilyType(), false, cache); + resolveVarFamilyType(xmlFamily, name), false, cache); if (family != null) { familyListSet.familyList.add(family); } else if (defaultFamily != null) { @@ -217,7 +282,8 @@ public final class SystemFonts { final FontFamily family = createFontFamily( xmlFamily.getFontList(), xmlFamily.getLocaleList().toLanguageTags(), xmlFamily.getVariant(), - xmlFamily.getVariableFontFamilyType(), + resolveVarFamilyType(xmlFamily, + null /* all fonts under named family should be treated as default */), true, // named family is always default bufferCache); if (family == null) { diff --git a/graphics/java/android/graphics/pdf/TEST_MAPPING b/graphics/java/android/graphics/pdf/TEST_MAPPING index d763598f5ba0..afec35c76371 100644 --- a/graphics/java/android/graphics/pdf/TEST_MAPPING +++ b/graphics/java/android/graphics/pdf/TEST_MAPPING @@ -1,7 +1,12 @@ { "presubmit": [ { - "name": "CtsPdfTestCases" + "name": "CtsPdfTestCases", + "options": [ + { + "include-filter": "android.graphics.pdf.cts.PdfDocumentTest" + } + ] } ] } diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java index c5e451a5ec3a..7d55928aa656 100644 --- a/graphics/java/android/graphics/text/LineBreakConfig.java +++ b/graphics/java/android/graphics/text/LineBreakConfig.java @@ -23,9 +23,7 @@ import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; +import android.app.ActivityThread; import android.os.Build; import android.os.LocaleList; import android.os.Parcel; @@ -43,15 +41,6 @@ import java.util.Objects; * line-break property</a> for more information. */ public final class LineBreakConfig implements Parcelable { - - /** - * A feature ID for automatic line break word style. - * @hide - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) - public static final long WORD_STYLE_AUTO = 280005585L; - /** * No hyphenation preference is specified. * @@ -187,6 +176,9 @@ public final class LineBreakConfig implements Parcelable { * - If at least one locale in the locale list contains Japanese script, this option is * equivalent to {@link #LINE_BREAK_STYLE_STRICT}. * - Otherwise, this option is equivalent to {@link #LINE_BREAK_STYLE_NONE}. + * + * <p> + * Note: future versions may have special line breaking style rules for other locales. */ @FlaggedApi(FLAG_WORD_STYLE_AUTO) public static final int LINE_BREAK_STYLE_AUTO = 5; @@ -260,6 +252,9 @@ public final class LineBreakConfig implements Parcelable { * option is equivalent to {@link #LINE_BREAK_WORD_STYLE_PHRASE} if the result of its line * count is less than 5 lines. * - Otherwise, this option is equivalent to {@link #LINE_BREAK_WORD_STYLE_NONE}. + * + * <p> + * Note: future versions may have special line breaking word style rules for other locales. */ @FlaggedApi(FLAG_WORD_STYLE_AUTO) public static final int LINE_BREAK_WORD_STYLE_AUTO = 2; @@ -354,13 +349,13 @@ public final class LineBreakConfig implements Parcelable { return this; } + // TODO(316208691): Revive following removed API docs. + // Note: different from {@link #merge(LineBreakConfig)} if this function is called with + // {@link #LINE_BREAK_STYLE_UNSPECIFIED}, the line break style is reset to + // {@link #LINE_BREAK_STYLE_UNSPECIFIED}. /** * Sets the line-break style. * - * Note: different from {@link #merge(LineBreakConfig)} if this function is called with - * {@link #LINE_BREAK_STYLE_UNSPECIFIED}, the line break style is reset to - * {@link #LINE_BREAK_STYLE_UNSPECIFIED}. - * * @see <a href="https://unicode.org/reports/tr35/#UnicodeLineBreakStyleIdentifier"> * Unicode Line Break Style Identifier</a> * @see <a href="https://drafts.csswg.org/css-text/#line-break-property"> @@ -374,13 +369,13 @@ public final class LineBreakConfig implements Parcelable { return this; } + // TODO(316208691): Revive following removed API docs. + // Note: different from {@link #merge(LineBreakConfig)} method, if this function is called + // with {@link #LINE_BREAK_WORD_STYLE_UNSPECIFIED}, the line break style is reset to + // {@link #LINE_BREAK_WORD_STYLE_UNSPECIFIED}. /** * Sets the line-break word style. * - * Note: different from {@link #merge(LineBreakConfig)} method, if this function is called - * with {@link #LINE_BREAK_WORD_STYLE_UNSPECIFIED}, the line break style is reset to - * {@link #LINE_BREAK_WORD_STYLE_UNSPECIFIED}. - * * @see <a href="https://unicode.org/reports/tr35/#UnicodeLineBreakWordIdentifier"> * Unicode Line Break Word Identifier</a> * @see <a href="https://drafts.csswg.org/css-text/#word-break-property"> @@ -487,8 +482,15 @@ public final class LineBreakConfig implements Parcelable { * @hide */ public static @LineBreakStyle int getResolvedLineBreakStyle(@Nullable LineBreakConfig config) { - final int defaultStyle = CompatChanges.isChangeEnabled(WORD_STYLE_AUTO) - ? LINE_BREAK_STYLE_AUTO : LINE_BREAK_STYLE_NONE; + final int targetSdkVersion = ActivityThread.currentApplication().getApplicationInfo() + .targetSdkVersion; + final int defaultStyle; + final int vicVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM; + if (targetSdkVersion >= vicVersion) { + defaultStyle = LINE_BREAK_STYLE_AUTO; + } else { + defaultStyle = LINE_BREAK_STYLE_NONE; + } if (config == null) { return defaultStyle; } @@ -515,8 +517,15 @@ public final class LineBreakConfig implements Parcelable { */ public static @LineBreakWordStyle int getResolvedLineBreakWordStyle( @Nullable LineBreakConfig config) { - final int defaultWordStyle = CompatChanges.isChangeEnabled(WORD_STYLE_AUTO) - ? LINE_BREAK_WORD_STYLE_AUTO : LINE_BREAK_WORD_STYLE_NONE; + final int targetSdkVersion = ActivityThread.currentApplication().getApplicationInfo() + .targetSdkVersion; + final int defaultWordStyle; + final int vicVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM; + if (targetSdkVersion >= vicVersion) { + defaultWordStyle = LINE_BREAK_WORD_STYLE_AUTO; + } else { + defaultWordStyle = LINE_BREAK_WORD_STYLE_NONE; + } if (config == null) { return defaultWordStyle; } diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java index 06ff4c5c5f36..d471f45e695e 100644 --- a/graphics/java/android/graphics/text/LineBreaker.java +++ b/graphics/java/android/graphics/text/LineBreaker.java @@ -17,6 +17,7 @@ package android.graphics.text; import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH; +import static com.android.text.flags.Flags.FLAG_LETTER_SPACING_JUSTIFICATION; import android.annotation.FlaggedApi; import android.annotation.FloatRange; @@ -163,7 +164,8 @@ public class LineBreaker { /** @hide */ @IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = { JUSTIFICATION_MODE_NONE, - JUSTIFICATION_MODE_INTER_WORD + JUSTIFICATION_MODE_INTER_WORD, + JUSTIFICATION_MODE_INTER_CHARACTER, }) @Retention(RetentionPolicy.SOURCE) public @interface JustificationMode {} @@ -179,6 +181,12 @@ public class LineBreaker { public static final int JUSTIFICATION_MODE_INTER_WORD = 1; /** + * Value for justification mode indicating the text is justified by stretching letter spacing. + */ + @FlaggedApi(FLAG_LETTER_SPACING_JUSTIFICATION) + public static final int JUSTIFICATION_MODE_INTER_CHARACTER = 2; + + /** * Helper class for creating a {@link LineBreaker}. */ public static final class Builder { diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java index 76e1a8beb890..884268a4b85c 100644 --- a/graphics/java/android/graphics/text/MeasuredText.java +++ b/graphics/java/android/graphics/text/MeasuredText.java @@ -279,6 +279,10 @@ public class MeasuredText { * offset is zero. After the style is applied the internal offset is moved to {@code offset * + length}, and next call will start from this new position. * + * <p> + * {@link Paint#TEXT_RUN_FLAG_RIGHT_EDGE} and {@link Paint#TEXT_RUN_FLAG_LEFT_EDGE} are + * ignored and treated as both of them are set. + * * @param paint a paint * @param length a length to be applied with a given paint, can not exceed the length of the * text |